aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/GNUmakefile1
-rw-r--r--src/openssl.c884
-rw-r--r--src/openssl.kdf.lua3
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