Skip to content

LuaSec 1.0.x

Bruno Silvestre edited this page Aug 14, 2021 · 6 revisions

LuaSec depends on OpenSSL, and integrates with LuaSocket to make it easy to add secure connections to any Lua applications or scripts.

This version is compatible with Lua 5.1, 5.2, 5.3, 5.4, and LuaJIT.

Version 1.0.2:

  • Fix handle SSL_send SYSCALL error without errno
  • Fix off by one in cert:validat(notafter)
  • Fix meth_get_sinagure => meth_get_signature_name function name
  • Fix update the Lua state reference on the selected SSL context after SNI
  • Fix ignore SSL_OP_BIT(n) macro and update option.c

Version 1.0.1:

  • Fix: luaL_Buffer can use the stack and break buffer_meth_receive()

Version 1.0:

  • Add cert:getsignaturename()

Notice:

  • LuaSec 0.8 and later require at least OpenSSL 1.0.2.
  • For old versions of OpenSSL, use LuaSec 0.7.

Index


ssl.config

Is a table with another tables that export information about OpenSSL's options, algorithms, curves, protocols, and capabilities.


ssl.loadcertificate(str)

Loads a X509 certificate from a string representation. See cert:pem()


ssl.newcontext(params)

Creates a context that is used to wrap a TCP connection. In case of errors, the function returns nil, followed by an error message.

params is a table that contains parameters to create the context. These parameters can be:

Key Value Type Value Mandatory
mode String
  • "client"
  • "server"
Yes
protocol String
  • "any": the SSL library selects the protocol (use `options` to disable the protocols you do not want to use)
  • "tlsv1": for TLS version 1
  • "tlsv1_1": for TLS version 1.1
  • "tlsv1_2": for TLS version 1.2
  • "tlsv1_3": for TLS version 1.3 (if available)
Yes
key String Path to the file that contains the key (in PEM format). No
password String / Function Password of the encrypted key, or a callback function that returns it. If the callback does not return a string, a null password is used. No
certificate String Path to the file that contains the chain certificates. These must be in PEM format and must be sorted starting from the subject's certificate (client or server), followed by intermediate CA certificates if applicable, and ending at the highest level CA. No
certificates Array It allows to inform more than one certificate. Each element of array is a table with fields certificate (path to the certificate file), key (path to the key file), and password (string or function). If you set certificates field, LuaSec will ignore the fields certificate, key, and password from "main" configuration table. No
cafile String Path to the file that contains a set of trusting certificates (in PEM format). No
capath String Path to the directory that constains a set of files with trusting certificates. No
verify String / Table Options used to verify the certificates. Use an array of strings for multiple options.
  • "none"
  • "peer"
  • "client_once"
  • "fail_if_no_peer_cert"
No
options String / Table Options to change the behaviour of the OpenSSL library. Use an array of strings for multiple options. See ssl.config.options for available options. No
ciphers String The ciphersuites to be used in TLS 1.3 the connection (if available). No
ciphersuites String The list of ciphers to be used in the connection. No
depth Number Maximum depth in the certificate chain verification. No
dhparam Function This callback function must return the DH parameters, used in the handshake. No
curve String Select the elliptic curve. No
curves_list String A list of curves separated by colon. When both curve and curves_list were set, if OpenSSL supports elliptic curve and curves list, the last is used. If OpenSSL supports elliptic curve and does not support curves list, the former is used. No
verifyext String / Table Extra options for handshake.
  • "lsec_continue": Handshake will not stop if an error occurs.
  • "lsec_ignore_purpose": Do not check the "purpose" flag (server/client) of the certificate.
  • "crl_check": Verify the leaf certificate against the CRL list.
  • "crl_check_chain": Verify all the certificate chain against the CRL list.
No
alpn
  • for client: String / Array of strings
  • for server: Function / Array of strings
For client, set the protocol or an array of protocols (in descending order of preference). The server can also set an array of protocols (in descending order of preference) or a callback that must return a protocol name or an array. No
dane Boolean Enable configuration to use DNS-based Authentication of Named Entities (DANE) No

Please, see OpenSSL documentation for more information.


ssl.wrap(sock, params)

Wraps the TCP connection sock and returns a new object that is used to establish a secure session. In case of error, the function returns nil, followed by an error message.

ssl.wrap needs a context, which provides parameters such as protocol, certificate, key, etc., in order to create the new connection object. You can provide a already created context in params or a table with the parameters. In this case, ssl.wrap calls ssl.newcontext to obtain the context.

Note: ssl.wrap invalidates the socket passed as argument. This prevents the garbage collector to close the TCP connection when the socket object is disposed.


conn:close()

Closes the connection.


conn:dohandshake()

Performs theTLS/SSL handshake to establesh the secure connection. In case of success, the function returns true, otherwise, false followed by an error message.

If timeout is set, conn:dohandshake can return false followed by "wantread" or "wantwrite" to indicate that the handshake was not finished yet. You have to wait the connection to be readable or writable, respectively (you can use socket.select), then call conn:dohandshake again to finish the operation.

For example:

local succ, msg
conn:settimeout(0)
while not succ do
  succ, msg = conn:dohandshake()
  if msg == "wantread" then
    socket.select({conn}, nil)
  elseif msg == "wantwrite" then
    socket.select(nil, {conn})
  else
    -- other errors
  end
end

conn:getalpn()

Returns the selected protocol.


conn:getfinished()

Returns the latest "Finished" message sent out.


conn:getpeercertificate([n])

Returns the nth certificate of the peer's chain certificate that we are connected with.

Default value to n is 1.


conn:getpeerchain()

Returns the chain certificate from the peer that we are connected with.


conn:getpeerverification()

Returns the verification state of the peer's chain certificate.


conn:getpeerfinished()

Returns the latest "Finished" message received.


conn:getsniname()

Returns the severname value specified in the handshake.


conn:getstats()

Returns accounting information on the connection, useful for throttling of bandwidth. The method returns the number of bytes received, the number of bytes sent, and the age of the connection object in seconds.


conn:info([field])

If field is omitted, this function returns a table with information about the connection.

  • algbits
  • authentication
  • bits
  • cipher
  • compression
  • encryption
  • export
  • key
  • mac
  • protocol

If field is present, this function returns its value only.


conn:receive([[pattern][, prefix]])

Reads data from the connection conn, according to the specified read pattern:

  • '*a': reads from the connection until it is closed. No end-of-line translation is performed;
  • '*l': reads a line of text from the connection. The line is terminated by a LF character (ASCII 10), optionally preceded by a CR character (ASCII 13). The CR and LF characters are not included in the returned line. In fact, all CR characters are ignored by the pattern. This is the default pattern;
  • number: causes the method to read a specified number of bytes from the socket.

The parameter prefix is an optional string to be concatenated to the beginning of any received data before return.

If successful, the method returns the received pattern. In case of error, the method returns nil followed by an error message.

Among the error messages, "closed" indicates that the connection was closed before the transmission was completed; "wantread" and "wantwrite" indicates that a timeout occurred during the operation. Also, after the error message, the function returns the partial result of the transmission.

In the case of "wantread" or "wantwrite" errors, you should wait the connection to be ready for reading or writing, respectively, and call conn:receive again.


conn:send(data [, i [, j]])

Sends data through the connection.

data is the string to be sent. The optional arguments i and j work exactly like the standard string.sub Lua function to allow the selection of a substring to be sent.

If successful, the method returns the index of the last byte within [i, j] that has been sent. Notice that, if i is 1 or absent, this is effectively the total number of bytes sent. In case of error, the method returns nil, followed by an error message and the index of the last byte within [i, j] that has been sent. You might want to try again from the byte following that.

Among the error messages, "closed" indicates that the connection was closed before the transmission was completed; "wantread" and "wantwrite" indicates that a timeout occured during the operation.

In the case of "wantread" or "wantwrite" errors, you should wait the connection to be ready for reading or writing, respectively, and call conn:send again.


conn:setdane(basedomain)

This function enables the use of DNS-based Authentication of Named Entities (DANE) in the connection. It must be called before the handshake. basedomain will be the primary reference for certificate name checks.

Note that dane field must be true when creating a new context in order to use DANE.


conn:setstats(received, sent, age)

Resets accounting information on the connection, useful for throttling of bandwidth.

Received is a number with the new number of bytes received. Sent is a number with the new number of bytes sent. Age is the new age in seconds.

The method returns 1 in case of success and nil otherwise.


conn:settimeout(value [, mode])

Changes the timeout values for the connection. By default, the operations conn:send, conn:receive, and conn:dohandshake will block indefinitely, until the operation completes. When a timeout is set and the specified amount of time has elapsed, the affected methods give up and fail with an error code.

The amount of time to wait is specified as the value parameter, in seconds. There are two timeout modes and both can be used together for fine tuning:

  • 'b': block timeout. Specifies the upper limit on the amount of time LuaSec can be blocked by the operating system while waiting for completion of any single I/O operation. This is the default mode;
  • 't': total timeout. Specifies the upper limit on the amount of time LuaSec can block a Lua script before returning from a call.

The nil timeout value allows operations to block indefinitely. Negative timeout values have the same effect.


conn:settlsa(usage, selector, mtype, data)

This function can be called one or more times to load the TLSA records. It must be called before the handshake.


conn:sni(name)

conn:sni(map [, strict])

Client uses the first form to inform the name (string) to connect to a server. This function must be called after ssl.wrap() and before conn:dohandshake().

The server uses the second form to register pairs of <name,context>, using parameter map (table). OpenSSL will match the name informed by the client to recover the context to use in the handshake.

When the name informed by the client was not registered by the server, if strict is true, the handshake fails. If strict is false, the server uses the context passed in ssl.wrap() call and the handshake proceeds.


conn:want()

Informs the reason that triggers the timeout in the last call of conn:send, conn:receive, or conn:dohandshake. The string "read" indicates the operation was not performed because the connection was not ready for reading. In the same way, "write" indicates the connection was not ready for writing. If the operations were successfully complited, the string "nothing" is returned.


cert:digest([alg])

Computes the certificate fingerprint.

alg can be "sha1" (default), "sha256", or "sha512".


cert:extensions()

Retrieves the extension fields from certificate.


cert:getsignaturename()

Retrieves the signature's name of the certificate.


cert:issued(subject)

Verifies if certificate cert issued the certificate subject.


cert:issuer()

Retrives the Issuer field from certificate.


cert:notbefore()

Returns the "not before" date.


cert:notafter()

Returns the "not after" date.


cert:pem()

Exports the certificate as string in PEM format. See ssl.loadcertificate()


cert:pubkey()

Returns the public key in PEM format.


cert:serial()

Returns the certificate's Serial Number.


cert:setencode(encode)

Set how strings like hostname or email are encoded in the certificate.

Supported encodes: "ai5" for ASCII and "utf8" for UTF-8.


cert:subject()

Retrives the Subject from certificate.


cert:validat(t)

Checks if the certificate is valid in a given time.


https.request(url [ , body])

This is a simple HTTPS client built on top of LuaSocket's HTTP module. This function creates a custom create function, that performs the secure connection with the server, and passes it to LuaSocket.

If url is a table, it should contain an union of LuaSocket's HTTP options and LuaSec configuration. However, the current implementation does not support proxy nor URL redirection, so the fields redirect and proxy are not supported in url. Also, setting http.PROXY is not permitted.

In the case url is a string, the module uses the following default configuration to establish the connection:

default = {
  protocol = "any",
  options = "all",
  verify = "none",
}

The parameter body is an optional string sent as request body.

In case of failure, https.requet returns nil followed by an error message. In case of success, if url is a string, the function returns the response's body, status code, headers, and status line. If url is a table, the function returns the same results, except the response's body is replaced by the value 1.

For example:

local res, code, headers, status = https.request("https://www.site.com.br")

local one, code, headers, status = https.request {
  url = "https://www.site.com.br",
  sink = ltn12.sink.file(io.stdout),
  protocol = "any",
  options = "all",
  verify = "none",
}