From be5dc10c24aabb6697ecb9fe2bd75c8a11e2b2d7 Mon Sep 17 00:00:00 2001 From: Wangchong Zhou Date: Thu, 14 May 2020 06:13:54 +0800 Subject: [PATCH] feat(*) initial support for OpenSSL 3.0 --- .travis.yml | 10 +++-- examples/aes-gcm-aead.lua | 23 ++++------- lib/resty/openssl/aux/jwk.lua | 7 +++- lib/resty/openssl/cipher.lua | 12 ++++-- lib/resty/openssl/digest.lua | 4 +- lib/resty/openssl/ecx.lua | 16 +++---- lib/resty/openssl/hmac.lua | 8 ++-- lib/resty/openssl/include/asn1.lua | 4 +- lib/resty/openssl/include/crypto.lua | 4 +- lib/resty/openssl/include/evp.lua | 18 ++++++-- lib/resty/openssl/include/hmac.lua | 4 +- lib/resty/openssl/include/rsa.lua | 4 +- lib/resty/openssl/include/stack.lua | 4 +- lib/resty/openssl/include/x509/crl.lua | 4 +- lib/resty/openssl/include/x509/csr.lua | 4 +- lib/resty/openssl/include/x509/init.lua | 4 +- lib/resty/openssl/include/x509_vfy.lua | 4 +- lib/resty/openssl/kdf.lua | 6 ++- lib/resty/openssl/pkey.lua | 55 +++++++++++++++++-------- lib/resty/openssl/rsa.lua | 24 +++++------ lib/resty/openssl/version.lua | 4 +- lib/resty/openssl/x509/crl.lua | 6 +-- lib/resty/openssl/x509/csr.lua | 4 +- lib/resty/openssl/x509/init.lua | 8 ++-- scripts/templates/x509_functions.j2 | 2 +- t/openssl.t | 2 +- t/openssl/cipher.t | 4 +- t/openssl/helper.lua | 2 +- t/openssl/pkey.t | 16 +++---- t/openssl/version.t | 4 +- 30 files changed, 158 insertions(+), 113 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6a0f2b7..30ebc1a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: required -dist: trusty +dist: bionic os: linux @@ -33,6 +33,8 @@ env: - NGINX_VERSION=1.15.8 OPENSSL_VER=1.0.2u - NGINX_VERSION=1.15.8 OPENSSL_VER=1.1.0l - NGINX_VERSION=1.15.8 OPENSSL_VER=1.1.1g + # add -Wno-error to fix deprecation warnings from openssl + - NGINX_VERSION=1.15.8 OPENSSL_HASH=90ad284f4e76254f8d67686ae3a5d6c576037091 NGINX_CC_OPTS=-Wno-error install: - export NGX_BUILD_CC=$CC @@ -53,8 +55,8 @@ install: - git clone https://github.com/openresty/lua-resty-string ../lua-resty-string # openssl # openssl 1.0.2 config doesn't work correctly on a cached directory - - wget https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz -O - | tar zxf - - - pushd openssl-$OPENSSL_VER/ + - if [ "X$OPENSSL_HASH" != "X" ]; then wget https://github.com/openssl/openssl/archive/$OPENSSL_HASH.tar.gz -O - | tar zxf - ; pushd openssl-$OPENSSL_HASH/; fi + - if [ "X$OPENSSL_HASH" = "X" ] ; then wget https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz -O - | tar zxf -; pushd openssl-$OPENSSL_VER/; fi - if [ ! -e $OPENSSL_PREFIX/include ]; then ./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); fi - if [ ! -e $OPENSSL_PREFIX/include ]; then make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); fi - if [ ! -e $OPENSSL_PREFIX/include ]; then sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); fi @@ -71,7 +73,7 @@ install: - if [ ! -e lua-cjson ]; then git clone https://github.com/openresty/lua-cjson.git ./lua-cjson; fi - pushd ./lua-cjson && make && sudo PATH=$PATH make install && popd # nginx - - if [ ! -e work ]; then ngx-build $NGINX_VERSION --add-module=../ndk-nginx-module --add-module=../lua-nginx-module --with-http_ssl_module --with-cc-opt="-I$OPENSSL_INC" --with-ld-opt="-L$OPENSSL_LIB -Wl,-rpath,$OPENSSL_LIB" --with-debug > build.log 2>&1 || (cat build.log && exit 1); fi + - if [ ! -e work ]; then ngx-build $NGINX_VERSION --add-module=../ndk-nginx-module --add-module=../lua-nginx-module --with-http_ssl_module --with-cc-opt="-I$OPENSSL_INC $NGINX_CC_OPTS" --with-ld-opt="-L$OPENSSL_LIB -Wl,-rpath,$OPENSSL_LIB" --with-debug > build.log 2>&1 || (cat build.log && exit 1); fi - nginx -V - ldd `which nginx`|grep -E 'luajit|ssl|pcre' - popd diff --git a/examples/aes-gcm-aead.lua b/examples/aes-gcm-aead.lua index 94d6b2f4..a8ff3fb5 100644 --- a/examples/aes-gcm-aead.lua +++ b/examples/aes-gcm-aead.lua @@ -1,7 +1,3 @@ -local function new_cipher() - return assert(require("resty.openssl.cipher").new("aes-256-gcm")) -end - local key = string.rep("0", 32) local iv = string.rep("0", 12) @@ -10,10 +6,9 @@ local to_be_encrypted = "secret" local aad = "aead aad" -- using one shot interface -local cipher = new_cipher() +local cipher = assert(require("resty.openssl.cipher").new("aes-256-gcm")) local encrypted = assert(cipher:encrypt(key, iv, to_be_encrypted, false, aad)) -- OR using streaming interface -local cipher = new_cipher() assert(cipher:init(key, iv, { is_encrypt = true, })) @@ -26,27 +21,25 @@ local tag = assert(cipher:get_aead_tag()) ngx.say("tag is: ", ngx.encode_base64(tag)) -local ok, _ = new_cipher():decrypt(key, iv, encrypted, false, nil, tag) +local ok, _ = cipher:decrypt(key, iv, encrypted, false, nil, tag) if not ok then ngx.say("no AAD, decryption failed") end -local ok, _ = new_cipher():decrypt(key, iv, encrypted, false, aad, nil) +local ok, _ = cipher:decrypt(key, iv, encrypted, false, aad, nil) if not ok then ngx.say("no tag, decryption failed") end -- using one shot interface -local cipher2 = new_cipher() -local decrypted = assert(cipher2:decrypt(key, iv, encrypted, false, aad, tag)) +local decrypted = assert(cipher:decrypt(key, iv, encrypted, false, aad, tag)) -- OR using streaming interface -local cipher2 = new_cipher() -assert(cipher2:init(key, iv, { +assert(cipher:init(key, iv, { is_encrypt = false, })) -assert(cipher2:update_aead_aad(aad)) -assert(cipher2:set_aead_tag(tag)) -decrypted = assert(cipher2:final(encrypted)) +assert(cipher:update_aead_aad(aad)) +assert(cipher:set_aead_tag(tag)) +decrypted = assert(cipher:final(encrypted)) ngx.say("decryption result: ", decrypted) diff --git a/lib/resty/openssl/aux/jwk.lua b/lib/resty/openssl/aux/jwk.lua index 72d98404..a65b8aeb 100644 --- a/lib/resty/openssl/aux/jwk.lua +++ b/lib/resty/openssl/aux/jwk.lua @@ -11,6 +11,7 @@ local ec_lib = require "resty.openssl.ec" local ecx_lib = require "resty.openssl.ecx" local bn_lib = require "resty.openssl.bn" local digest_lib = require "resty.openssl.digest" +local OPENSSL_30 = require("resty.openssl.version").OPENSSL_30 local _M = {} @@ -174,7 +175,11 @@ function _M.load_jwk(txt) end key, err = load_jwk_okp(key_type, tbl) if key ~= nil then - return key + if OPENSSL_30 then + return { key, key_type } + else + return key + end end else return nil, "not yet supported jwk type \"" .. (tbl["kty"] or "nil") .. "\"" diff --git a/lib/resty/openssl/cipher.lua b/lib/resty/openssl/cipher.lua index 4ca58912..26631433 100644 --- a/lib/resty/openssl/cipher.lua +++ b/lib/resty/openssl/cipher.lua @@ -9,7 +9,7 @@ local evp_macro = require "resty.openssl.include.evp" local ctypes = require "resty.openssl.aux.ctypes" local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local uchar_array = ctypes.uchar_array local void_ptr = ctypes.void_ptr @@ -26,7 +26,7 @@ function _M.new(typ) end local ctx - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ctx = C.EVP_CIPHER_CTX_new() ffi_gc(ctx, C.EVP_CIPHER_CTX_free) elseif OPENSSL_10 then @@ -50,6 +50,7 @@ function _M.new(typ) return setmetatable({ ctx = ctx, + cipher_type = dtyp, initialized = false, block_size = tonumber(C.EVP_CIPHER_CTX_block_size(ctx)), key_size = tonumber(C.EVP_CIPHER_CTX_key_length(ctx)), @@ -70,8 +71,11 @@ function _M:init(key, iv, opts) return false, string.format("cipher:init: incorrect iv size, expect %d", self.iv_size) end - if C.EVP_CipherInit_ex(self.ctx, nil, nil, key, iv, opts.is_encrypt and 1 or 0) == 0 then - return false, format_error("cipher:init") + -- always passed in the `EVP_CIPHER` parameter to reinitialized the cipher + -- it will have a same effect as EVP_CIPHER_CTX_cleanup/EVP_CIPHER_CTX_reset then Init_ex with + -- empty cipher_type + if C.EVP_CipherInit_ex(self.ctx, self.cipher_type, nil, key, iv, opts.is_encrypt and 1 or 0) == 0 then + return false, format_error("cipher:init EVP_CipherInit_ex") end if opts.no_padding then diff --git a/lib/resty/openssl/digest.lua b/lib/resty/openssl/digest.lua index 2658bf42..ebe7a953 100644 --- a/lib/resty/openssl/digest.lua +++ b/lib/resty/openssl/digest.lua @@ -7,7 +7,7 @@ local ffi_str = ffi.string require "resty.openssl.include.evp" local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local _M = {} local mt = {__index = _M} @@ -16,7 +16,7 @@ local md_ctx_ptr_ct = ffi.typeof('EVP_MD_CTX*') function _M.new(typ) local ctx - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ctx = C.EVP_MD_CTX_new() ffi_gc(ctx, C.EVP_MD_CTX_free) elseif OPENSSL_10 then diff --git a/lib/resty/openssl/ecx.lua b/lib/resty/openssl/ecx.lua index b6c7cd44..759519ec 100644 --- a/lib/resty/openssl/ecx.lua +++ b/lib/resty/openssl/ecx.lua @@ -5,6 +5,7 @@ local ffi_str = ffi.string require "resty.openssl.include.ec" require "resty.openssl.include.evp" +local ctypes = require "resty.openssl.aux.ctypes" local format_error = require("resty.openssl.err").format_error local _M = {} @@ -17,23 +18,22 @@ local MAX_ECX_KEY_SIZE = 114 -- ed448 uses 114 bytes function _M.get_parameters(evp_pkey_st) return setmetatable(empty_table, { __index = function(_, k) - local buf = ffi_new('unsigned char[?]', MAX_ECX_KEY_SIZE) - local size_t_ptr = ffi_new("size_t[1]") - size_t_ptr[0] = MAX_ECX_KEY_SIZE + local buf = ffi_new(ctypes.uchar_array, MAX_ECX_KEY_SIZE) + local length = ffi_new(ctypes.ptr_of_size_t) + length[0] = MAX_ECX_KEY_SIZE if k == 'public' or k == "pub_key" then - if C.EVP_PKEY_get_raw_public_key(evp_pkey_st, buf, size_t_ptr) ~= 1 then - return nil, format_error("ecx.get_parameters: EVP_PKEY_get_raw_private_key") + if C.EVP_PKEY_get_raw_public_key(evp_pkey_st, buf, length) ~= 1 then + error(format_error("ecx.get_parameters: EVP_PKEY_get_raw_private_key")) end elseif k == 'private' or k == "priv ~=_key" then - if C.EVP_PKEY_get_raw_private_key(evp_pkey_st, buf, size_t_ptr) ~= 1 then + if C.EVP_PKEY_get_raw_private_key(evp_pkey_st, buf, length) ~= 1 then return nil, format_error("ecx.get_parameters: EVP_PKEY_get_raw_private_key") end else return nil, "ecx.get_parameters: unknown parameter \"" .. k .. "\" for EC key" end - - return ffi_str(buf, size_t_ptr[0]) + return ffi_str(buf, length[0]) end }), nil end diff --git a/lib/resty/openssl/hmac.lua b/lib/resty/openssl/hmac.lua index d3415304..18fe510f 100644 --- a/lib/resty/openssl/hmac.lua +++ b/lib/resty/openssl/hmac.lua @@ -5,19 +5,21 @@ local ffi_new = ffi.new local ffi_str = ffi.string require "resty.openssl.include.hmac" -local evp_macro = require "resty.openssl.include.evp" local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local _M = {} local mt = {__index = _M} local hmac_ctx_ptr_ct = ffi.typeof('HMAC_CTX*') +-- Note: https://www.openssl.org/docs/manmaster/man3/HMAC_Init.html +-- Replace with EVP_MAC_* functions for OpenSSL 3.0 + function _M.new(key, typ) local ctx - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ctx = C.HMAC_CTX_new() ffi_gc(ctx, C.HMAC_CTX_free) elseif OPENSSL_10 then diff --git a/lib/resty/openssl/include/asn1.lua b/lib/resty/openssl/include/asn1.lua index 1cb34773..4c7cf99c 100644 --- a/lib/resty/openssl/include/asn1.lua +++ b/lib/resty/openssl/include/asn1.lua @@ -43,10 +43,10 @@ declare_asn1_functions("ASN1_OBJECT") declare_asn1_functions("ASN1_STRING") local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local ASN1_STRING_get0_data -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef[[ const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x); ]] diff --git a/lib/resty/openssl/include/crypto.lua b/lib/resty/openssl/include/crypto.lua index e832495e..e16e3af1 100644 --- a/lib/resty/openssl/include/crypto.lua +++ b/lib/resty/openssl/include/crypto.lua @@ -2,7 +2,7 @@ local ffi = require "ffi" local C = ffi.C local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local OPENSSL_free if OPENSSL_10 then @@ -10,7 +10,7 @@ if OPENSSL_10 then void CRYPTO_free(void *ptr); ]] OPENSSL_free = C.CRYPTO_free -elseif OPENSSL_11 then +elseif OPENSSL_11_OR_LATER then ffi.cdef [[ void CRYPTO_free(void *ptr, const char *file, int line); ]] diff --git a/lib/resty/openssl/include/evp.lua b/lib/resty/openssl/include/evp.lua index 6c69d769..202cea7d 100644 --- a/lib/resty/openssl/include/evp.lua +++ b/lib/resty/openssl/include/evp.lua @@ -4,7 +4,8 @@ local bit = require("bit") require "resty.openssl.include.ossl_typ" require "resty.openssl.include.objects" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER +local OPENSSL_30 = require("resty.openssl.version").OPENSSL_30 ffi.cdef [[ EVP_PKEY *EVP_PKEY_new(void); @@ -82,6 +83,11 @@ ffi.cdef [[ /*__owur*/ int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); + // openssl 1.0.2 + int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a); + // openssl >= 1.1.0 + int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx); + int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); @@ -118,7 +124,13 @@ ffi.cdef [[ int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); ]] -if OPENSSL_11 then +if OPENSSL_30 then + ffi.cdef [[ + int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad_mode); + ]] +end + +if OPENSSL_11_OR_LATER then ffi.cdef [[ EVP_MD_CTX *EVP_MD_CTX_new(void); void EVP_MD_CTX_free(EVP_MD_CTX *ctx); @@ -215,7 +227,7 @@ local _M = { EVP_PKEY_X448 = ffi.C.OBJ_txt2nid("X448"), EVP_PKEY_ED448 = ffi.C.OBJ_txt2nid("ED448"), - EVP_PKEY_OP_DERIVE = bit.lshift(1, 10), + EVP_PKEY_OP_DERIVE = OPENSSL_30 and bit.lshift(1, 12) or bit.lshift(1, 10), EVP_PKEY_ALG_CTRL = 0x1000, EVP_PKEY_CTRL_RSA_PADDING = 0x1000 + 1, diff --git a/lib/resty/openssl/include/hmac.lua b/lib/resty/openssl/include/hmac.lua index 18af8534..0a789349 100644 --- a/lib/resty/openssl/include/hmac.lua +++ b/lib/resty/openssl/include/hmac.lua @@ -3,7 +3,7 @@ local ffi = require "ffi" require "resty.openssl.include.ossl_typ" require "resty.openssl.include.evp" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER ffi.cdef [[ /*__owur*/ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, @@ -14,7 +14,7 @@ ffi.cdef [[ unsigned int *len); ]] -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef [[ HMAC_CTX *HMAC_CTX_new(void); void HMAC_CTX_free(HMAC_CTX *ctx); diff --git a/lib/resty/openssl/include/rsa.lua b/lib/resty/openssl/include/rsa.lua index 4cd636b1..8e1b27a3 100644 --- a/lib/resty/openssl/include/rsa.lua +++ b/lib/resty/openssl/include/rsa.lua @@ -2,7 +2,7 @@ local ffi = require "ffi" require "resty.openssl.include.ossl_typ" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER ffi.cdef [[ RSA *RSA_new(void); @@ -10,7 +10,7 @@ ffi.cdef [[ int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); ]] -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef [[ void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d); diff --git a/lib/resty/openssl/include/stack.lua b/lib/resty/openssl/include/stack.lua index 7e371910..ad18f9a2 100644 --- a/lib/resty/openssl/include/stack.lua +++ b/lib/resty/openssl/include/stack.lua @@ -10,7 +10,7 @@ local C = ffi.C require "resty.openssl.include.ossl_typ" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local _M = {} @@ -18,7 +18,7 @@ ffi.cdef [[ typedef char *OPENSSL_STRING; ]] -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef [[ typedef struct stack_st OPENSSL_STACK; diff --git a/lib/resty/openssl/include/x509/crl.lua b/lib/resty/openssl/include/x509/crl.lua index bf3c36fa..c089dffe 100644 --- a/lib/resty/openssl/include/x509/crl.lua +++ b/lib/resty/openssl/include/x509/crl.lua @@ -9,7 +9,7 @@ require "resty.openssl.include.stack" local asn1_macro = require "resty.openssl.include.asn1" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER asn1_macro.declare_asn1_functions("X509_CRL") @@ -30,7 +30,7 @@ ffi.cdef [[ X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl); ]] -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef [[ int X509_CRL_set1_lastUpdate(X509_CRL *x, const ASN1_TIME *tm); int X509_CRL_set1_nextUpdate(X509_CRL *x, const ASN1_TIME *tm); diff --git a/lib/resty/openssl/include/x509/csr.lua b/lib/resty/openssl/include/x509/csr.lua index bd84359d..c4b512e8 100644 --- a/lib/resty/openssl/include/x509/csr.lua +++ b/lib/resty/openssl/include/x509/csr.lua @@ -9,7 +9,7 @@ require "resty.openssl.include.stack" local asn1_macro = require "resty.openssl.include.asn1" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER asn1_macro.declare_asn1_functions("X509_REQ") @@ -39,7 +39,7 @@ ffi.cdef [[ int X509_REQ_add_extensions(X509_REQ *req, OPENSSL_STACK *exts); ]] -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef [[ X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req); long X509_REQ_get_version(const X509_REQ *req); diff --git a/lib/resty/openssl/include/x509/init.lua b/lib/resty/openssl/include/x509/init.lua index e2adab76..c3457479 100644 --- a/lib/resty/openssl/include/x509/init.lua +++ b/lib/resty/openssl/include/x509/init.lua @@ -7,7 +7,7 @@ require "resty.openssl.include.stack" local asn1_macro = require "resty.openssl.include.asn1" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER asn1_macro.declare_asn1_functions("X509") @@ -62,7 +62,7 @@ ffi.cdef [[ int X509_verify_cert(X509_STORE_CTX *ctx); ]] -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then ffi.cdef [[ int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm); int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm); diff --git a/lib/resty/openssl/include/x509_vfy.lua b/lib/resty/openssl/include/x509_vfy.lua index 27fcf756..44ef7bdd 100644 --- a/lib/resty/openssl/include/x509_vfy.lua +++ b/lib/resty/openssl/include/x509_vfy.lua @@ -4,7 +4,7 @@ local C = ffi.C require "resty.openssl.include.ossl_typ" require "resty.openssl.include.stack" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER ffi.cdef [[ X509_STORE *X509_STORE_new(void); @@ -40,7 +40,7 @@ if OPENSSL_10 then OPENSSL_STACK *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx); ]]; _M.X509_STORE_CTX_get0_chain = C.X509_STORE_CTX_get_chain -elseif OPENSSL_11 then +elseif OPENSSL_11_OR_LATER then ffi.cdef [[ // STACK_OF(X509) OPENSSL_STACK *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx); diff --git a/lib/resty/openssl/kdf.lua b/lib/resty/openssl/kdf.lua index 798d6e53..a27a073c 100644 --- a/lib/resty/openssl/kdf.lua +++ b/lib/resty/openssl/kdf.lua @@ -158,9 +158,13 @@ function _M.derive(options) pass_len = 0 end -- https://www.openssl.org/docs/man1.1.0/man3/PKCS5_PBKDF2_HMAC.html + local iter = options.pbkdf2_iter + if iter < 1 then + iter = 1 + end code = C.PKCS5_PBKDF2_HMAC( options.pass, pass_len, - options.salt, salt_len, options.pbkdf2_iter, + options.salt, salt_len, iter, md, options.outlen, buf ) elseif typ == NID_id_scrypt then diff --git a/lib/resty/openssl/pkey.lua b/lib/resty/openssl/pkey.lua index 1d5e65d7..ae29c171 100644 --- a/lib/resty/openssl/pkey.lua +++ b/lib/resty/openssl/pkey.lua @@ -23,7 +23,8 @@ local ctypes = require "resty.openssl.aux.ctypes" local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER +local OPENSSL_30 = require("resty.openssl.version").OPENSSL_30 local ptr_of_uint = ctypes.ptr_of_uint local ptr_of_size_t = ctypes.ptr_of_size_t @@ -107,10 +108,15 @@ local function generate_key(config) return nil, format_error("EVP_PKEY_keygen_init") end local ctx_ptr = ffi_new("EVP_PKEY*[1]") + -- TODO: move to use EVP_PKEY_gen after drop support for <1.1.1 if C.EVP_PKEY_keygen(pctx, ctx_ptr) ~= 1 then - return nil, format_error("EVP_PKEY_keygen") + return nil, format_error("EVP_PKEY_gen") + end + if OPENSSL_30 then + return { ctx_ptr[0], key_type } + else + return ctx_ptr[0] end - return ctx_ptr[0] else return nil, "unsupported type " .. type end @@ -297,6 +303,7 @@ local evp_pkey_ptr_ct = ffi.typeof('EVP_PKEY*') function _M.new(s, opts) local ctx, err s = s or {} + local key_type if type(s) == 'table' then ctx, err = generate_key(s) if err then @@ -321,31 +328,38 @@ function _M.new(s, opts) return nil, err end - -- although OpenSSL discourages to use this size for digest/verify - -- but this - local sig_size = C.EVP_PKEY_size(ctx) - local key_type = C.EVP_PKEY_base_id(ctx) + -- OpenSSL 3.0 seems always return 0 when key is generated by EVP_PKEY_keygen + -- and EVP_PKEY_new_raw_*_key + if OPENSSL_30 and type(ctx) == "table" then + key_type = ctx[2] + ctx = ctx[1] + end + + ffi_gc(ctx, C.EVP_PKEY_free) + + key_type = key_type or C.EVP_PKEY_base_id(ctx) + if key_type == 0 then + return nil, "pkey.new: cannot get key_type" + end local key_type_is_ecx = (key_type == evp_macro.EVP_PKEY_ED25519) or (key_type == evp_macro.EVP_PKEY_X25519) or (key_type == evp_macro.EVP_PKEY_ED448) or (key_type == evp_macro.EVP_PKEY_X448) - if err then - return nil, err - end + -- although OpenSSL discourages to use this size for digest/verify + -- but this is good enough for now + local sig_size = C.EVP_PKEY_size(ctx) local self = setmetatable({ ctx = ctx, pkey_ctx = nil, rsa_padding = nil, - buf = ffi_new(ctypes.uchar_array, sig_size), key_type = key_type, - sig_size = sig_size, key_type_is_ecx = key_type_is_ecx, + buf = ffi_new(ctypes.uchar_array, sig_size), + sig_size = sig_size, }, mt) - ffi_gc(ctx, C.EVP_PKEY_free) - return self, nil end @@ -360,7 +374,7 @@ end local function get_pkey_key(self) if self.key_type == evp_macro.EVP_PKEY_RSA then local rsa_st - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then rsa_st = C.EVP_PKEY_get0_RSA(self.ctx) if rsa_st == nil then return nil, "pkey:get_pkey_key EVP_PKEY_get0_RSA() failed" @@ -371,7 +385,7 @@ local function get_pkey_key(self) return rsa_st elseif self.key_type == evp_macro.EVP_PKEY_EC then local ec_key_st - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ec_key_st = C.EVP_PKEY_get0_EC_KEY(self.ctx) if ec_key_st == nil then return nil, "pkey:get_pkey_key: EVP_PKEY_get0_EC_KEY() failed" @@ -382,7 +396,7 @@ local function get_pkey_key(self) return ec_key_st end - return nil, "pkey:get_pkey_key: key type not supported" + return nil, string.format("pkey:get_pkey_key: key type %d not supported", self.key_type) end function _M:get_parameters() @@ -468,9 +482,14 @@ local function asymmetric_routine(self, s, is_encrypt, padding) -- EVP_PKEY_CTX_ctrl must be called after *_init if self.key_type == evp_macro.EVP_PKEY_RSA and padding then - local code = C.EVP_PKEY_CTX_ctrl(pkey_ctx, evp_macro.EVP_PKEY_RSA, -1, + local code + if OPENSSL_30 then + code = C.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding) + else + code = C.EVP_PKEY_CTX_ctrl(pkey_ctx, evp_macro.EVP_PKEY_RSA, -1, evp_macro.EVP_PKEY_CTRL_RSA_PADDING, padding, nil) + end if code ~= 1 then return nil, format_error("pkey:asymmetric_routine EVP_PKEY_CTX_ctrl") end diff --git a/lib/resty/openssl/rsa.lua b/lib/resty/openssl/rsa.lua index 5d93e6da..b8cedec8 100644 --- a/lib/resty/openssl/rsa.lua +++ b/lib/resty/openssl/rsa.lua @@ -4,7 +4,7 @@ local C = ffi.C local bn_lib = require "resty.openssl.bn" local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local format_error = require("resty.openssl.err").format_error local _M = {} @@ -18,47 +18,47 @@ function _M.get_parameters(rsa_st) return setmetatable(empty_table, { __index = function(_, k) local ptr, ret - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ptr = bn_ptrptr_ct() end if k == 'n' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_key(rsa_st, ptr, nil, nil) end elseif k == 'e' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_key(rsa_st, nil, ptr, nil) end elseif k == 'd' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_key(rsa_st, nil, nil, ptr) end elseif k == 'p' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_factors(rsa_st, ptr, nil) end elseif k == 'q' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_factors(rsa_st, nil, ptr) end elseif k == 'dmp1' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_crt_params(rsa_st, ptr, nil, nil) end elseif k == 'dmq1' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_crt_params(rsa_st, nil, ptr, nil) end elseif k == 'iqmp' then - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then C.RSA_get0_crt_params(rsa_st, nil, nil, ptr) end else return nil, "rsa.get_parameters: unknown parameter \"" .. k .. "\" for RSA key" end - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ret = ptr[0] elseif OPENSSL_10 then ret = rsa_st[k] @@ -102,7 +102,7 @@ function _M.set_parameters(rsa_st, opts) do_set_crt_params = true end end - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then -- "The values n and e must be non-NULL the first time this function is called on a given RSA object." -- thus we force to set them together local code diff --git a/lib/resty/openssl/version.lua b/lib/resty/openssl/version.lua index 006af2c6..a5c01935 100644 --- a/lib/resty/openssl/version.lua +++ b/lib/resty/openssl/version.lua @@ -7,7 +7,7 @@ ffi.cdef[[ // 1.0 unsigned long SSLeay(void); const char *SSLeay_version(int t); - // 1.1 + // >= 1.1 unsigned long OpenSSL_version_num(); const char *OpenSSL_version(int t); ]] @@ -58,7 +58,9 @@ return setmetatable({ version = function(t) return ffi_str(version_func(t)) end, + OPENSSL_30 = version_num >= 0x30000000 and version_num < 0x30100000, OPENSSL_11 = version_num >= 0x10100000 and version_num < 0x10200000, + OPENSSL_11_OR_LATER = version_num >= 0x10100000 and version_num < 0x30100000, OPENSSL_10 = version_num < 0x10100000 and version_num > 0x10000000, }, { __index = types_table, diff --git a/lib/resty/openssl/x509/crl.lua b/lib/resty/openssl/x509/crl.lua index 5cca384e..3df5bbd9 100644 --- a/lib/resty/openssl/x509/crl.lua +++ b/lib/resty/openssl/x509/crl.lua @@ -14,14 +14,14 @@ local txtnid2nid = require("resty.openssl.objects").txtnid2nid local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local accessors = {} accessors.set_issuer_name = C.X509_CRL_set_issuer_name accessors.set_version = C.X509_CRL_set_version -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then accessors.get_last_update = C.X509_CRL_get0_lastUpdate accessors.set_last_update = C.X509_CRL_set1_lastUpdate accessors.get_next_update = C.X509_CRL_get0_nextUpdate @@ -237,7 +237,7 @@ function _M:get_extension(nid_txt, last_pos) end local X509_CRL_delete_ext -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then X509_CRL_delete_ext = C.X509_CRL_delete_ext elseif OPENSSL_10 then X509_CRL_delete_ext = function(ctx, pos) diff --git a/lib/resty/openssl/x509/csr.lua b/lib/resty/openssl/x509/csr.lua index a8bfb5be..bfe94bcb 100644 --- a/lib/resty/openssl/x509/csr.lua +++ b/lib/resty/openssl/x509/csr.lua @@ -14,7 +14,7 @@ local digest_lib = require("resty.openssl.digest") local util = require "resty.openssl.util" local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER local accessors = {} @@ -24,7 +24,7 @@ accessors.get_pubkey = C.X509_REQ_get_pubkey accessors.set_pubkey = C.X509_REQ_set_pubkey accessors.set_version = C.X509_REQ_set_version -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then accessors.get_subject_name = C.X509_REQ_get_subject_name -- returns internal ptr accessors.get_version = C.X509_REQ_get_version elseif OPENSSL_10 then diff --git a/lib/resty/openssl/x509/init.lua b/lib/resty/openssl/x509/init.lua index 19e791d0..7cbba641 100644 --- a/lib/resty/openssl/x509/init.lua +++ b/lib/resty/openssl/x509/init.lua @@ -19,7 +19,7 @@ local util = require "resty.openssl.util" local txtnid2nid = require("resty.openssl.objects").txtnid2nid local format_error = require("resty.openssl.err").format_error local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 -local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER -- accessors provides an openssl version neutral interface to lua layer -- it doesn't handle any error, expect that to be implemented in @@ -35,7 +35,7 @@ accessors.set_subject_name = C.X509_set_subject_name accessors.get_issuer_name = C.X509_get_issuer_name -- returns internal ptr, we dup it accessors.set_issuer_name = C.X509_set_issuer_name -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then -- generally, use get1 if we return a lua table wrapped ctx which doesn't support dup. -- in that case, a new struct is returned from C api, and we will handle gc. -- openssl will increment the reference count for returned ptr, and won't free it when @@ -294,7 +294,7 @@ local uint_ptr = ffi.typeof("unsigned int[1]") local function digest(self, cfunc, typ) -- TODO: dedup the following with resty.openssl.digest local ctx - if OPENSSL_11 then + if OPENSSL_11_OR_LATER then ctx = C.EVP_MD_CTX_new() ffi_gc(ctx, C.EVP_MD_CTX_free) elseif OPENSSL_10 then @@ -415,7 +415,7 @@ function _M:get_extension(nid_txt, last_pos) end local X509_delete_ext -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then X509_delete_ext = C.X509_delete_ext elseif OPENSSL_10 then X509_delete_ext = function(ctx, pos) diff --git a/scripts/templates/x509_functions.j2 b/scripts/templates/x509_functions.j2 index dd22802e..e0eab60a 100644 --- a/scripts/templates/x509_functions.j2 +++ b/scripts/templates/x509_functions.j2 @@ -83,7 +83,7 @@ function _M:get_extension(nid_txt, last_pos) end local {{ module.type }}_delete_ext -if OPENSSL_11 then +if OPENSSL_11_OR_LATER then {{ module.type }}_delete_ext = C.{{ module.type }}_delete_ext elseif OPENSSL_10 then {{ module.type }}_delete_ext = function(ctx, pos) diff --git a/t/openssl.t b/t/openssl.t index 8d1d4784..59cac8a9 100644 --- a/t/openssl.t +++ b/t/openssl.t @@ -33,7 +33,7 @@ __DATA__ --- request GET /t --- response_body_like -10\d{4}[0-9a-f]f +\d{6}[0-9a-f][0f] --- no_error_log [error] diff --git a/t/openssl/cipher.t b/t/openssl/cipher.t index d001c526..b4b38bf3 100644 --- a/t/openssl/cipher.t +++ b/t/openssl/cipher.t @@ -112,6 +112,8 @@ cipher:update: cipher not initalized, call cipher:init first no_padding = true, }) ngx.say(s) + -- 1.x: data not multiple of block length + -- 3.0: wrong final block length ngx.say(err) local s = myassert(cipher:encrypt(string.rep("0", 32), string.rep("0", 16), '1' .. string.rep(string.char(15), 15), { @@ -124,7 +126,7 @@ cipher:update: cipher not initalized, call cipher:init first GET /t --- response_body_like eval "nil -.+data not multiple of block length +.+(?:data not multiple of block length|wrong final block length) VhGyRCcMvlAgUjTYrqiWpg==" --- no_error_log [error] diff --git a/t/openssl/helper.lua b/t/openssl/helper.lua index cf9ce0b9..959a19f5 100644 --- a/t/openssl/helper.lua +++ b/t/openssl/helper.lua @@ -43,7 +43,7 @@ local function myassert(...) local err = ret[#ret] if #ret > 1 and err then ngx.log(ngx.ERR, tostring(err)) - ngx.exit(500) + ngx.exit(0) end return ... end diff --git a/t/openssl/pkey.t b/t/openssl/pkey.t index 18272219..dd2186db 100644 --- a/t/openssl/pkey.t +++ b/t/openssl/pkey.t @@ -294,14 +294,14 @@ ok --- request GET /t --- response_body_like eval -"[A-F0-9]{512} -[A-F0-9]{6} -[A-F0-9]{512} -[A-F0-9]{256} -[A-F0-9]{256} -[A-F0-9]{256} -[A-F0-9]{256} -[A-F0-9]{256} +"[A-F0-9]+ +[A-F0-9]+ +[A-F0-9]+ +[A-F0-9]+ +[A-F0-9]+ +[A-F0-9]+ +[A-F0-9]+ +[A-F0-9]+ nil " --- no_error_log diff --git a/t/openssl/version.t b/t/openssl/version.t index 0629c896..10293148 100644 --- a/t/openssl/version.t +++ b/t/openssl/version.t @@ -33,7 +33,7 @@ __DATA__ --- request GET /t --- response_body_like -OpenSSL 1.\d.\d.+ +OpenSSL \d.\d.\d.+ --- no_error_log [error] @@ -50,7 +50,7 @@ OpenSSL 1.\d.\d.+ --- request GET /t --- response_body_like -OpenSSL 1.\d.\d.+ +OpenSSL \d.\d.\d.+ compiler:.+ --- no_error_log [error]