FFI-based OpenSSL binding for LuaJIT, supporting OpenSSL 3.0, 1.1 and 1.0.2 series
- Description
- Status
- Synopsis
- resty.openssl
- resty.openssl.version
- resty.openssl.pkey
- resty.openssl.bn
- bn.new
- bn.dup
- bn.istype
- bn.from_binary, bn:to_binary
- bn.from_hex, bn:to_hex
- bn.from_dec, bn:to_dec
- bn:to_number
- bn:__metamethods
- bn:add, bn:sub, bn:mul, bn:div, bn:exp, bn:mod, bn:gcd
- bn:sqr
- bn:mod_add, bn:mod_sub, bn:mod_mul, bn:mod_exp
- bn:mod_sqr
- bn:lshift, bn:rshift
- bn:is_zero, bn:is_one, bn:is_odd, bn:is_word
- bn:is_prime
- resty.openssl.cipher
- resty.openssl.digest
- resty.openssl.hmac
- resty.openssl.kdf
- resty.openssl.objects
- resty.openssl.rand
- resty.openssl.x509
- x509.new
- x509.dup
- x509.istype
- x509:digest
- x509:pubkey_digest
- x509:get_, x509:set_
- x509:get_lifetime
- x509:set_lifetime
- x509:get_extension
- x509:add_extension
- x509:set_extension
- x509:get_extension_critical
- x509:set_extension_critical
- x509:get_ocsp_url
- x509:get_crl_url
- x509:sign
- x509:verify
- x509:tostring
- x509:to_PEM
- resty.openssl.x509.csr
- resty.openssl.x509.crl
- resty.openssl.x509.name
- resty.openssl.x509.altname
- resty.openssl.x509.extension
- resty.openssl.x509.extension.dist_points
- resty.openssl.x509.extension.info_access
- resty.openssl.x509.chain
- resty.openssl.x509.store
- Functions for stack-like objects
- Compatibility
- Copyright and License
- See Also
lua-resty-openssl is a FFI-based OpenSSL binding library, currently
supports OpenSSL 3.0.0, 1.1.1, 1.1.0 and 1.0.2 series.
Note: when using with OpenSSL 1.0.2, it's recommanded to not use this library with other FFI-based OpenSSL binding libraries to avoid potential mismatch of cdef.
Production.
This library is greatly inspired by luaossl, while uses the
naming conversion closer to original OpenSSL API.
For example, a function called X509_set_pubkey in OpenSSL C API will expect to exist
as resty.openssl.x509:set_pubkey.
CamelCases are replaced to underscore_cases, for exmaple X509_set_serialNumber becomes
resty.openssl.x509:set_serial_number. Another difference than luaossl is that errors are never thrown
using error() but instead return as last parameter.
Each Lua table returned by new() contains a cdata object ctx. User are not supposed to manully setting
ffi.gc or calling corresponding destructor of the ctx struct (like *_free functions).
This meta module provides a version sanity check against linked OpenSSL library and returns all exported modules to a table.
return {
_VERSION = 'x.y.z',
bn = require("resty.openssl.bn"),
cipher = require("resty.openssl.cipher"),
digest = require("resty.openssl.digest"),
hmac = require("resty.openssl.hmac"),
kdf = require("resty.openssl.kdf"),
pkey = require("resty.openssl.pkey"),
objects = require("resty.openssl.objects"),
rand = require("resty.openssl.rand"),
version = require("resty.openssl.version"),
x509 = require("resty.openssl.x509"),
altname = require("resty.openssl.x509.altname"),
chain = require("resty.openssl.x509.chain"),
csr = require("resty.openssl.x509.csr"),
crl = require("resty.openssl.x509.crl"),
extension = require("resty.openssl.x509.extension"),
name = require("resty.openssl.x509.name"),
store = require("resty.openssl.x509.store"),
}Starting OpenSSL 3.0, provider is also available.
syntax: openssl.luaossl_compat()
Provides luaossl flavored API which uses camelCase naming; user can expect drop in replacement.
For example, pkey:get_parameters is mapped to pkey:getParameters.
Note that not all luaossl API has been implemented, please check readme for source of truth.
syntax: openssl.resty_hmac_compat()
Call this function before require("resty.hmac") to allow these two libraries play nice with
each other. This function is not available with OpenSSL 1.0.
A module to provide version info.
The OpenSSL version number.
The OpenSSL version text.
syntax: text = version.version(types)
Returns various OpenSSL version information. Available values for types are:
VERSION
CFLAGS
BUILT_ON
PLATFORM
DIR
ENGINES_DIR
VERSION_STRING
FULL_VERSION_STRING
MODULES_DIR
CPU_INFO
For OpenSSL prior to 1.1.x, only VERSION, CFLAGS, BUILT_ON, PLATFORM
and DIR are supported. Please refer to
OPENSSL_VERSION_NUMBER(3)
for explanation of each type.
local version = require("resty.openssl.version")
ngx.say(string.format("%x", version.version_num))
-- outputs "101000bf"
ngx.say(version.version_text)
-- outputs "OpenSSL 1.1.0k 28 May 2019"
ngx.say(version.version(version.PLATFORM))
-- outputs "darwin64-x86_64-cc"syntax: text = version.info(types)
Returns various OpenSSL information. Available values for types are:
INFO_ENGINES_DIR
INFO_DSO_EXTENSION
INFO_CPU_SETTINGS
INFO_LIST_SEPARATOR
INFO_DIR_FILENAME_SEPARATOR
INFO_CONFIG_DIR
INFO_SEED_SOURCE
INFO_MODULES_DIR
This function is only available on OpenSSL 3.0. Please refer to OPENSSL_VERSION_NUMBER(3) for explanation of each type.
local version = require("resty.openssl.version")
ngx.say(version.version(version.INFO_DSO_EXTENSION))
-- outputs ".so"A boolean indicates whether the linked OpenSSL is 3.0 series.
A boolean indicates whether the linked OpenSSL is 1.1 series.
A boolean indicates whether the linked OpenSSL is 1.0 series.
Module to interact with private keys and public keys (EVP_PKEY).
Each key type may only support part of operations:
| Key Type | Load existing key | Key generation | Encrypt/Decrypt | Sign/Verify | Key Exchange |
|---|---|---|---|---|---|
| RSA | Y | Y | Y | Y | |
| EC | Y | Y | Y (ECDSA) | Y (ECDH) | |
| Ed25519 | Y | Y | Y (PureEdDSA) | ||
| X25519 | Y | Y | Y (ECDH) | ||
| Ed448 | Y | Y | Y (PureEdDSA) | ||
| X448 | Y | Y | Y (ECDH) |
Ed25519, X25519, Ed448 and X448 keys are only supported since OpenSSL 1.1.0.
syntax: pk, err = pkey.new(config)
syntax: pk, err = pkey.new(string, opts?)
syntax: pk, err = pkey.new()
Creates a new pkey instance. The first argument can be:
- A
configtable to create a new PKEY pair. Which defaults to:
pkey.new({
type = 'RSA',
bits = 2048,
exp = 65537
})to create EC private key:
pkey.new({
type = 'EC',
curve = 'prime196v1',
})To see list of supported EC curves, use openssl ecparam -list_curves.
Other possible types are Ed25519, X25519, Ed448 and X448. No additional parameters
can be set during key generation for those keys.
- A
stringof private or public key in PEM, DER or JWK format text; optionally accpet a tableoptsto explictly loadformatand keytype. When loading a key in PEM format,passphraseorpassphrase_cbmay be provided to decrypt the key.
pkey.new(pem_or_der_text, {
format = "*", -- choice of "PEM", "DER", "JWK" or "*" for auto detect
type = "*", -- choice of "pr" for privatekey, "pu" for public key and "*" for auto detect
passphrase = "secret password", -- the PEM encryption passphrase
passphrase_cb = function()
return "secret password"
end, -- the PEM encryption passphrase callback function
}
- When loading JWK, make sure the encoded JSON text is passed in.
- Currently it's not supported to contraint
typeon JWK key, the parameters in provided JSON will decide if a private or public key is loaded. - Only JWK with key type of
RSA,P-256,P-384andP-512EC,Ed25519,X25519,Ed448andX448OKPkeys are supported. - Public key part for
OKPkeys (thexparameter) is always not honored and derived from private key part (thedparameter) if it's specified.
nilto create a 2048 bits RSA key.- A
EVP_PKEY*pointer, to return a wrappedpkeyinstance. Normally user won't use this approach. User shouldn't free the pointer on their own, since the pointer is not copied.
syntax: ok = pkey.istype(table)
Returns true if table is an instance of pkey. Returns false otherwise.
syntax: parameters, err = pk:get_parameters()
Returns a table containing the parameters of pkey instance.
syntax: ok, err = pk:set_parameters(params)
Set the paramets of the pkey from a table params.
If the parameter is not set in the params table,
it remains untouched in the pkey instance.
local pk, err = require("resty.openssl.pkey").new()
local parameters, err = pk:get_parameters()
local e = parameters.e
ngx.say(e:to_number())
-- outputs 65537
local ok, err = pk:set_parameters({
e = require("resty.openssl.bn").from_hex("100001")
})
local ok, err = pk:set_parameters(parameters)Parameters for RSA key:
| Parameter | Description | Type |
|---|---|---|
| n | modulus common to both public and private key | bn |
| e | public exponent | bn |
| d | private exponent | bn |
| p | first factor of n | bn |
| q | second factor of n | bn |
| dmp1 | d mod (p - 1), exponent1 |
bn |
| dmq1 | d mod (q - 1), exponent2 |
bn |
| iqmp | (InverseQ)(q) = 1 mod p, coefficient |
bn |
Parameters for EC key:
| Parameter | Description | Type |
|---|---|---|
| private | private key | bn |
| public | public key | bn |
| x | x coordinate of the public key | bn |
| y | y coordinate of the public key | bn |
| group | the named curve group | NID as a number, when passed in as set_parameters(), it's also possible to use the text representation. This is different from luaossl where a EC_GROUP instance is returned. |
It's not possible to set x, y with public at same time as x and y is basically another representation
of public. Also currently it's only possible to set x and y at same time.
Parameters for Curve25519 and Curve448 keys:
| Parameter | Description | Type |
|---|---|---|
| private | raw private key represented as bytes | string |
| public | raw public key represented as bytes | string |
syntax: obj, err = pk:get_key_type()
Returns a ASN1_OBJECT of key type of the private key as a table.
local pkey, err = require("resty.openssl.pkey").new({type="X448"})
ngx.say(require("cjson").encode(pkey:get_key_type()))
-- outputs '{"ln":"X448","nid":1035,"sn":"X448","id":"1.3.101.111"}'syntax: signature, err = pk:sign(digest)
Sign a digest using the private key defined in pkey
instance. The digest parameter must be a resty.openssl.digest
instance. Returns the signed raw binary and error if any. For EC key, this function
does a ECDSA signing.
The passed in digest parameter should not have been called final(),
user should only use update().
Note that OpenSSL does not support EC digital signature (ECDSA) with the obsolete MD5 hash algorithm and will return error on this combination. See EVP_DigestSign(3) for a list of algorithms and associated public key algorithms.
For Ed25519 or Ed448 keys, this function does a PureEdDSA verification and requires
digest to be the string that needs signing.
-- RSA and EC keys
local pk, err = require("resty.openssl.pkey").new()
local digest, err = require("resty.openssl.digest").new("SHA256")
digest:update("dog")
-- WRONG:
-- digest:final("dog")
local signature, err = pk:sign(digest)
ngx.say(ngx.encode_base64(signature))
-- Ed25519 and Ed448 keys
local pk, err = require("resty.openssl.pkey").new({
type = "Ed25519",
})
local signature, err = pk:sign("23333")
ngx.say(ngx.encode_base64(signature))syntax: ok, err = pk:verify(signature, digest)
Verify a signture (which can be the string returned by pkey:sign). The second
argument must be a resty.openssl.digest instance that uses
the same digest algorithm as used in sign. ok returns true if verficiation is
successful and false otherwise. Note when verfication failed err will not be set.
For EC key, this function does a ECDSA verification.
For Ed25519 or Ed448 keys, this function does a PureEdDSA verification and requires
both signature and digest to be string.
syntax: cipher_txt, err = pk:encrypt(txt, padding?)
Encrypts plain text txt with pkey instance, which must loaded a public key.
When key is a RSA key, the function accepts an optional second argument padding which can be:
pkey.PADDINGS = {
RSA_PKCS1_PADDING = 1,
RSA_SSLV23_PADDING = 2,
RSA_NO_PADDING = 3,
RSA_PKCS1_OAEP_PADDING = 4,
RSA_X931_PADDING = 5,
RSA_PKCS1_PSS_PADDING = 6,
}If omitted, padding is default to pkey.PADDINGS.RSA_PKCS1_PADDING.
syntax: txt, err = pk:decrypt(cipher_txt, padding?)
Decrypts cipher text cipher_txt with pkey instance, which must loaded a private key.
The optional second argument padding has same meaning in pkey:encrypt.
local pkey = require("resty.openssl.pkey")
local privkey, err = pkey.new()
local pub_pem = privkey:to_PEM("public")
local pubkey, err = pkey.new(pub_pem)
local s, err = pubkey:encrypt("🦢", pkey.PADDINGS.RSA_PKCS1_PADDING)
ngx.say(#s)
-- outputs 256
local decrypted, err = privkey:decrypt(s)
ngx.say(decrypted)
-- outputs "🦢"syntax: txt, err = pk:derive(peer_key)
Derive public key algorithm shared secret peer_key, which must be a pkey
instance.
See examples/x25519-dh.lua for an example on how key exchange works for X25519 keys with DH algorithm.
syntax: txt, err = pk:tostring(private_or_public?, fmt?)
Outputs private key or public key of pkey instance in PEM-formatted text.
The first argument must be a choice of public, PublicKey, private, PrivateKey or nil.
The second argument fmt can be PEM, DER, JWK or nil.
If both arguments are omitted, this functions returns the PEM representation of public key.
syntax: pem, err = pk:to_PEM(private_or_public?)
Equivalent to pk:tostring(private_or_public, "PEM").
Module to expose BIGNUM structure. Note bignum is a big integer, no float operations (like square root) are supported.
syntax: b, err = bn.new(number?)
Creates a bn instance. The first argument can be a Lua number or nil to
creates an empty instance.
syntax: b, err = bn.dup(bn_ptr_cdata)
Duplicates a BIGNUM* to create a new bn instance.
syntax: ok = bn.istype(table)
Returns true if table is an instance of bn. Returns false otherwise.
syntax: bn, err = bn.from_binary(bin)
syntax: bin, err = bn:to_binary()
Creates a bn instance from binary string.
Exports the BIGNUM value in binary string.
local b, err = require("resty.openssl.bn").from_binary(ngx.decode_base64("WyU="))
local bin, err = b:to_binary()
ngx.say(ngx.encode_base64(bin))
-- outputs "WyU="syntax: bn, err = bn.from_hex(hex)
syntax: hex, err = bn:to_hex()
Creates a bn instance from hex encoded string. Note that the leading 0x should not be
included. A leading - indicating the sign may be included.
Exports the bn instance to hex encoded string.
local bn = require("resty.openssl.bn")
local b = bn.from_hex("5B25")
local hex, err = b:to_hex()
ngx.say(hex)
-- outputs "5B25"syntax: bn, err = bn.from_dec(dec)
syntax: dec, err = bn:to_dec()
Creates a bn instance from decimal string. A leading - indicating the sign may be included.
Exports the bn instance to decimal string.
local bn = require("resty.openssl.bn")
local b = bn.from_dec("23333")
local dec, err = b:to_dec()
ngx.say(dec)
-- outputs "23333"syntax: n, err = bn:to_number()
syntax: n, err = bn:tonumber()
Export the lowest 32 bits or 64 bits part (based on the ABI) of bn instance
to a number. This is useful when user wants to perform bitwise operations.
local bn = require("resty.openssl.bn")
local b = bn.from_dec("23333")
local n, err = b:to_number()
ngx.say(n)
-- outputs 23333
ngx.say(type(n))
-- outputs "number"Various mathematical operations can be performed as if it's a number.
local bn = require("resty.openssl.bn")
local a = bn.new(123456)
local b = bn.new(222)
-- the following returns a bn
local r
r = -a
r = a + b
r = a - b
r = a * b
r = a / b -- equal to bn:idiv, returns floor division
r = a % b
-- all operations can be performed between number and bignum
r = a + 222
r = 222 + a
-- the following returns a bool
local bool
bool = a < b
bool = a >= b
-- compare between number will not work
-- WRONG: bool = a < 222syntax: r = a:op(b)
syntax: r = bn.op(a, b)
Perform mathematical operations op.
add: addsub: subtractmul: multiplydiv,idiv: floor division (division with rounding down to nearest integer)exp,pow: theb-th power ofa, this function is faster than repeateda * a * ....mod: modulogcd: the greatest common divider ofaandb.
Note that add, sub, mul, div, mod is also available with +, -, *, /, % operaters.
See above section for examples.
local bn = require("resty.openssl.bn")
local a = bn.new(123456)
local b = bn.new(9876)
local r
-- the followings are equal
r = a:add(b)
r = bn.add(a, b)
r = a:add(9876)
r = bn.add(a, 9876)
r = bn.add(123456, b)
r = bn.add(123456, 9876)syntax: r = a:sqr()
syntax: r = bn.sqr(a)
Computes the 2-th power of a. This function is faster than r = a * a.
syntax: r = a:op(b, m)
syntax: r = bn.op(a, b, m)
Perform modulo mathematical operations op.
mod_add: addsatobmodulommod_sub: substractsbfromamodulommod_mul: multipliesabyband finds the non-negative remainder respective to modulusmmod_exp,mod_pow: computesato theb-th power modulom(r=a^b % m). This function uses less time and space thanexp. Do not call this function whenmis even and any of the parameters have theBN_FLG_CONSTTIMEflag set.
local bn = require("resty.openssl.bn")
local a = bn.new(123456)
local b = bn.new(9876)
local r
-- the followings are equal
r = a:mod_add(b, 3)
r = bn.mod_add(a, b, 3)
r = a:mod_add(9876, 3)
r = bn.mod_add(a, 9876, 3)
r = bn.mod_add(123456, b, 3)
r = bn.mod_add(123456, 9876, 3)syntax: r = a:mod_sqr(m)
syntax: r = bn.mod_sqr(a, m)
Takes the square of a modulo m.
syntax: r = bn:lshift(bit)
syntax: r = bn.lshift(a, bit)
syntax: r = bn:rshift(bit)
syntax: r = bn.rshift(a, bit)
Bit shift a to bit bits.
syntax: ok = bn:is_zero()
syntax: ok = bn:is_one()
syntax: ok = bn:is_odd()
syntax: ok, err = bn:is_word(n)
Checks if bn is 0, 1, and odd number or a number n respectively.
syntax: ok, err = bn:is_prime(nchecks?)
Checks if bn is a prime number. Returns true if it is prime with an
error probability of less than 0.25^nchecks and error if any. If omitted,
nchecks is set to 0 which means to select number of iterations basedon the
size of the number
This function perform a Miller-Rabin probabilistic primality test with nchecks iterations. If nchecks == BN_prime_checks (0), a number of iterations is used that yields a false positive rate of at most 2^-64 for random input. The error rate depends on the size of the prime and goes down for bigger primes. The rate is 2^-80 starting at 308 bits, 2^-112 at 852 bits, 2^-128 at 1080 bits, 2^-192 at 3747 bits and 2^-256 at 6394 bits.
When the source of the prime is not random or not trusted, the number of checks needs to be much higher to reach the same level of assurance: It should equal half of the targeted security level in bits (rounded up to the next integer if necessary). For instance, to reach the 128 bit security level, nchecks should be set to 64.
See also BN_is_prime(3).
Module to interact with symmetric cryptography (EVP_CIPHER).
syntax: d, err = cipher.new(cipher_name)
Creates a cipher instance. cipher_name is a case-insensitive string of cipher algorithm name.
To view a list of cipher algorithms implemented, use openssl list -cipher-algorithms.
syntax: ok = cipher.istype(table)
Returns true if table is an instance of cipher. Returns false otherwise.
syntax: s, err = cipher:encrypt(key, iv?, s, no_padding?, aead_aad?)
Encrypt the text s with key key and IV iv. Returns the encrypted text in raw binary string
and error if any.
Optionally accepts a boolean no_padding which tells the cipher to enable or disable padding and default
to false (enable padding). If no_padding is true, the length of s must then be a multiple of the
block size or an error will occur.
When using GCM or CCM mode or chacha20-poly1305 cipher, it's also possible to pass
the Additional Authenticated Data (AAD) as the fifth argument.
This function is a shorthand of cipher:init, cipher:set_aead_aad (if appliable) then cipher:final.
syntax: s, err = cipher:decrypt(key, iv?, s, no_padding?, aead_aad?, aead_tag?)
Decrypt the text s with key key and IV iv. Returns the decrypted text in raw binary string
and error if any.
Optionally accepts a boolean no_padding which tells the cipher to enable or disable padding and default
to false (enable padding). If no_padding is true, the length of s must then be a multiple of the
block size or an error will occur; also, padding in the decrypted text will not be removed.
When using GCM or CCM mode or chacha20-poly1305 cipher, it's also possible to pas
the Additional Authenticated Data (AAD) as the fifth argument and authentication tag
as the sixth argument.
This function is a shorthand of cipher:init, cipher:set_aead_aad (if appliable),
cipher:set_aead_tag (if appliable) then cipher:final.
syntax: ok, err = cipher:init(key, iv?, opts?)
Initialize the cipher with key key and IV iv. The optional third argument is a table consists of:
{
is_encrypt = false,
no_padding = false,
}Calling function is needed before cipher:update and cipher:final if the cipher is not being initialized already. But not cipher:encrypt and cipher:decrypt.
If you wish to reuse cipher instance multiple times, calling this function is necessary
to clear the internal state of the cipher. The shorthand functions
cipher:encrypt and cipher:decrypt
already take care of initialization and reset.
syntax: s, err = cipher:update(partial, ...)
Updates the cipher with one or more strings. If the cipher has larger than block size of data to flush, the function will return a non-empty string as first argument. This function can be used in a streaming fashion to encrypt or decrypt continous data stream.
syntax: ok, err = cipher:update_aead_aad(aad)
Provides AAD data to the cipher, this function can be called more than one times.
syntax: tag, err = cipher:get_aead_tag(size?)
Gets the authentication tag from cipher with length specified as size. If omitted, a tag with length
of half of the block size will be returned. The size cannot exceed block size.
This function can only be called after encryption is finished.
syntax: ok, err = cipher:set_aead_tag(tag)
Set the authentication tag of cipher with tag.
This function can only be called before decryption starts.
syntax: s, err = cipher:final(partial?)
Returns the encrypted or decrypted text in raw binary string, optionally accept one string to encrypt or decrypt.
-- encryption
local c, err = require("resty.openssl.cipher").new("aes256")
c:init(string.rep("0", 32), string.rep("0", 16), {
is_encrypt = true,
})
c:update("🦢")
local cipher, err = c:final()
ngx.say(ngx.encode_base64(cipher))
-- outputs "vGJRHufPYrbbnYYC0+BnwQ=="
-- OR:
local c, err = require("resty.openssl.cipher").new("aes256")
local cipher, err = c:encrypt(string.rep("0", 32), string.rep("0", 16), "🦢")
ngx.say(ngx.encode_base64(cipher))
-- outputs "vGJRHufPYrbbnYYC0+BnwQ=="
-- decryption
local encrypted = ngx.decode_base64("vGJRHufPYrbbnYYC0+BnwQ==")
local c, err = require("resty.openssl.cipher").new("aes256")
c:init(string.rep("0", 32), string.rep("0", 16), {
is_encrypt = false,
})
c:update(encrypted)
local cipher, err = c:final()
ngx.say(cipher)
-- outputs "🦢"
-- OR:
local c, err = require("resty.openssl.cipher").new("aes256")
local cipher, err = c:decrypt(string.rep("0", 32), string.rep("0", 16), encrypted)
ngx.say(cipher)
-- outputs "🦢"See examples/aes-gcm-aead.lua for an example to use AEAD modes with authentication.
syntax: key, iv, err = cipher:derive(key, salt?, count?, md?)
Derive a key and IV (if appliable) from given material that can be used in current cipher. This function is useful mainly to work with keys that were already derived from same algorithm. Newer applications should use a more modern algorithm such as PBKDF2 provided by kdf.derive.
count is the iteration count to perform. If it's omitted, it's set to 1. Note the recent version of
openssl enc cli tool automatically use PBKDF2 if -iter is set to larger than 1,
while this function will not. To use PBKDF2 to derive a key, please refer to kdf.derive.
md is the message digest name to use, it can take one of the values md2, md5, sha or sha1.
If it's omitted, it's default to sha1.
local cipher = require("resty.openssl.cipher").new("aes-128-cfb")
local key, iv, err = cipher:derive("x")
-- equivalent to `openssl enc -aes-128-cfb -pass pass:x -nosalt -P -md sha1`Module to interact with message digest (EVP_MD_CTX).
syntax: d, err = digest.new(digest_name?)
Creates a digest instance. digest_name is a case-insensitive string of digest algorithm name.
To view a list of digest algorithms implemented, use openssl list -digest-algorithms.
If digest_name is omitted, it's default to sha1. Specially, the digest_name "null"
represents a "null" message digest that does nothing: i.e. the hash it returns is of zero length.
syntax: ok = digest.istype(table)
Returns true if table is an instance of digest. Returns false otherwise.
syntax: ok, err = digest:update(partial, ...)
Updates the digest with one or more strings.
syntax: str, err = digest:final(partial?)
Returns the digest in raw binary string, optionally accept one string to digest.
local d, err = require("resty.openssl.digest").new("sha256")
d:update("🦢")
local digest, err = d:final()
ngx.say(ngx.encode_base64(digest))
-- outputs "tWW/2P/uOa/yIV1gRJySJLsHq1xwg0E1RWCvEUDlla0="
-- OR:
local d, err = require("resty.openssl.digest").new("sha256")
local digest, err = d:final("🦢")
ngx.say(ngx.encode_base64(digest))
-- outputs "tWW/2P/uOa/yIV1gRJySJLsHq1xwg0E1RWCvEUDlla0="syntax: ok, err = digest:reset()
Reset the internal state of digest instance as it's just created by digest:new.
It calls EVP_DigestInit_ex under
the hood.
Module to interact with hash-based message authentication code (HMAC_CTX).
syntax: h, err = hmac.new(key, digest_name?)
Creates a hmac instance. digest_name is a case-insensitive string of digest algorithm name.
To view a list of digest algorithms implemented, use openssl list -digest-algorithms.
If digest_name is omitted, it's default to sha1.
syntax: ok = hmac.istype(table)
Returns true if table is an instance of hmac. Returns false otherwise.
syntax: ok, err = hmac:update(partial, ...)
Updates the HMAC with one or more strings.
syntax: str, err = hmac:final(partial?)
Returns the HMAC in raw binary string, optionally accept one string to digest.
local d, err = require("resty.openssl.hmac").new("goose", "sha256")
d:update("🦢")
local hmac, err = d:final()
ngx.say(ngx.encode_base64(hmac))
-- outputs "k2UcrRp25tj1Spff89mJF3fAVQ0lodq/tJT53EYXp0c="
-- OR:
local d, err = require("resty.openssl.hmac").new("goose", "sha256")
local hmac, err = d:final("🦢")
ngx.say(ngx.encode_base64(hmac))
-- outputs "k2UcrRp25tj1Spff89mJF3fAVQ0lodq/tJT53EYXp0c="syntax: ok, err = hmac:reset()
Reset the internal state of hmac instance as it's just created by hmac:new.
It calls HMAC_Init_ex under
the hood.
Module to interact with KDF (key derivation function).
syntax: key, err = kdf.derive(options)
Derive a key from given material. Various KDFs are supported based on OpenSSL version:
- On OpenSSL 1.0.2 and later,
PBKDF2(RFC 2898, NIST SP 800-132) is available. - On OpenSSL 1.1.0 and later,
HKDF(RFC 5869),TLS1-PRF(RFC 2246, RFC 5246 and NIST SP 800-135 r1) andscrypt(RFC 7914) is available.
options is a table that contains:
| Key | Type | Description | Required or default |
|---|---|---|---|
| type | number | Type of KDF function to use, one of kdf.PBKDF2, kdf.SCRYPT, kdf.TLS1_PRF or kdf.HKDF |
required |
| outlen | number | Desired key length to derive | required |
| pass | string | Initial key material to derive from | (empty string) |
| salt | string | Add some salt | (empty string) |
| md | string | Message digest method name to use, not effective for scrypt type |
"sha1" |
| pbkdf2_iter | number | PBKDF2 iteration count. RFC 2898 suggests an iteration count of at least 1000. Any value less than 1 is treated as a single iteration. | 1 |
| hkdf_key | string | HKDF key | required |
| hkdf_mode | number | HKDF mode to use, one of kdf.HKDEF_MODE_EXTRACT_AND_EXPAND, kdf.HKDEF_MODE_EXTRACT_ONLY or kdf.HKDEF_MODE_EXPAND_ONLY. This is only effective with OpenSSL >= 1.1.1. To learn about mode, please refer to EVP_PKEY_CTX_set1_hkdf_key(3). |
kdf.HKDEF_MODE_EXTRACT_AND_EXPAND |
| hkdf_info | string | HKDF info value | (empty string) |
| tls1_prf_secret | string | TLS1-PRF secret | required |
| tls1_prf_seed | string | TLS1-PRF seed | required |
| scrypt_maxmem | number | Scrypt maximum memory usage in bytes | 32 * 1024 * 1024 |
| scrypt_N | number | Scrypt CPU/memory cost parameter, must be a power of 2 | required |
| scrypt_r | number | Scrypt blocksize parameter (8 is commonly used) | required |
| scrypt_p | number | Scrypt parallelization parameter | required |
local kdf = require("resty.openssl.kdf")
local key, err = kdf.derive({
type = kdf.PBKDF2,
outlen = 16,
pass = "1234567",
md = "md5",
pbkdf2_iter = 1000,
})
ngx.say(ngx.encode_base64(key))
-- outputs "cDRFLQ7NWt+AP4i0TdBzog=="
key, err = kdf.derive({
type = kdf.SCRYPT,
outlen = 16,
pass = "1234567",
scrypt_N = 1024,
scrypt_r = 8,
scrypt_p = 16,
})
ngx.say(ngx.encode_base64(key))
-- outputs "9giFtxace5sESmRb8qxuOw=="Helpfer module on ASN1_OBJECT.
syntax: tbl = objects.bytes(asn1_obj)
Convert a ASN1_OBJECT pointer to a Lua table where
{
id: OID of the object,
nid: NID of the object,
sn: short name of the object,
ln: long name of the object,
}
syntax: tbl, err = objects.nid2table(nid)
Convert a NID to a Lua table, returns the same format as objects.obj2table
syntax: nid, err = objects.txt2nid(txt)
Convert a text representation to NID.
Module to interact with random number generator.
syntax: str, err = rand.bytes(length)
Generate random bytes with length of length.
Module to interact with X.509 certificates.
syntax: crt, err = x509.new(txt?, fmt?)
Creates a x509 instance. txt can be PEM or DER formatted text;
fmt is a choice of PEM, DER to load specific format, or * for auto detect.
When txt is omitted, new() creates an empty x509 instance.
syntax: x509, err = x509.dup(x509_ptr_cdata)
Duplicates a X509* to create a new x509 instance.
syntax: ok = x509.istype(table)
Returns true if table is an instance of x509. Returns false otherwise.
syntax: d, err = x509:digest(digest_name?)
Returns a digest of the DER representation of the X509 certificate object in raw binary text.
digest_name is a case-insensitive string of digest algorithm name.
To view a list of digest algorithms implemented, use openssl list -digest-algorithms.
If digest_name is omitted, it's default to sha1.
syntax: d, err = x509:pubkey_digest(digest_name?)
Returns a digest of the DER representation of the pubkey in the X509 object in raw binary text.
digest_name is a case-insensitive string of digest algorithm name.
To view a list of digest algorithms implemented, use openssl list -digest-algorithms.
If digest_name is omitted, it's default to sha1.
syntax: ok, err = x509:set_attribute(instance)
syntax: instance, err = x509:get_attribute()
Setters and getters for x509 attributes share the same syntax.
| Attribute name | Type | Description |
|---|---|---|
| issuer_name | x509.name | Issuer of the certificate |
| not_before | number | Unix timestamp when certificate is not valid before |
| not_after | number | Unix timestamp when certificate is not valid after |
| pubkey | pkey | Public key of the certificate |
| serial_number | bn | Serial number of the certficate |
| subject_name | x509.name | Subject of the certificate |
| version | number | Version of the certificate, value is one less than version. For example, 2 represents version 3 |
Additionally, getters and setters for extensions are also available:
| Extension name | Type | Description |
|---|---|---|
| subject_alt_name | x509.altname | Subject Alternative Name of the certificate, SANs are usually used to define "additional Common Names" |
| issuer_alt_name | x509.altname | Issuer Alternative Name of the certificate |
| basic_constraints | table, { ca = bool, pathlen = int} | Basic Constriants of the certificate |
| info_access | x509.extension.info_access | Authority Information Access of the certificate, contains information like OCSP reponder URL. |
| crl_distribution_points | x509.extension.dist_points | CRL Distribution Points of the certificate, contains information like Certificate Revocation List(CRL) URLs. |
For all extensions, get_{extension}_critical and set_{extension}_critical is also supported to
access the critical flag of the extension.
If the attribute is not found, getter will return nil, nil.
local x509, err = require("resty.openssl.x509").new()
err = x509:set_not_before(ngx.time())
local not_before, err = x509:get_not_before()
ngx.say(not_before)
-- outputs 1571875065
err = x509:set_basic_constraints_critical(true)If type is a table, setter requires a table with case-insensitive keys to set; getter returns the value of the given case-insensitive key or a table of all keys if no key provided.
local x509, err = require("resty.openssl.x509").new()
err = x509:set_basic_constraints({
cA = false,
pathlen = 0,
})
ngx.say(x509:get_basic_constraints("pathlen"))
-- outputs 0
ngx.say(x509:get_basic_constraints())
-- outputs '{"ca":false,"pathlen":0}'Note that user may also access the certain extension by x509:get_extension and
x509:set_extension, while the later two function returns or requires
extension instead. User may use getter and setters listed here if modification
of current extensions is needed; use x509:get_extension or
x509:set_extension if user are adding or replacing the whole extension or
getters/setters are not implemented. If the getter returned a type of x509.* instance, it can be
converted to a extension instance by extension:from_data,
and thus used by x509:get_extension and x509:set_extension
syntax: not_before, not_after, err = x509:get_lifetime()
A shortcut of x509:get_not_before plus x509:get_not_after
syntax: ok, err = x509:set_lifetime(not_before, not_after)
A shortcut of x509:set_not_before
plus x509:set_not_after.
syntax: extension, pos, err = x509:get_extension(nid_or_txt, last_pos?)
Get X.509 extension matching the given NID to certificate, returns a
resty.openssl.x509.extension instance and the found position.
If last_pos is defined, the function searchs from that position; otherwise it
finds from beginning. Index is 1-based.
local ext, pos, err = x509:get_extension("keyUsage")syntax: ok, err = x509:add_extension(extension)
Adds an X.509 extension to certificate, the first argument must be a
resty.openssl.x509.extension instance.
local extension, err = require("resty.openssl.extension").new({
"keyUsage", "critical,keyCertSign,cRLSign",
})
local x509, err = require("resty.openssl.x509").new()
local ok, err = x509:add_extension(extension)syntax: ok, err = x509:set_extension(extension, last_pos?)
Adds an X.509 extension to certificate, the first argument must be a
resty.openssl.x509.extension instance.
The difference from x509:add_extension is that
in this function if a extension with same type already exists,
the old extension will be replaced.
If last_pos is defined, the function replaces the same extension from that position;
otherwise it finds from beginning. Index is 1-based. Returns nil, nil if not found.
Note this function is not thread-safe.
syntax: ok, err = x509:get_extension_critical(nid_or_txt)
Get critical flag of the X.509 extension matching the given NID from certificate.
syntax: ok, err = x509:set_extension_critical(nid_or_txt, crit?)
Set critical flag of the X.509 extension matching the given NID to certificate.
syntax: url_or_urls, err = x509:get_ocsp_url(return_all?)
Get OCSP URL(s) of the X.509 object. If return_all is set to true, returns a table
containing all OCSP URLs; otherwise returns a string with first OCSP URL found.
Returns nil if the extension is not found.
syntax: url_or_urls, err = x509:get_crl_url(return_all?)
Get CRL URL(s) of the X.509 object. If return_all is set to true, returns a table
containing all CRL URLs; otherwise returns a string with first CRL URL found.
Returns nil if the extension is not found.
syntax: ok, err = x509:sign(pkey, digest?)
Sign the certificate using the private key specified by pkey, which must be a
resty.openssl.pkey that stores private key. Optionally accept digest
parameter to set digest method, whichmust be a resty.openssl.digest instance.
Returns a boolean indicating if signing is successful and error if any.
syntax: ok, err = x509:verify(pkey)
Verify the certificate signature using the public key specified by pkey, which
must be a resty.openssl.pkey. Returns a boolean indicating if
verification is successful and error if any.
syntax: str, err = x509:tostring(fmt?)
Outputs certificate in PEM-formatted text or DER-formatted binary.
The first argument can be a choice of PEM or DER; when omitted, this function outputs PEM by default.
syntax: pem, err = x509:to_PEM()
Outputs the certificate in PEM-formatted text.
Module to interact with certificate signing request (X509_REQ).
See examples/csr.lua for an example to generate CSR.
syntax: csr, err = csr.new(txt?, fmt?)
Create an empty csr instance. txt can be PEM or DER formatted text;
fmt is a choice of PEM, DER to load specific format, or * for auto detect.
When txt is omitted, new() creates an empty csr instance.
syntax: ok = csr.istype(table)
Returns true if table is an instance of csr. Returns false otherwise.
syntax: ok, err = csr:set_attribute(instance)
syntax: instance, err = csr:get_attribute()
Setters and getters for x509 attributes share the same syntax.
| Attribute name | Type | Description |
|---|---|---|
| pubkey | pkey | Public key of the certificate request |
| subject_name | x509.name | Subject of the certificate request |
| version | number | Version of the certificate request, value is one less than version. For example, 2 represents version 3 |
Additionally, getters and setters for extensions are also available:
| Extension name | Type | Description |
|---|---|---|
| subject_alt_name | x509.altname | Subject Alternative Name of the certificate request, SANs are usually used to define "additional Common Names" |
If the attribute is not found, getter will return nil, nil.
local csr, err = require("resty.openssl.csr").new()
err = csr:set_version(3)
local version, err = csr:get_version()
ngx.say(version)
-- outputs 3Setters and getters for x509 attributes share the same syntax.
Same as csr:set_subject_alt_name, this function is deprecated to align with naming convension with other functions.
syntax: ok, err = csr:sign(pkey, digest?)
Sign the certificate request using the private key specified by pkey, which must be a
resty.openssl.pkey that stores private key. Optionally accept digest
parameter to set digest method, whichmust be a resty.openssl.digest instance.
Returns a boolean indicating if signing is successful and error if any.
syntax: ok, err = csr:verify(pkey)
Verify the CSR signature using the public key specified by pkey, which
must be a resty.openssl.pkey. Returns a boolean indicating if
verification is successful and error if any.
syntax: str, err = csr:tostring(fmt?)
Outputs certificate request in PEM-formatted text or DER-formatted binary.
The first argument can be a choice of PEM or DER; when omitted, this function outputs PEM by default.
syntax: pem, err = csr:to_PEM(?)
Outputs CSR in PEM-formatted text.
Module to interact with X509_CRL(certificate revocation list).
syntax: crt, err = crl.new(txt?, fmt?)
Creates a crl instance. txt can be PEM or DER formatted text;
fmt is a choice of PEM, DER to load specific format, or * for auto detect.
When txt is omitted, new() creates an empty crl instance.
syntax: crl, err = crl.dup(crl_ptr_cdata)
Duplicates a X509_CRL* to create a new crl instance.
syntax: ok = crl.istype(table)
Returns true if table is an instance of crl. Returns false otherwise.
syntax: ok, err = crl:set_attribute(instance)
syntax: instance, err = crl:get_attribute()
Setters and getters for crl attributes share the same syntax.
| Attribute name | Type | Description |
|---|---|---|
| issuer_name | x509.name | Issuer of the CRL |
| last_update | number | Unix timestamp when CRL is not valid before |
| next_update | number | Unix timestamp when CRL is not valid after |
| version | number | Version of the certificate, value is one less than version. For example, 2 represents version 3 |
Additionally, getters and setters for extensions are also available:
| Extension name | Type | Description |
|---|
For all extensions, get_{extension}_critical and set_{extension}_critical is also supported to
access the critical flag of the extension.
If the attribute is not found, getter will return nil, nil.
local crl, err = require("resty.openssl.crl").new()
err = crl:set_next_update(ngx.time())
local not_before, err = crl:get_next_update()
ngx.say(not_before)
-- outputs 1571875065Note that user may also access the certain extension by crl:get_extension and
crl:set_extension, while the later two function returns or requires
extension instead. User may use getter and setters listed here if modification
of current extensions is needed; use crl:get_extension or
crl:set_extension if user are adding or replacing the whole extension or
getters/setters are not implemented. If the getter returned a type of crl.* instance, it can be
converted to a extension instance by extension:from_data,
and thus used by crl:get_extension and crl:set_extension
syntax: extension, pos, err = crl:get_extension(nid_or_txt, last_pos?)
Get X.509 extension matching the given NID to CRL, returns a
resty.openssl.x509.extension instance and the found position.
If last_pos is defined, the function searchs from that position; otherwise it
finds from beginning. Index is 1-based.
syntax: ok, err = crl:add_extension(extension)
Adds an X.509 extension to CRL, the first argument must be a
resty.openssl.x509.extension instance.
syntax: ok, err = crl:set_extension(extension, last_pos?)
Adds an X.509 extension to CRL, the first argument must be a
resty.openssl.x509.extension instance.
The difference from crl:add_extension is that
in this function if a extension with same type already exists,
the old extension will be replaced.
If last_pos is defined, the function replaces the same extension from that position;
otherwise it finds from beginning. Index is 1-based. Returns nil, nil if not found.
Note this function is not thread-safe.
syntax: ok, err = crl:get_extension_critical(nid_or_txt)
Get critical flag of the X.509 extension matching the given NID from CRL.
syntax: ok, err = crl:set_extension_critical(nid_or_txt, crit?)
Set critical flag of the X.509 extension matching the given NID to CRL.
syntax: ok, err = crl:sign(pkey, digest?)
Sign the CRL using the private key specified by pkey, which must be a
resty.openssl.pkey that stores private key. Optionally accept digest
parameter to set digest method, whichmust be a resty.openssl.digest instance.
Returns a boolean indicating if signing is successful and error if any.
syntax: ok, err = crl:verify(pkey)
Verify the CRL signature using the public key specified by pkey, which
must be a resty.openssl.pkey. Returns a boolean indicating if
verification is successful and error if any.
syntax: str, err = crl:tostring(fmt?)
Outputs CRL in PEM-formatted text or DER-formatted binary.
The first argument can be a choice of PEM or DER; when omitted, this function outputs PEM by default.
syntax: pem, err = crl:to_PEM()
Outputs the CRL in PEM-formatted text.
Module to interact with X.509 names.
syntax: name, err = name.new()
Creates an empty name instance.
syntax: name, err = name.dup(name_ptr_cdata)
Duplicates a X509_NAME* to create a new name instance.
syntax: ok = name.istype(table)
Returns true if table is an instance of name. Returns false otherwise.
syntax: name, err = name:add(nid_text, txt)
Adds an ASN.1 object to name. First arguments in the text representation of NID.
Second argument is the plain text value for the ASN.1 object.
Returns the name instance itself on success, or nil and an error on failure.
This function can be called multiple times in a chained fashion.
local name, err = require("resty.openssl.x509.name").new()
local _, err = name:add("CN", "example.com")
_, err = name
:add("C", "US")
:add("ST", "California")
:add("L", "San Francisco")
syntax: obj, pos, err = name:find(nid_text, last_pos?)
Finds the ASN.1 object with the given text representation of NID from the
postition of last_pos. By omitting the last_pos parameter, find finds from the beginning.
Returns the object in a table as same format as decribed here, the position
of the found object and error if any. Index is 1-based. Returns nil, nil if not found.
local name, err = require("resty.openssl.x509.name").new()
local _, err = name:add("CN", "example.com")
:add("CN", "example2.com")
local obj, pos, err = name:find("CN")
ngx.say(obj.blob, " at ", pos)
-- outputs "example.com at 1"
local obj, pos, err = name:find("2.5.4.3", 1)
ngx.say(obj.blob, " at ", pos)
-- outputs "example2.com at 2"syntax: for k, obj in pairs(name)
syntax: len = #name
syntax: k, v = name[i]
Access the underlying objects as it's a Lua table. Make sure your LuaJIT compiled
with -DLUAJIT_ENABLE_LUA52COMPAT flag; otherwise use all, each, index and count
instead.
See also functions for stack-like objects.
Each returned object is a table where:
{
id: OID of the object,
nid: NID of the object,
sn: short name of the object,
ln: long name of the object,
blob: value of the object,
}
local name, err = require("resty.openssl.x509.name").new()
local _, err = name:add("CN", "example.com")
for k, obj in pairs(name) do
ngx.say(k, ":", require("cjson").encode(obj))
end
-- outputs 'CN: {"sn":"CN","id":"2.5.4.3","nid":13,"blob":"3.example.com","ln":"commonName"}'Module to interact with GENERAL_NAMES, an extension to X.509 names.
syntax: altname, err = altname.new()
Creates an empty altname instance.
syntax: altname = digest.istype(table)
Returns true if table is an instance of altname. Returns false otherwise.
syntax: altname, err = altname:add(key, value)
Adds a name to altname stack, first argument is case-insensitive and can be one of
RFC822Name
RFC822
Email
UniformResourceIdentifier
URI
DNSName
DNS
IPAddress
IP
DirName
This function can be called multiple times in a chained fashion.
local altname, err = require("resty.openssl.x509").new()
local _, err = altname:add("DNS", "example.com")
_, err = altname
:add("DNS", "2.example.com")
:add("DnS", "3.example.com")syntax: for k, obj in pairs(altname)
syntax: len = #altname
syntax: k, v = altname[i]
Access the underlying objects as it's a Lua table. Make sure your LuaJIT compiled
with -DLUAJIT_ENABLE_LUA52COMPAT flag; otherwise use all, each, index and count
instead.
See also functions for stack-like objects.
Module to interact with X.509 extensions.
syntax: ext, err = extension.new(name, value, data?)
Creates a new extension instance. name and value are strings in OpenSSL
arbitrary extension format.
data can be a table or nil. Where data is a table, the following key will be looked up:
data = {
issuer = resty.openssl.x509 instance,
subject = resty.openssl.x509 instance,
request = resty.openssl.x509.csr instance,
crl = resty.openssl.x509.crl instance,
}Example:
local x509, err = require("resty.openssl.x509").new()
local extension = require("resty.openssl.x509.extension")
local ext, err = extension.new("extendedKeyUsage", "serverAuth,clientAuth")
ext, err = extension.new("subjectKeyIdentifier", "hash", {
subject = crt
})See examples/tls-alpn-01.lua for an example to create extension with an unknown nid.
syntax: ext, err = extension.dup(extension_ptr_cdata)
Creates a new extension instance from X509_EXTENSION* pointer.
syntax: ext, ok = extension.from_data(table, nid, crit?)
Creates a new extension instance. table can be instance of:
nid is a number of NID and crit is the critical flag of the extension.
syntax: ok = extension.istype(table)
Returns true if table is an instance of extension. Returns false otherwise.
syntax: crit, err = extension:get_extension_critical()
Returns true if extension is critical. Returns false otherwise.
syntax: ok, err = extension:set_extension_critical(crit)
Set the critical flag of the extension.
syntax: obj = extension:get_object()
Returns the name of extension as ASN.1 Object. User can further use helper functions in resty.openssl.objects to print human readable texts.
syntax: txt, err = extension:text()
Returns the text representation of extension
local objects = require "resty.openssl.objects"
ngx.say(cjson.encode(objects.obj2table(extension:get_object())))
-- outputs {"ln":"X509v3 Subject Key Identifier","nid":82,"sn":"subjectKeyIdentifier","id":"2.5.29.14"}
ngx.say(extension:text())
-- outputs C9:C2:53:61:66:9D:5F:AB:25:F4:26:CD:0F:38:9A:A8:49:EA:48:A9syntax: txt, err = extension:tostring()
Same as extension:text.
Module to interact with CRL Distribution Points(DIST_POINT stack).
syntax: dp, err = dist_points.new()
Creates a new dist_points instance.
syntax: dp, err = dist_points.dup(dist_points_ptr_cdata)
Duplicates a STACK_OF(DIST_POINT) to create a new dist_points instance. The function creates a new
stack and increases reference count for all elements by 1. But it won't duplicate the elements
themselves.
syntax: ok = dist_points.istype(table)
Returns true if table is an instance of dist_points. Returns false otherwise.
syntax: for i, obj in ipairs(dist_points)
syntax: len = #dist_points
syntax: obj = dist_points[i]
Access the underlying objects as it's a Lua table. Make sure your LuaJIT compiled
with -DLUAJIT_ENABLE_LUA52COMPAT flag; otherwise use all, each, index and count
instead.
See also functions for stack-like objects.
Module to interact with Authority Information Access data (AUTHORITY_INFO_ACCESS, ACCESS_DESCRIPTION stack).
syntax: aia, err = info_access.new()
Creates a new info_access instance.
syntax: aia, err = info_access.dup(info_access_ptr_cdata)
Duplicates a AUTHORITY_INFO_ACCESS to create a new info_access instance. The function creates a new
stack and increases reference count for all elements by 1. But it won't duplicate the elements
themselves.
syntax: ok = info_access.istype(table)
Returns true if table is an instance of info_access. Returns false otherwise.
syntax: ok, err = info_access:add(x509)
Add a x509 object to the info_access. The first argument must be a
resty.openssl.x509 instance.
syntax: for i, obj in ipairs(info_access)
syntax: len = #info_access
syntax: obj = info_access[i]
Access the underlying objects as it's a Lua table. Make sure your LuaJIT compiled
with -DLUAJIT_ENABLE_LUA52COMPAT flag; otherwise use all, each, index and count
instead.
See also functions for stack-like objects.
Module to interact with X.509 stack.
syntax: ch, err = chain.new()
Creates a new chain instance.
syntax: ch, err = chain.dup(chain_ptr_cdata)
Duplicates a STACK_OF(X509) to create a new chain instance. The function creates a new
stack and increases reference count for all elements by 1. But it won't duplicate the elements
themselves.
syntax: ok = chain.istype(table)
Returns true if table is an instance of chain. Returns false otherwise.
syntax: ok, err = chain:add(x509)
Add a x509 object to the chain. The first argument must be a
resty.openssl.x509 instance.
syntax: for i, obj in ipairs(chain)
syntax: len = #chain
syntax: obj = chain[i]
Access the underlying objects as it's a Lua table. Make sure your LuaJIT compiled
with -DLUAJIT_ENABLE_LUA52COMPAT flag; otherwise use all, each, index and count
instead.
See also functions for stack-like objects.
Module to interact with X.509 certificate store (X509_STORE).
syntax: st, err = store.new()
Creates a new store instance.
syntax: ok = store.istype(table)
Returns true if table is an instance of store. Returns false otherwise.
syntax: ok, err = store:use_default()
Loads certificates into the X509_STORE from the hardcoded default paths.
Note that to load "default" CAs correctly, usually you need to install a CA
certificates bundle. For example, the package in Debian/Ubuntu is called ca-certificates.
syntax: ok, err = store:add(x509_or_crl)
Adds a X.509 or a CRL object into store. The argument must be a resty.openssl.x509 instance or a resty.openssl.x509.store instance.
syntax: ok, err = store:load_file(path)
Loads a X.509 certificate on file system into store.
syntax: ok, err = store:load_directory(path)
Loads a directory of X.509 certificates on file system into store. The certificates in the directory must be in hashed form, as documented in X509_LOOKUP_hash_dir(3).
syntax: chain, err = store:verify(x509, chain?, return_chain?)
Verifies a X.509 object with the store. The first argument must be resty.openssl.x509 instance. Optionally accept a validation chain as second argument, which must be a resty.openssl.x509.chain instance.
If verification succeed, and return_chain is set to true, returns the proof of validation as a
resty.openssl.x509.chain; otherwise
returns true only. If verification failed, returns nil and error explaining the reason.
syntax: for k, obj in pairs(x)
syntax: for k, obj in ipairs(x)
syntax: len = #x
syntax: obj = x[i]
Access the underlying objects as it's a Lua table. Make sure your LuaJIT compiled
with -DLUAJIT_ENABLE_LUA52COMPAT flag.
Each object may only support either pairs or ipairs. Index is 1-based.
local name, err = require("resty.openssl.x509.name").new()
local _, err = name:add("CN", "example.com")
for k, obj in pairs(name) do
ngx.say(k, ":", require("cjson").encode(obj))
end
-- outputs 'CN: {"sn":"CN","id":"2.5.4.3","nid":13,"blob":"3.example.com","ln":"commonName"}'syntax: iter = x:each()
Return an iterator to traverse objects. Use this while LUAJIT_ENABLE_LUA52COMPAT is not enabled.
local name, err = require("resty.openssl.x509.name").new()
local _, err = name:add("CN", "example.com")
local iter = name:each()
while true do
local k, obj = iter()
if not k then
break
end
endsyntax: objs, err = x:all()
Returns all objects in the table. Use this while LUAJIT_ENABLE_LUA52COMPAT is not enabled.
syntax: len = x:count()
Returns count of objects of the table. Use this while LUAJIT_ENABLE_LUA52COMPAT is not enabled.
syntax: obj = x:index(i)
Returns objects at index of i of the table, index is 1-based. If index is out of bound, nil is returned.
- When a type is added or returned to another type, it's internal cdata is always copied.
local name = require("resty.openssl.x509.name"):add("CN", "example.com")
local x509 = require("resty.openssl.x509").new()
-- `name` is copied when added to x509
x509:set_subject_name(name)
name:add("L", "Mars")
-- subject_name in x509 will not be modified- The creator set the GC handler; the user must not free it.
- For a stack:
- If it's created by
new(): set GC handler to sk_TYPE_pop_free- The gc handler for elements being added to stack should not be set. Instead, rely on the gc handler of the stack to free each individual elements.
- If it's created by
dup()(shallow copy):- If elements support reference counter (like X509): increase ref count for all elements by 1; set GC handler to sk_TYPE_pop_free.
- If not, set GC handler to sk_free
- Additionally, the stack duplicates the element when it's added to stack, a GC handler for the duplicate must be set. But a reference should be kept in Lua land to prevent premature gc of individual elements. (See x509.altname)
- If it's created by
Although only a small combinations of CPU arch and OpenSSL version are tested, the library should function well as long as the linked OpenSSL library is API compatible. This means the same name of functions are exported with same argument types.
For OpenSSL 1.0.2 series however, binary/ABI compatibility must be ensured as some struct members are accessed directly. They are accessed by memory offset in assembly.
OpenSSL keeps ABI/binary compatibility with minor releases or letter releases. So all structs offsets and macro constants are kept same.
If you plan to use this library on an untested version of OpenSSL (like custom builds or pre releases), this can be a good source to consult.
This module is licensed under the BSD license.
Copyright (C) 2019-2020, by fffonion [email protected].
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.