Fortinet white logo
Fortinet white logo

SSL commands

SSL commands

SSL:sni()

Returns the SNI or false (if no).

Syntax
SSL:sni()
Arguments

N/A

Events

Applicable in CLIENTSSL_HANDSHAKE, SERVERSSL_HANDSHAKE, HTTP_REQUEST, and HTTP_DATA_REQUEST

Example
when CLIENTSSL_HANDSHAKE {
    local svr_name = SSL:sni()
    if svr_name then
        debug("client handshake sni: %s\n", svr_name)
    end
}

SSL:set_sni(svr_name)

Returns true if the server name indication extension has been set, otherwise false.

Syntax
SSL:set_sni(svr_name)
Arguments

Name

Description

svr_name

String type server name indication extension.

Events

Applicable in event SEVERSSL_CLIENTHELLO_SEND.

Example
when SERVERSSL_CLIENTHELLO_SEND {
    svr_name = "www.visa.com"
    debug("set Server Name Indication(SNI) in ClientHello = %s\n", svr_name)
    SSL:set_sni(svr_name)
}

SSL:cipher()

Returns the cipher in handshake (string type, in OPENSSL form). Please note that the name returned is in standard RFC format.

Syntax
SSL:cipher()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE and SERVERSSL_HANDSHAKE. HTTP_REQUEST and HTTP_DATA_REQUEST

Example
when CLIENTSSL_HANDSHAKE {
    local cipher = SSL:cipher()
    if cipher then
       debug("cipher in client handshake =%s\n", cipher)
    end
}

SSL:version()

Returns the SSL version in handshake (string type).

Syntax
SSL:version()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE and SERVERSSL_HANDSHAKE. HTTP_REQUEST and HTTP_DATA_REQUEST

Example
when CLIENTSSL_HANDSHAKE {
    local ssl_version = SSL:version()
    debug("client ssl version : %s\n", ssl_version)
}

SSL:alpn()

Returns the ALPN protocol selected in handshake (string type). Returns false if not presented or supported.

Syntax
SSL:alpn()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE and SERVERSSL_HANDSHAKE, HTTP_REQUEST and HTTP_DATA_REQUEST

Example

when CLIENTSSL_HANDSHAKE {
    local alpn_protocol = SSL:alpn()
    if alpn_protocol then
        debug("alpn_protocol in client handshake =  %s\n", alpn_protocol)
    end
}

SSL:client_cert_verify()

Returns the status of client-certificate-verify, whether or not it is enabled. True represents enabled, otherwise False.

Syntax
SSL:client_cert_verify()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    debug("status of client-certificate-verify = %s", SSL:client_cert_verify())
}

SSL:cert_count()

Returns the total number of certificates that the peer has offered, including the peer certificate and client certificate chains. (Integer)

Syntax
SSL:cert_count()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    if SSL:client_cert_verify() then
        debug("client cert verify enabled\n")
        local cert_cnt = SSL:cert_count()
        debug("cert_cnt number %d\n", cert_cnt)
    end
}

SSL:get_peer_cert_by_idx(index_value)

Returns the issuer certificate of the index of the X509 SSL certificate in the peer certificate chain, where index is a value greater than or equal to zero.

A value of zero denotes the first certificate in the chain (aka leaf peer certificate);

A value of one denotes the next, and so on. If the input value is out of range, return nil.

Return type: A table including the information of a client certificate.

Syntax
SSL:get_peer_cert_by_idx(index_value)
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    if SSL:client_cert_verify() then
        debug("client cert verify enabled\n")
        local cert_cnt = SSL:cert_count()
        debug("cert_cnt number %d\n", cert_cnt)
        if cert_cnt >= 1 then
            local cert_table = SSL:get_peer_cert_by_idx(0)
            print_table(cert_table, 0)
        end
        debug("verify result: %d\n", SSL:verify_result())
    end
}
-- a function to print a table, i represents the number of \t for formatting purpose.
function print_table(table, indent)
    local space = string.rep('\t',indent)
    for key, value in pairs(table) do
        if(type(value)=='table') then
            debug("%s sub-table[%s]\n", space, key)
            print_table(value, indent+1)
        else
            debug("%s %s: %s\n", space, key, value)
        end
    end
end

SSL:verify_result()

Returns the result code from peer certificate verification. The returned code uses the same values as those of OpenSSL’s X509 verify_result (X509_V_ERR_) definitions.

Returns type: Integer. Returns -1 if the verification code can not be retrieved

Syntax
SSL:verify_result()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    if SSL:client_cert_verify() then
        debug("client cert verify enabled\n")
        debug("verify result: %d\n", SSL:verify_result())
    end
}

SSL:renegotiate()

When the system evaluates the command under a client-side context, the system immediately renegotiates a request for the associated client-side connection.

This function is temporarily ONLY available in HTTP_REQUEST event.

It returns true for success and false for failure.

This function does not support TLS1.3.

Syntax
SSL:renegotiate()
Arguments

N/A

Events

Applicable in event HTTP_REQUEST.

Example

In this sample script, when an HTTPS request with the prefix "autotest" is received, it triggers client certificate verification through SSL renegotiation.

Once the SSL renegotiation is completed, it checks the content-routing policy.

If the client certificate presented by the client meets certain conditions that matches a specific HTTP content routing policy, the traffic will be directed to a designated server pool.

The following is a function to print a table, i representing the number of \t for formatting purposes.

function print_table(table, indent)
    local space = string.rep('\t',indent)
    for key, value in pairs(table) do
        if(type(value)=='table') then
            debug("%s sub-table[%s]\n", space, key)
            print_table(value, indent+1)
        else
            debug("%s %s: %s\n", space, key, value)
        end
    end
end

when HTTP_REQUEST {
    local url = HTTP:url()
    if url:find("^/autotest") and HTTP:is_https() and SSL:client_cert_verify() then
        -- Trigger SSL renegotiate only when it's https request and SSL connection has already been established
        -- Example URL-based certificate verify and then Content-Routing
        debug("url: %s match rule, need client certificate verify\n", url)
        local cert_count = SSL:cert_count()
        debug("cert_count = %s\n", cert_count)
        if cert_count and cert_count == 0 then
            SSL:renegotiate()
            debug("emit SSL renegotiation\n")
        end
    end
}


when CLIENTSSL_RENEGOTIATE {
    local cert_count = SSL:cert_count()
    debug("cert_count = %s\n", cert_count)
    if cert_count and cert_count > 0 then
        local cert_table = SSL:get_peer_cert_by_idx(0)
        print_table(cert_table, 0)
        local subject = cert_table["subject"]
        -- match CN value with regular expression
        local cn_value = subject:match("CN%s-=%s-([^,%s]+)")
        debug("CN value in X509 subject is: %s\n", cn_value)
        if cn_value and cn_value == "test1" then
            LB:routing("ctrt")
        end
    end
}

SSL:close()

Terminates the SSL/TLS connection during the handshake phase, allowing FortiWeb to enforce early-session security decisions based on SSL context. This function is particularly useful in scenarios where you need to prevent connections from proceeding beyond the SSL layer, such as when rejecting traffic based on the Server Name Indication (SNI) value or other handshake metadata before HTTP parsing or WAF processing occurs.

Internally, SSL:close() triggers a connection teardown by sending a TCP FIN or RST (depending on timing and state) without completing the handshake or generating application-level logs. Because the TLS handshake is aborted, this function minimizes resource usage and ensures the transaction is dropped silently from the client’s perspective.

  • Terminates the SSL connection immediately, preventing further processing (including HTTP and WAF modules).

  • Can be combined with functions like SSL:sni() to enforce domain-level access control.

  • The connection is dropped silently without alerting the client (no TLS alerts or HTTP response).

Syntax
SSL:close()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE, SERVERSSL_HANDSHAKE.

Examples

Block clients based on SNI:

when CLIENTSSL_HANDSHAKE {
    local svr_name = SSL:sni()
    if svr_name == "www.blocked-site.com" then
        SSL:close()
        debug("Blocked connection with SNI: %s\n", svr_name)
    end
}

Block server-side handshake for specific domain:

when SERVERSSL_HANDSHAKE {
    local svr_name = SSL:sni()
    if svr_name == "internal-only.example.com" then
        SSL:close()
        debug("Terminating server handshake for internal domain: %s\n", svr_name)
    end
}

SSL commands

SSL commands

SSL:sni()

Returns the SNI or false (if no).

Syntax
SSL:sni()
Arguments

N/A

Events

Applicable in CLIENTSSL_HANDSHAKE, SERVERSSL_HANDSHAKE, HTTP_REQUEST, and HTTP_DATA_REQUEST

Example
when CLIENTSSL_HANDSHAKE {
    local svr_name = SSL:sni()
    if svr_name then
        debug("client handshake sni: %s\n", svr_name)
    end
}

SSL:set_sni(svr_name)

Returns true if the server name indication extension has been set, otherwise false.

Syntax
SSL:set_sni(svr_name)
Arguments

Name

Description

svr_name

String type server name indication extension.

Events

Applicable in event SEVERSSL_CLIENTHELLO_SEND.

Example
when SERVERSSL_CLIENTHELLO_SEND {
    svr_name = "www.visa.com"
    debug("set Server Name Indication(SNI) in ClientHello = %s\n", svr_name)
    SSL:set_sni(svr_name)
}

SSL:cipher()

Returns the cipher in handshake (string type, in OPENSSL form). Please note that the name returned is in standard RFC format.

Syntax
SSL:cipher()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE and SERVERSSL_HANDSHAKE. HTTP_REQUEST and HTTP_DATA_REQUEST

Example
when CLIENTSSL_HANDSHAKE {
    local cipher = SSL:cipher()
    if cipher then
       debug("cipher in client handshake =%s\n", cipher)
    end
}

SSL:version()

Returns the SSL version in handshake (string type).

Syntax
SSL:version()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE and SERVERSSL_HANDSHAKE. HTTP_REQUEST and HTTP_DATA_REQUEST

Example
when CLIENTSSL_HANDSHAKE {
    local ssl_version = SSL:version()
    debug("client ssl version : %s\n", ssl_version)
}

SSL:alpn()

Returns the ALPN protocol selected in handshake (string type). Returns false if not presented or supported.

Syntax
SSL:alpn()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE and SERVERSSL_HANDSHAKE, HTTP_REQUEST and HTTP_DATA_REQUEST

Example

when CLIENTSSL_HANDSHAKE {
    local alpn_protocol = SSL:alpn()
    if alpn_protocol then
        debug("alpn_protocol in client handshake =  %s\n", alpn_protocol)
    end
}

SSL:client_cert_verify()

Returns the status of client-certificate-verify, whether or not it is enabled. True represents enabled, otherwise False.

Syntax
SSL:client_cert_verify()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    debug("status of client-certificate-verify = %s", SSL:client_cert_verify())
}

SSL:cert_count()

Returns the total number of certificates that the peer has offered, including the peer certificate and client certificate chains. (Integer)

Syntax
SSL:cert_count()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    if SSL:client_cert_verify() then
        debug("client cert verify enabled\n")
        local cert_cnt = SSL:cert_count()
        debug("cert_cnt number %d\n", cert_cnt)
    end
}

SSL:get_peer_cert_by_idx(index_value)

Returns the issuer certificate of the index of the X509 SSL certificate in the peer certificate chain, where index is a value greater than or equal to zero.

A value of zero denotes the first certificate in the chain (aka leaf peer certificate);

A value of one denotes the next, and so on. If the input value is out of range, return nil.

Return type: A table including the information of a client certificate.

Syntax
SSL:get_peer_cert_by_idx(index_value)
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    if SSL:client_cert_verify() then
        debug("client cert verify enabled\n")
        local cert_cnt = SSL:cert_count()
        debug("cert_cnt number %d\n", cert_cnt)
        if cert_cnt >= 1 then
            local cert_table = SSL:get_peer_cert_by_idx(0)
            print_table(cert_table, 0)
        end
        debug("verify result: %d\n", SSL:verify_result())
    end
}
-- a function to print a table, i represents the number of \t for formatting purpose.
function print_table(table, indent)
    local space = string.rep('\t',indent)
    for key, value in pairs(table) do
        if(type(value)=='table') then
            debug("%s sub-table[%s]\n", space, key)
            print_table(value, indent+1)
        else
            debug("%s %s: %s\n", space, key, value)
        end
    end
end

SSL:verify_result()

Returns the result code from peer certificate verification. The returned code uses the same values as those of OpenSSL’s X509 verify_result (X509_V_ERR_) definitions.

Returns type: Integer. Returns -1 if the verification code can not be retrieved

Syntax
SSL:verify_result()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE.

Example
when CLIENTSSL_HANDSHAKE {
    if SSL:client_cert_verify() then
        debug("client cert verify enabled\n")
        debug("verify result: %d\n", SSL:verify_result())
    end
}

SSL:renegotiate()

When the system evaluates the command under a client-side context, the system immediately renegotiates a request for the associated client-side connection.

This function is temporarily ONLY available in HTTP_REQUEST event.

It returns true for success and false for failure.

This function does not support TLS1.3.

Syntax
SSL:renegotiate()
Arguments

N/A

Events

Applicable in event HTTP_REQUEST.

Example

In this sample script, when an HTTPS request with the prefix "autotest" is received, it triggers client certificate verification through SSL renegotiation.

Once the SSL renegotiation is completed, it checks the content-routing policy.

If the client certificate presented by the client meets certain conditions that matches a specific HTTP content routing policy, the traffic will be directed to a designated server pool.

The following is a function to print a table, i representing the number of \t for formatting purposes.

function print_table(table, indent)
    local space = string.rep('\t',indent)
    for key, value in pairs(table) do
        if(type(value)=='table') then
            debug("%s sub-table[%s]\n", space, key)
            print_table(value, indent+1)
        else
            debug("%s %s: %s\n", space, key, value)
        end
    end
end

when HTTP_REQUEST {
    local url = HTTP:url()
    if url:find("^/autotest") and HTTP:is_https() and SSL:client_cert_verify() then
        -- Trigger SSL renegotiate only when it's https request and SSL connection has already been established
        -- Example URL-based certificate verify and then Content-Routing
        debug("url: %s match rule, need client certificate verify\n", url)
        local cert_count = SSL:cert_count()
        debug("cert_count = %s\n", cert_count)
        if cert_count and cert_count == 0 then
            SSL:renegotiate()
            debug("emit SSL renegotiation\n")
        end
    end
}


when CLIENTSSL_RENEGOTIATE {
    local cert_count = SSL:cert_count()
    debug("cert_count = %s\n", cert_count)
    if cert_count and cert_count > 0 then
        local cert_table = SSL:get_peer_cert_by_idx(0)
        print_table(cert_table, 0)
        local subject = cert_table["subject"]
        -- match CN value with regular expression
        local cn_value = subject:match("CN%s-=%s-([^,%s]+)")
        debug("CN value in X509 subject is: %s\n", cn_value)
        if cn_value and cn_value == "test1" then
            LB:routing("ctrt")
        end
    end
}

SSL:close()

Terminates the SSL/TLS connection during the handshake phase, allowing FortiWeb to enforce early-session security decisions based on SSL context. This function is particularly useful in scenarios where you need to prevent connections from proceeding beyond the SSL layer, such as when rejecting traffic based on the Server Name Indication (SNI) value or other handshake metadata before HTTP parsing or WAF processing occurs.

Internally, SSL:close() triggers a connection teardown by sending a TCP FIN or RST (depending on timing and state) without completing the handshake or generating application-level logs. Because the TLS handshake is aborted, this function minimizes resource usage and ensures the transaction is dropped silently from the client’s perspective.

  • Terminates the SSL connection immediately, preventing further processing (including HTTP and WAF modules).

  • Can be combined with functions like SSL:sni() to enforce domain-level access control.

  • The connection is dropped silently without alerting the client (no TLS alerts or HTTP response).

Syntax
SSL:close()
Arguments

N/A

Events

Applicable in event CLIENTSSL_HANDSHAKE, SERVERSSL_HANDSHAKE.

Examples

Block clients based on SNI:

when CLIENTSSL_HANDSHAKE {
    local svr_name = SSL:sni()
    if svr_name == "www.blocked-site.com" then
        SSL:close()
        debug("Blocked connection with SNI: %s\n", svr_name)
    end
}

Block server-side handshake for specific domain:

when SERVERSSL_HANDSHAKE {
    local svr_name = SSL:sni()
    if svr_name == "internal-only.example.com" then
        SSL:close()
        debug("Terminating server handshake for internal domain: %s\n", svr_name)
    end
}