diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GNUmakefile | 1 | ||||
-rw-r--r-- | src/openssl.c | 884 | ||||
-rw-r--r-- | src/openssl.kdf.lua | 3 |
3 files changed, 853 insertions, 35 deletions
diff --git a/src/GNUmakefile b/src/GNUmakefile index f5c7c55..9a568a1 100644 --- a/src/GNUmakefile +++ b/src/GNUmakefile @@ -80,6 +80,7 @@ MODS$(1)_$(d) = \ $$(DESTDIR)$(3)/openssl.lua \ $$(DESTDIR)$(3)/openssl/auxlib.lua \ $$(DESTDIR)$(3)/openssl/bignum.lua \ + $$(DESTDIR)$(3)/openssl/kdf.lua \ $$(DESTDIR)$(3)/openssl/ocsp/basic.lua \ $$(DESTDIR)$(3)/openssl/ocsp/response.lua \ $$(DESTDIR)$(3)/openssl/pkey.lua \ diff --git a/src/openssl.c b/src/openssl.c index 8f90769..31c173a 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -127,6 +127,18 @@ #define HAVE_C___DECLSPEC_NORETURN MSC_PREREQ(8,0,0) #endif +#ifndef HAVE_OPENSSL_ZALLOC +#define HAVE_OPENSSL_ZALLOC OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_OPENSSL_CLEAR_FREE +#define HAVE_OPENSSL_CLEAR_FREE OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_OPENSSL_MEMDUP +#define HAVE_OPENSSL_MEMDUP OPENSSL_PREREQ(1,1,0) +#endif + #ifndef HAVE_ASN1_STRING_GET0_DATA #define HAVE_ASN1_STRING_GET0_DATA (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif @@ -207,6 +219,18 @@ #define HAVE_EVP_CIPHER_CTX_NEW (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif +#ifndef HAVE_EVP_KDF_CTX +#define HAVE_EVP_KDF_CTX OPENSSL_PREREQ(1,2,0) +#endif + +#ifndef HAVE_PKCS5_PBKDF2_HMAC +#define HAVE_PKCS5_PBKDF2_HMAC (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) +#endif + +#ifndef HAVE_SCRYPT +#define HAVE_SCRYPT OPENSSL_PREREQ(1,1,0) +#endif + #ifndef HAVE_EVP_MD_CTX_FREE #define HAVE_EVP_MD_CTX_FREE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif @@ -227,6 +251,14 @@ #define HAVE_EVP_PKEY_CTX_NEW (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif +#ifndef HAVE_EVP_PKEY_CTX_KDF +#define HAVE_EVP_PKEY_CTX_KDF OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_EVP_PKEY_CTX_HKDF_MODE +#define HAVE_EVP_PKEY_CTX_HKDF_MODE (HAVE_EVP_PKEY_CTX_KDF && OPENSSL_PREREQ(1,1,1)) +#endif + #ifndef HAVE_EVP_PKEY_GET0 #define HAVE_EVP_PKEY_GET0 (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif @@ -436,7 +468,7 @@ #endif #ifndef HAVE_SSL_GET_SERVER_TMP_KEY -#define HAVE_SSL_GET_SERVER_TMP_KEY OPENSSL_PREREQ(1,0,2) +#define HAVE_SSL_GET_SERVER_TMP_KEY (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,3)) #endif #ifndef HAVE_SSL_GET_TLSEXT_STATUS_TYPE @@ -471,6 +503,10 @@ #define HAVE_STACK_OPENSSL_STRING_FUNCS (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif +#ifndef HAVE_X509_CHAIN_UP_REF +#define HAVE_X509_CHAIN_UP_REF OPENSSL_PREREQ(1,0,2) +#endif + #ifndef HAVE_X509_CRL_GET0_LASTUPDATE #define HAVE_X509_CRL_GET0_LASTUPDATE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif @@ -535,6 +571,10 @@ #define HMAC_INIT_EX_INT OPENSSL_PREREQ(1,0,0) #endif +#if HAVE_EVP_PKEY_CTX_KDF || HAVE_EVP_KDF_CTX +#include <openssl/kdf.h> +#endif + #ifndef STRERROR_R_CHAR_P #ifdef __GLIBC__ #define STRERROR_R_CHAR_P (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)) @@ -1521,6 +1561,32 @@ dlerr: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#if !HAVE_OPENSSL_ZALLOC +static void *OPENSSL_zalloc(size_t num) { + void *ret = OPENSSL_malloc(num); + + if (ret != NULL) + memset(ret, 0, num); + return ret; +} +#endif + +#if !HAVE_OPENSSL_CLEAR_FREE +static void OPENSSL_clear_free(void *str, size_t num) { + if (str == NULL) + return; + if (num) + OPENSSL_cleanse(str, num); + CRYPTO_free(str); +} /* CRYPTO_clear_free() */ +#endif + +#if !HAVE_OPENSSL_MEMDUP +static void *OPENSSL_memdup(const void *data, size_t siz) { + return BUF_memdup(data, siz); +} /* OPENSSL_memdup() */ +#endif + #define COMPAT_X509_STORE_FREE_BUG 0x01 static struct { @@ -2123,6 +2189,24 @@ static int compat_X509_up_ref(X509 *crt) { } /* compat_X509_up_ref() */ #endif +#if !HAVE_X509_CHAIN_UP_REF +/* + * NB: this operation dups the chain (but not the certificates within it) + */ +#define X509_chain_up_ref(...) EXPAND( compat_X509_chain_up_ref(__VA_ARGS__) ) + +STACK_OF(X509) *compat_X509_chain_up_ref(STACK_OF(X509) *chain) { + STACK_OF(X509) *ret; + int i; + ret = sk_X509_dup(chain); + for (i = 0; i < sk_X509_num(ret); i++) { + X509 *x = sk_X509_value(ret, i); + X509_up_ref(x); + } + return ret; +} /* compat_X509_chain_up_ref() */ +#endif + #if !HAVE_X509_VERIFY_PARAM_SET1_EMAIL /* * NB: Cannot emulate. Requires dereferencing X509_VERIFY_PARAM_ID objects, @@ -2136,6 +2220,418 @@ static int compat_X509_up_ref(X509 *crt) { */ #endif + +#if !HAVE_EVP_KDF_CTX +/* + * Emulate EVP_KDF_CTX API (introduced in OpenSSL 1.2.0) + */ + +#ifndef ERR_LIB_KDF +#define ERR_LIB_KDF 0 +#endif + +#ifndef KDFerr +#define KDFerr(f,r) ERR_PUT_error(ERR_LIB_KDF,f,(r),__FILE__,__LINE__) +#endif + +#ifndef EVP_F_EVP_KDF_CTRL +#define EVP_F_EVP_KDF_CTRL 0 +#endif + +#ifndef EVP_F_EVP_KDF_CTX_NEW_ID +#define EVP_F_EVP_KDF_CTX_NEW_ID 0 +#endif + +#ifndef EVP_R_UNSUPPORTED_ALGORITHM +#define EVP_R_UNSUPPORTED_ALGORITHM EVP_R_UNKNOWN_OPTION +#endif + +#ifndef EVP_R_COMMAND_NOT_SUPPORTED +#define EVP_R_COMMAND_NOT_SUPPORTED EVP_R_UNKNOWN_OPTION +#endif + +typedef struct { + int nid; + union { +#if HAVE_PKCS5_PBKDF2_HMAC + /* Arguments for PKCS5_PBKDF2_HMAC */ + struct { + unsigned char *pass; + size_t passlen; + unsigned char *salt; + size_t saltlen; + int iter; + const EVP_MD *md; + } pbkdf2; +#endif + +#if HAVE_SCRYPT + /* Arguments for EVP_PBE_scrypt */ + struct { + unsigned char *pass; + size_t passlen; + unsigned char *salt; + size_t saltlen; + uint64_t N; + uint32_t r; + uint32_t p; + uint64_t maxmem_bytes; + } scrypt; +#endif + +#if HAVE_EVP_PKEY_CTX_KDF + EVP_PKEY_CTX *pctx; +#endif + }; +} EVP_KDF_CTX; + +static void EVP_KDF_CTX_free(EVP_KDF_CTX *kctx) { + if (kctx == NULL) + return; + + switch(kctx->nid) { +#if HAVE_PKCS5_PBKDF2_HMAC + case NID_id_pbkdf2: + OPENSSL_clear_free(kctx->pbkdf2.pass, kctx->pbkdf2.passlen); + OPENSSL_clear_free(kctx->pbkdf2.salt, kctx->pbkdf2.saltlen); + break; +#endif +#if HAVE_SCRYPT + case NID_id_scrypt: + OPENSSL_clear_free(kctx->scrypt.pass, kctx->scrypt.passlen); + OPENSSL_clear_free(kctx->scrypt.salt, kctx->scrypt.saltlen); + break; +#endif +#if HAVE_EVP_PKEY_CTX_KDF + case NID_tls1_prf: + case NID_hkdf: + EVP_PKEY_CTX_free(kctx->pctx); + break; +#endif + } + + OPENSSL_free(kctx); +} /* EVP_KDF_CTX_free() */ + +static EVP_KDF_CTX *EVP_KDF_CTX_new_id(int id) { + EVP_KDF_CTX *ret; + + ret = OPENSSL_zalloc(sizeof(*ret)); + if (ret == NULL) { + EVPerr(EVP_F_EVP_KDF_CTX_NEW_ID, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->nid = id; + + switch(id) { +#if HAVE_PKCS5_PBKDF2_HMAC + case NID_id_pbkdf2: + break; +#endif +#if HAVE_SCRYPT + case NID_id_scrypt: + break; +#endif +#if HAVE_EVP_PKEY_CTX_KDF + case NID_tls1_prf: + case NID_hkdf: { + ret->pctx = EVP_PKEY_CTX_new_id(id, NULL); + if (!ret->pctx) { + OPENSSL_free(ret); + return NULL; + } + if (EVP_PKEY_derive_init(ret->pctx) <= 0) { + EVP_KDF_CTX_free(ret); + return NULL; + } + break; + } + break; +#endif + default: + OPENSSL_free(ret); + EVPerr(EVP_F_EVP_KDF_CTX_NEW_ID, EVP_R_UNSUPPORTED_ALGORITHM); + return NULL; + } + + return ret; +} /* EVP_KDF_CTX_new_id() */ + +static int set_membuf(unsigned char **buffer, size_t *buflen, const unsigned char *new_buffer, size_t new_buflen) { + if (new_buffer == NULL) + return 1; + OPENSSL_clear_free(*buffer, *buflen); + if (new_buflen > 0) { + *buffer = OPENSSL_memdup(new_buffer, new_buflen); + } else { + *buffer = OPENSSL_malloc(1); + } + if (*buffer == NULL) { + KDFerr(EVP_F_EVP_KDF_CTRL, ERR_R_MALLOC_FAILURE); + return 0; + } + *buflen = new_buflen; + return 1; +} + +#define EVP_KDF_CTRL_SET_PASS 0x01 /* unsigned char *, size_t */ +#define EVP_KDF_CTRL_SET_SALT 0x02 /* unsigned char *, size_t */ +#define EVP_KDF_CTRL_SET_ITER 0x03 /* int */ +#define EVP_KDF_CTRL_SET_MD 0x04 /* EVP_MD * */ +#define EVP_KDF_CTRL_SET_KEY 0x05 /* unsigned char *, size_t */ +#define EVP_KDF_CTRL_SET_MAXMEM_BYTES 0x06 /* uint64_t */ +#define EVP_KDF_CTRL_SET_TLS_SECRET 0x07 /* unsigned char *, size_t */ +#define EVP_KDF_CTRL_RESET_TLS_SEED 0x08 +#define EVP_KDF_CTRL_ADD_TLS_SEED 0x09 /* unsigned char *, size_t */ +#define EVP_KDF_CTRL_RESET_HKDF_INFO 0x0a +#define EVP_KDF_CTRL_ADD_HKDF_INFO 0x0b /* unsigned char *, size_t */ +#define EVP_KDF_CTRL_SET_HKDF_MODE 0x0c /* int */ +#define EVP_KDF_CTRL_SET_SCRYPT_N 0x0d /* uint64_t */ +#define EVP_KDF_CTRL_SET_SCRYPT_R 0x0e /* uint32_t */ +#define EVP_KDF_CTRL_SET_SCRYPT_P 0x0f /* uint32_t */ + +#ifdef EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND +#define EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND +#elif HAVE_EVP_PKEY_CTX_KDF +#define EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND 0 +#endif + +#ifdef EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY +#define EVP_KDF_HKDF_MODE_EXTRACT_ONLY EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY +#endif + +#ifdef EVP_PKEY_HKDEF_MODE_EXPAND_ONLY +#define EVP_KDF_HKDF_MODE_EXPAND_ONLY EVP_PKEY_HKDEF_MODE_EXPAND_ONLY +#endif + +static int EVP_KDF_vctrl(EVP_KDF_CTX *kctx, int cmd, va_list args) { + const EVP_MD *md; + const unsigned char *p; + size_t len; + uint64_t u64_value; + uint32_t value; + int iter, mode; + + if (kctx == NULL) + return 0; + + switch (kctx->nid) { +#if HAVE_PKCS5_PBKDF2_HMAC + case NID_id_pbkdf2: { + switch (cmd) { + case EVP_KDF_CTRL_SET_PASS: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return set_membuf(&kctx->pbkdf2.pass, &(kctx->pbkdf2.passlen), p, len); + + case EVP_KDF_CTRL_SET_SALT: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return set_membuf(&kctx->pbkdf2.salt, &kctx->pbkdf2.saltlen, p, len); + + case EVP_KDF_CTRL_SET_ITER: + iter = va_arg(args, int); + if (iter < 1) + return 0; + kctx->pbkdf2.iter = iter; + return 1; + + case EVP_KDF_CTRL_SET_MD: + md = va_arg(args, const EVP_MD *); + if (md == NULL) + return 0; + kctx->pbkdf2.md = md; + return 1; + + default: + EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + } +#endif +#if HAVE_SCRYPT + case NID_id_scrypt: { + switch (cmd) { + case EVP_KDF_CTRL_SET_PASS: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return set_membuf(&kctx->scrypt.pass, &kctx->scrypt.passlen, p, len); + + case EVP_KDF_CTRL_SET_SALT: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return set_membuf(&kctx->scrypt.salt, &kctx->scrypt.saltlen, p, len); + + case EVP_KDF_CTRL_SET_SCRYPT_N: + u64_value = va_arg(args, uint64_t); + if ((u64_value <= 1) || ((u64_value & (u64_value - 1)) != 0)) /* is_power_of_two check */ + return 0; + kctx->scrypt.N = u64_value; + return 1; + + case EVP_KDF_CTRL_SET_SCRYPT_R: + value = va_arg(args, uint32_t); + if (value < 1) + return 0; + kctx->scrypt.r = value; + return 1; + + case EVP_KDF_CTRL_SET_SCRYPT_P: + value = va_arg(args, uint32_t); + if (value < 1) + return 0; + kctx->scrypt.p = value; + return 1; + + case EVP_KDF_CTRL_SET_MAXMEM_BYTES: + u64_value = va_arg(args, uint64_t); + if (u64_value < 1) + return 0; + kctx->scrypt.maxmem_bytes = u64_value; + return 1; + + default: + EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + } +#endif +#if HAVE_EVP_PKEY_CTX_KDF + case NID_tls1_prf: { + switch (cmd) { + case EVP_KDF_CTRL_SET_MD: + md = va_arg(args, const EVP_MD *); + return EVP_PKEY_CTX_set_tls1_prf_md(kctx->pctx, md); + + case EVP_KDF_CTRL_SET_TLS_SECRET: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + /* XXX: the old api resets the seed when you set the secret. When + * using this compat routine, make sure you set the secret before + * the seed. + * https://github.com/openssl/openssl/issues/7728 + */ + return EVP_PKEY_CTX_set1_tls1_prf_secret(kctx->pctx, p, len); + + case EVP_KDF_CTRL_ADD_TLS_SEED: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return EVP_PKEY_CTX_add1_tls1_prf_seed(kctx->pctx, p, len); + + default: + EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + } + case NID_hkdf: { + switch (cmd) { + case EVP_KDF_CTRL_SET_SALT: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return EVP_PKEY_CTX_set1_hkdf_salt(kctx->pctx, p, len); + + case EVP_KDF_CTRL_SET_MD: + md = va_arg(args, const EVP_MD *); + return EVP_PKEY_CTX_set_hkdf_md(kctx->pctx, md); + + case EVP_KDF_CTRL_SET_KEY: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return EVP_PKEY_CTX_set1_hkdf_key(kctx->pctx, p, len); + + case EVP_KDF_CTRL_ADD_HKDF_INFO: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + return EVP_PKEY_CTX_add1_hkdf_info(kctx->pctx, p, len); + + case EVP_KDF_CTRL_SET_HKDF_MODE: + mode = va_arg(args, int); +#if HAVE_EVP_PKEY_CTX_HKDF_MODE + return EVP_PKEY_CTX_hkdf_mode(kctx->pctx, mode); +#else + if (mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND) + return 1; + else + /* XXX: OpenSSL doesn't set an error here */ + return 0; + +#endif + default: + EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + } +#endif + default: + (void)cmd; + (void)args; + return 0; + } +} /* EVP_KDF_vctrl() */ + +static int EVP_KDF_ctrl(EVP_KDF_CTX *kctx, int cmd, ...) { + int ret; + va_list args; + va_start(args, cmd); + ret = EVP_KDF_vctrl(kctx, cmd, args); + va_end(args); + if (ret == -2) + EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); + return ret; +} /* EVP_KDF_ctrl() */ + +static size_t EVP_KDF_size(EVP_KDF_CTX *kctx) { + if (kctx == NULL) + return 0; + + switch(kctx->nid) { +#if HAVE_EVP_PKEY_CTX_KDF + case NID_tls1_prf: + case NID_hkdf: { + size_t outlen = 0; + EVP_PKEY_derive(kctx->pctx, NULL, &outlen); + return outlen; + } +#endif + default: + return SIZE_MAX; + } +} /* EVP_KDF_size() */ + +static int EVP_KDF_derive(EVP_KDF_CTX *kctx, unsigned char *out, size_t *outlen) { + switch(kctx->nid) { +#if HAVE_PKCS5_PBKDF2_HMAC + case NID_id_pbkdf2: + return PKCS5_PBKDF2_HMAC((const char*)kctx->pbkdf2.pass, kctx->pbkdf2.passlen, + kctx->pbkdf2.salt, kctx->pbkdf2.saltlen, + kctx->pbkdf2.iter, + kctx->pbkdf2.md, + *outlen, out); +#endif +#if HAVE_SCRYPT + case NID_id_scrypt: + return EVP_PBE_scrypt((const char*)kctx->scrypt.pass, kctx->scrypt.passlen, + kctx->scrypt.salt, kctx->scrypt.saltlen, + kctx->scrypt.N, kctx->scrypt.r, kctx->scrypt.p, + kctx->scrypt.maxmem_bytes, + out, *outlen); +#endif +#if HAVE_EVP_PKEY_CTX_KDF + case NID_tls1_prf: + case NID_hkdf: + return EVP_PKEY_derive(kctx->pctx, out, outlen); +#endif + default: + (void)out; + (void)outlen; + return 0; + } +} /* EVP_KDF_derive() */ + +#endif + + /* compat_init must not be called from multiple threads at once */ static int compat_init(void) { static int store_index = -1, ssl_ctx_index = -1, done; @@ -2706,7 +3202,7 @@ static const char opensslconf_no[][20] = { { "" } /* in case nothing is defined above */ }; /* opensslconf_no[] */ -static const auxL_IntegerReg ssleay_version[] = { +static const auxL_IntegerReg openssl_integers[] = { #ifdef SSLEAY_VERSION_NUMBER { "SSLEAY_VERSION_NUMBER", SSLEAY_VERSION_NUMBER }, #endif @@ -2728,6 +3224,19 @@ static const auxL_IntegerReg ssleay_version[] = { #ifdef SSLEAY_DIR { "SSLEAY_DIR", SSLEAY_DIR }, #endif +#ifdef LIBRESSL_VERSION_NUMBER + { "LIBRESSL_VERSION_NUMBER", LIBRESSL_VERSION_NUMBER }, +#endif +#ifdef OPENSSL_VERSION_NUMBER + { "OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER }, +#endif +#ifdef LIBRESSL_VERSION_NUMBER + { "VERSION_NUMBER", LIBRESSL_VERSION_NUMBER }, +#elif OPENSSL_VERSION_NUMBER + { "VERSION_NUMBER", OPENSSL_VERSION_NUMBER }, +#else + { "VERSION_NUMBER", SSLEAY_VERSION_NUMBER }, +#endif { NULL, 0 }, }; @@ -2743,10 +3252,7 @@ EXPORT int luaopen__openssl(lua_State *L) { } } - auxL_setintegers(L, ssleay_version); - - auxL_pushinteger(L, OPENSSL_VERSION_NUMBER); - lua_setfield(L, -2, "VERSION_NUMBER"); + auxL_setintegers(L, openssl_integers); lua_pushstring(L, OPENSSL_VERSION_TEXT); lua_setfield(L, -2, "VERSION_TEXT"); @@ -2757,11 +3263,6 @@ EXPORT int luaopen__openssl(lua_State *L) { lua_pushstring(L, SHLIB_VERSION_NUMBER); lua_setfield(L, -2, "SHLIB_VERSION_NUMBER"); -#if defined LIBRESSL_VERSION_NUMBER - auxL_pushinteger(L, LIBRESSL_VERSION_NUMBER); - lua_setfield(L, -2, "LIBRESSL_VERSION_NUMBER"); -#endif - return 1; } /* luaopen__openssl() */ @@ -6785,6 +7286,112 @@ static int xc_sign(lua_State *L) { } /* xc_sign() */ +static int xc_verify(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + X509_STORE *store = NULL; + STACK_OF(X509) *chain = NULL; + X509_VERIFY_PARAM *params = NULL; + X509_STORE_CTX *ctx = NULL; + int ok, why; + STACK_OF(X509) **proof; + + if (lua_istable(L, 2)) { + if (lua_getfield(L, 2, "store") != LUA_TNIL) { + store = checksimple(L, -1, X509_STORE_CLASS); + } else if (!(OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,5))) { + /* + Without .store OpenSSL 1.0.1 crashes e.g. + + #0 X509_STORE_get_by_subject (vs=vs@entry=0x6731b0, type=type@entry=1, name=name@entry=0x66a360, ret=ret@entry=0x7fffffffe580) at x509_lu.c:293 + #1 0x00007ffff69653ca in X509_STORE_CTX_get1_issuer (issuer=0x7fffffffe620, ctx=0x6731b0, x=0x665db0) at x509_lu.c:604 + #2 0x00007ffff696117c in X509_verify_cert (ctx=ctx@entry=0x6731b0) at x509_vfy.c:256 + + Was fixed in LibreSSL somewhere between 2.6.5 and 2.7.5 + */ + luaL_argerror(L, 2, ".store required in OpenSSL <= 1.0.1"); + } + lua_pop(L, 1); + + if (lua_getfield(L, 2, "chain") != LUA_TNIL) { + chain = checksimple(L, -1, X509_CHAIN_CLASS); + } + lua_pop(L, 1); + + if (lua_getfield(L, 2, "params") != LUA_TNIL) { + params = checksimple(L, -1, X509_VERIFY_PARAM_CLASS); + } + lua_pop(L, 1); + + if (lua_getfield(L, 2, "crls") != LUA_TNIL) { + luaL_argerror(L, 2, "crls not yet supported"); + } + lua_pop(L, 1); + + if (lua_getfield(L, 2, "dane") != LUA_TNIL) { + luaL_argerror(L, 2, "dane not yet supported"); + } + lua_pop(L, 1); + } + + /* pre-allocate space for a successful return */ + proof = prepsimple(L, X509_CHAIN_CLASS); + + if (chain && !(chain = X509_chain_up_ref(chain))) + goto eossl; + + if (!(ctx = X509_STORE_CTX_new()) || !X509_STORE_CTX_init(ctx, store, crt, chain)) { + sk_X509_pop_free(chain, X509_free); + goto eossl; + } + + if (params) { + X509_VERIFY_PARAM *params_copy = X509_VERIFY_PARAM_new(); + if (!params_copy) + goto eossl; + + ok = X509_VERIFY_PARAM_inherit(params_copy, params); + if (!ok) { + X509_VERIFY_PARAM_free(params_copy); + goto eossl; + } + + X509_STORE_CTX_set0_param(ctx, params_copy); + } + + ERR_clear_error(); + + ok = X509_verify_cert(ctx); + + switch (ok) { + case 1: /* verified */ + if (!(*proof = X509_STORE_CTX_get1_chain(ctx))) + goto eossl; + X509_STORE_CTX_free(ctx); + + lua_pushboolean(L, 1); + lua_pushvalue(L, -2); + + return 2; + case 0: /* not verified */ + why = X509_STORE_CTX_get_error(ctx); + X509_STORE_CTX_free(ctx); + + lua_pushboolean(L, 0); + lua_pushstring(L, X509_verify_cert_error_string(why)); + + return 2; + default: + goto eossl; + } + +eossl: + if (ctx) + X509_STORE_CTX_free(ctx); + + return auxL_error(L, auxL_EOPENSSL, "x509.cert:verify"); +} /* xc_verify() */ + + static int xc_text(lua_State *L) { static const struct { const char *kw; unsigned int flag; } map[] = { { "no_header", X509_FLAG_NO_HEADER }, @@ -6936,6 +7543,7 @@ static const auxL_Reg xc_methods[] = { { "getPublicKeyDigest", &xc_getPublicKeyDigest }, { "getSignatureName", &xc_getSignatureName }, { "sign", &xc_sign }, + { "verify", &xc_verify }, { "text", &xc_text }, { "toPEM", &xc_toPEM }, { "tostring", &xc__tostring }, @@ -7915,16 +8523,18 @@ EXPORT int luaopen__openssl_x509_crl(lua_State *L) { static void xl_dup(lua_State *L, STACK_OF(X509) *src, _Bool copy) { STACK_OF(X509) **dst = prepsimple(L, X509_CHAIN_CLASS); - X509 *crt; - int i, n; if (copy) { + int i, n; + if (!(*dst = sk_X509_new_null())) goto error; n = sk_X509_num(src); for (i = 0; i < n; i++) { + X509 *crt; + if (!(crt = sk_X509_value(src, i))) continue; @@ -7937,21 +8547,13 @@ static void xl_dup(lua_State *L, STACK_OF(X509) *src, _Bool copy) { } } } else { - if (!(*dst = sk_X509_dup(src))) + if (!(*dst = X509_chain_up_ref(src))) goto error; - - n = sk_X509_num(*dst); - - for (i = 0; i < n; i++) { - if (!(crt = sk_X509_value(*dst, i))) - continue; - X509_up_ref(crt); - } } return; error: - auxL_error(L, auxL_EOPENSSL, "sk_X509_dup"); + auxL_error(L, auxL_EOPENSSL, "xl_dup"); } /* xl_dup() */ @@ -8169,19 +8771,8 @@ static int xs_verify(lua_State *L) { proof = prepsimple(L, X509_CHAIN_CLASS); if (!lua_isnoneornil(L, 3)) { - X509 *elm; - int i, n; - - if (!(chain = sk_X509_dup(checksimple(L, 3, X509_CHAIN_CLASS)))) + if (!(chain = X509_chain_up_ref(checksimple(L, 3, X509_CHAIN_CLASS)))) goto eossl; - - n = sk_X509_num(chain); - - for (i = 0; i < n; i++) { - if (!(elm = sk_X509_value(chain, i))) - continue; - X509_up_ref(elm); - } } if (!(ctx = X509_STORE_CTX_new()) || !X509_STORE_CTX_init(ctx, store, crt, chain)) { @@ -11360,6 +11951,229 @@ EXPORT int luaopen__openssl_cipher(lua_State *L) { /* + * openssl.kdf + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int EVP_KDF__gc(lua_State *L) { + EVP_KDF_CTX **res = lua_touserdata(L, 1); + + if (*res) { + EVP_KDF_CTX_free(*res); + *res = NULL; + } + + return 0; +} /* EVP_KDF__gc() */ + + +static int kdf_derive(lua_State *L) { + int nid; + luaL_Buffer b; + EVP_KDF_CTX *kctx, **kctxp; + unsigned char* out; + size_t outlen = 0; + const char *str = NULL; + size_t len; + _Bool seed = 0; + int mode; + + luaL_checktype(L, 1, LUA_TTABLE); + + { + const char* type; + if (!loadfield(L, 1, "type", LUA_TSTRING, &type)) + return luaL_argerror(L, 1, "missing 'type' field"); + if (!auxS_txt2nid(&nid, type)) + return luaL_argerror(L, 1, "unknown 'type'"); + } + + /* ensure EVP_KDF_CTX is collected on error */ + kctxp = prepudata(L, sizeof(EVP_KDF_CTX*), NULL, &EVP_KDF__gc); + if (!(kctx = EVP_KDF_CTX_new_id(nid))) + return auxL_error(L, auxL_EOPENSSL, "kdf.derive"); + *kctxp = kctx; + + + lua_pushnil(L); + while (lua_next(L, 1)) { + switch (auxL_testoption(L, -2, 0, (const char *[]){ + /* special fields */ + "type", + "outlen", + /* general options */ + "pass", + "salt", + "iter", + "md", + "key", + "maxmem_bytes", + /* KDF specific */ + "secret", + "seed", + "info", + "hkdf_mode", + "N", + "r", + "p", + NULL }, 0)) { + case 0: /* skip 'type' */ + break; + + case 1: + outlen = auxL_checkunsigned(L, -1, 1, SIZE_MAX-1); + break; + + case 2: + str = luaL_checklstring(L, -1, &len); + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PASS, (const unsigned char*)str, len) <= 0) + goto error; + break; + + case 3: + str = luaL_checklstring(L, -1, &len); + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, (const unsigned char*)str, len) <= 0) + goto error; + break; + + case 4: + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_ITER, auxL_checkunsigned(L, -1, 1, (int)-1)) <= 0) + goto error; + break; + + case 5: + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, md_checkdigest(L, -1)) <= 0) + goto error; + break; + + case 6: + str = luaL_checklstring(L, -1, &len); + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, (const unsigned char*)str, len) <= 0) + goto error; + break; + + case 7: + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MAXMEM_BYTES, auxL_checkunsigned(L, -1, 0, UINT64_MAX)) <= 0) + goto error; + break; + + case 8: + str = luaL_checklstring(L, -1, &len); + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_TLS_SECRET, (const unsigned char*)str, len) <= 0) + goto error; + break; + + case 9: + seed = 1; + break; + + case 10: + str = luaL_checklstring(L, -1, &len); + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_ADD_HKDF_INFO, (const unsigned char*)str, len) <= 0) + goto error; + break; + + case 11: + mode = ((int[]){ +#ifdef EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND + EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND, +#endif +#ifdef EVP_KDF_HKDF_MODE_EXTRACT_ONLY + EVP_KDF_HKDF_MODE_EXTRACT_ONLY, +#endif +#ifdef EVP_KDF_HKDF_MODE_EXPAND_ONLY + EVP_KDF_HKDF_MODE_EXPAND_ONLY, +#endif + 0 })[auxL_checkoption(L, -1, 0, (const char *[]){ +#ifdef EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND + "extract_and_expand", +#endif +#ifdef EVP_KDF_HKDF_MODE_EXTRACT_ONLY + "extract_only", +#endif +#ifdef EVP_KDF_HKDF_MODE_EXPAND_ONLY + "expand_only", +#endif + NULL }, 0)]; + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_HKDF_MODE, mode) <= 0) + goto error; + break; + + case 12: + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_N, auxL_checkunsigned(L, -1, 0, UINT64_MAX)) <= 0) + goto error; + break; + + case 13: + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_R, auxL_checkunsigned(L, -1, 0, UINT32_MAX)) <= 0) + goto error; + break; + + case 14: + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_P, auxL_checkunsigned(L, -1, 0, UINT32_MAX)) <= 0) + goto error; + break; + + default: + return luaL_argerror(L, 1, lua_pushfstring(L, "unknown field '%s'", lua_tostring(L, -2))); + } + lua_pop(L, 1); + } + + /* XXX: seed must be set *after* secret + * https://github.com/openssl/openssl/issues/7728 */ + if (seed) { + lua_getfield(L, 1, "seed"); + str = luaL_checklstring(L, -1, &len); + if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_ADD_TLS_SEED, (const unsigned char*)str, len) <= 0) + goto error; + lua_pop(L, 1); + } + + if (outlen == 0) { + outlen = EVP_KDF_size(kctx); + if (outlen == 0) + goto error; + if (outlen == SIZE_MAX) + return luaL_argerror(L, 1, "missing 'outlen' field"); + } + + out = (unsigned char *)luaL_buffinitsize(L, &b, outlen); + + if (EVP_KDF_derive(kctx, out, &outlen) <= 0) + goto error; + + EVP_KDF_CTX_free(kctx); + *kctxp = NULL; + + luaL_pushresultsize(&b, outlen); + + return 1; + +error: + if (*kctxp) { + EVP_KDF_CTX_free(kctx); + *kctxp = NULL; + } + return auxL_error(L, auxL_EOPENSSL, "kdf.derive"); +} /* kdf_derive */ + + +static const auxL_Reg kdf_globals[] = { + { "derive", &kdf_derive }, + { NULL, NULL }, +}; + +int luaopen__openssl_kdf(lua_State *L) { + initall(L); + + auxL_newlib(L, kdf_globals, 0); + + return 1; +} /* luaopen__openssl_kdf() */ + + +/* * OCSP_RESPONSE - openssl.ocsp.response * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/src/openssl.kdf.lua b/src/openssl.kdf.lua new file mode 100644 index 0000000..da203b0 --- /dev/null +++ b/src/openssl.kdf.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.kdf" + +return ctx |