diff options
-rw-r--r-- | doc/luaossl.pdf | bin | 313323 -> 182545 bytes | |||
-rw-r--r-- | doc/luaossl.tex | 133 | ||||
-rwxr-xr-x | regress/167-verify-cert.lua | 47 | ||||
-rwxr-xr-x | regress/95-kdf.lua | 45 | ||||
-rw-r--r-- | regress/regress.lua | 3 | ||||
-rw-r--r-- | src/GNUmakefile | 1 | ||||
-rw-r--r-- | src/openssl.c | 884 | ||||
-rw-r--r-- | src/openssl.kdf.lua | 3 |
8 files changed, 1081 insertions, 35 deletions
diff --git a/doc/luaossl.pdf b/doc/luaossl.pdf Binary files differindex 1f9d84d..fb5679d 100644 --- a/doc/luaossl.pdf +++ b/doc/luaossl.pdf diff --git a/doc/luaossl.tex b/doc/luaossl.tex index c63df57..c371dbd 100644 --- a/doc/luaossl.tex +++ b/doc/luaossl.tex @@ -597,6 +597,19 @@ Returns the type of signature used to sign the certificate as a string. e.g. ``R Signs and updates the instance certificate using the \module{openssl.pkey} $key$. $type$ is an optional string describing the digest type. See \module{pkey:sign}, regarding which types of digests are valid. If $type$ is omitted than a default type is used---``sha1'' for RSA keys, ``dss1'' for DSA keys, and ``ecdsa-with-SHA1'' for EC keys. +\subsubsection[\fn{x509:verify}]{\fn{x509:verify\{ $\ldots$ \}}} + +Verifies the certificate against to the specified parameters. + +\begin{ctabular}{ c | c | p{9cm}} +field & type & description\\\hline +.store & \module{openssl.x509.store} & The certificate store to verify against, any custom settings from the store will be used. \\ +.chain & \module{openssl.x509.chain} & A collection of additional certificates to consider \\ +.params & \module{openssl.x509.verify\_param} & The verification parameters to use; overrides any parameters in $.store$ +\end{ctabular} + +Returns two values. The first is a boolean value for whether the specified certificate $crt$ was verified. If true, the second value is a \module{openssl.x509.chain} object validation chain. If false, the second value is a string describing why verification failed. + \subsubsection[\fn{x509:text}]{\fn{x509:text()}} Returns a human-readable textual representation of the X.509 certificate. @@ -787,6 +800,95 @@ Returns two values. The first is a boolean value for whether the specified certi \end{Module} +\begin{Module}{openssl.x509.verify\_param} + +Binds the ``X509\_VERIFY\_PARAM'' OpenSSL object, principally used for setting parameters to be used during certificate verification operations. + +\subsubsection[\fn{verify\_param.new}]{\fn{verify\_param.new()}} + +Returns a new verify\_param object. + +\subsubsection[\fn{verify\_param.interpose}]{\fn{verify\_param.interpose($name$, $function$)}} + +Add or interpose a verify\_param class method. Returns the previous method, if any. + +\subsubsection[\fn{verify\_param:inherit}]{\fn{verify\_param:inherit($src$)}} + +Inherit flags from $src$. $src$ can be either another \fn{verify\_param} object to inherit from, or a string referring to one of the OpenSSL predefined parameters: + +\begin{ctabular}{ l | p{5cm} } +name & description \\\hline +default & X509 default parameters \\ +smime\_sign & S/MIME sign parameters \\ +pkcs7 & Identical to $smime\_sign$ \\ +ssl\_client & SSL/TLS client parameters \\ +ssl\_server & SSL/TLS server parameters +\end{ctabular} + +\subsubsection[\fn{verify\_param:setPurpose}]{\fn{verify\_param:setPurpose($id\_or\_name$)}} + +Sets the verification purpose of the $verify\_param$. Valid argument can be either an integer which corresponds to OpenSSL's internal purpose ID, or string indicating predefined purposes: + +\begin{ctabular}{ l | p{4cm} } +name & description \\\hline +sslclient & SSL/TLS client \\ +sslserver & SSL/TLS server \\ +nssslserver & Netscape SSL server \\ +smimeencrypt & S/MIME encryption \\ +any & Any Purpose \\ +ocsphelper & OCSP helper \\ +timestampsign & Time Stamp signing +\end{ctabular} + +\subsubsection[\fn{verify\_param:setTime}]{\fn{verify\_param:setTime([$timestamp$])}} + +Sets the verification time in $verify\_param$ to the provided Unix timestamp. By default the current system time is used. + +\subsubsection[\fn{verify\_param:setDepth}]{\fn{verify\_param:setDepth($depth$)}} + +Sets the maximum verification depth to $depth$. That is the maximum number of untrusted CA certificates that can appear in a chain.\footnote{OpenSSL's behaviour in regards to depth changed between OpenSSL 1.0.1 and OpenSSL 1.0.2; similarly for LibreSSL} + +\subsubsection[\fn{verify\_param:getDepth}]{\fn{verify\_param:getDepth()}} + +Returns the current maximum verification depth. + +\subsubsection[\fn{verify\_param:setAuthLevel}]{\fn{verify\_param:setAuthLevel($auth\_level$)}} + +Sets the authentication security level to $auth\_level$. The authentication security level determines the acceptable signature and public key strength when verifying certificate chains. For a certificate chain to validate, the public keys of all the certificates must meet the specified security level. The signature algorithm security level is not enforced for the chain's trust anchor certificate, which is either directly trusted or validated by means other than its signature. See \href{https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html}{$SSL\_CTX\_set\_security\_level(3)$} for the definitions of the available levels. The default security level is -1, or "not set". At security level 0 or lower all algorithms are acceptable. Security level 1 requires at least 80-bit-equivalent security and is broadly interoperable, though it will, for example, reject MD5 signatures or RSA keys shorter than 1024 bits. + +\emph{Only supported since OpenSSL 1.1.0.} + +\subsubsection[\fn{verify\_param:getAuthLevel}]{\fn{verify\_param:getAuthLevel()}} + +Returns the current authentication security level. + +\emph{Only supported since OpenSSL 1.1.0.} + +\subsubsection[\fn{verify\_param:setHost}]{\fn{verify\_param:setHost($name$)}} + +Sets the expected DNS hostname to the string $name$, overriding any previously specified host name or names. If $name$ is $nil$ then name checks will not be performed on the peer certificate. + +\emph{Only supported since OpenSSL 1.1.0.} + +\subsubsection[\fn{verify\_param:addHost}]{\fn{verify\_param:addHost($name$)}} + +Adds $name$ as an additional reference identifier that can match the peer's certificate. Any previous names set via \fn{verify\_param:setHost} or \fn{verify\_param:addHost} are retained. When multiple names are configured, the peer is considered verified when any name matches. + +\emph{Only supported since OpenSSL 1.1.0.} + +\subsubsection[\fn{verify\_param:setEmail}]{\fn{verify\_param:setEmail($email$)}} + +Sets the expected RFC822 email address to the string $email$, overriding any previously specified email address. + +\emph{Only supported since OpenSSL 1.1.0.} + +\subsubsection[\fn{verify\_param:setIP}]{\fn{verify\_param:setIP($address$)}} + +Sets the expected IP address to $address$. Can be dotted decimal quad for IPv4 and colon-separated hexadecimal for IPv6. The condensed "::" notation is supported for IPv6 addresses. + +\emph{Only supported since OpenSSL 1.1.0.} + +\end{Module} \begin{Module}{openssl.pkcs12} @@ -1457,6 +1559,37 @@ Applies DES\_set\_odd\_parity to the string $key$. Only the first 8 bytes of $ke \end{Module} +\begin{Module}{openssl.kdf} + +Binds OpenSSL's Key Derivation Function interfaces. + +\subsubsection[\fn{kdf.derive}]{\fn{kdf.derive($options$)}} + +Derive a key given the table of $options$, different KDF types require different options. Accepted options are: + +\begin{ctabular}{ c | c | p{5in}} +field & type & description\\\hline +.type & string & key derivation algorithm---``PBKDF2'', ``id-scrypt'', ``hkdf'', ``TLS-PRF1'' or other depending on your version of OpenSSL \\ +.outlen & number & the desired output size \\ +.pass & string & password \\ +.salt & string & salt \\ +.iter & number & iteration count \\ +.md & string & digest to use \\ +.key & string & key \\ +.maxmem\_bytes & number & amount of RAM key derivation may maximally use (in bytes) \\ +.secret & string & TLS1-PRF secret \\ +.seed & string & TLS1-PRF seed \\ +.hkdf\_mode & string & the HKDF mode to use, one of ``extract\_and\_expand'', ``extract\_only'' or ``expand\_only'' \\ +.info & string & HKDF info value \\ +.N & number & scrypt ``N'' parameter to use \\ +.r & number & scrypt ``r'' parameter to use \\ +.p & number & scrypt ``p'' parameter to use +\end{ctabular} + + +\end{Module} + + \chapter{Examples} These examples and others are made available under examples/ in the source tree. diff --git a/regress/167-verify-cert.lua b/regress/167-verify-cert.lua new file mode 100755 index 0000000..b7433e8 --- /dev/null +++ b/regress/167-verify-cert.lua @@ -0,0 +1,47 @@ +#!/usr/bin/env lua + +local regress = require "regress" + +if (regress.openssl.OPENSSL_VERSION_NUMBER and regress.openssl.OPENSSL_VERSION_NUMBER < 0x10002000) + or (regress.openssl.LIBRESSL_VERSION_NUMBER and regress.openssl.LIBRESSL_VERSION_NUMBER < 0x20705000) +then + -- skipping test due to different behaviour in earlier OpenSSL versions + return +end + +local params = regress.verify_param.new() +params:setDepth(0) + +local ca_key, ca_crt = regress.genkey() +do -- should fail as no trust anchor + regress.check(not ca_crt:verify({params=params, chain=nil, store=nil})) +end + +local store = regress.store.new() +store:add(ca_crt) +do -- should succeed as cert is in the store + regress.check(ca_crt:verify({params=params, chain=nil, store=store})) +end + +local intermediate_key, intermediate_crt = regress.genkey(nil, ca_key, ca_crt) +do -- should succeed as ca cert is in the store + regress.check(intermediate_crt:verify({params=params, chain=nil, store=store})) +end + +local _, crt = regress.genkey(nil, intermediate_key, intermediate_crt) +do -- should fail as intermediate cert is missing + regress.check(not crt:verify({params=params, chain=nil, store=store})) +end + +local chain = regress.chain.new() +chain:add(intermediate_crt) +do -- should fail as max depth is too low + regress.check(not crt:verify({params=params, chain=chain, store=store})) +end + +params:setDepth(1) +do -- should succeed + regress.check(crt:verify({params=params, chain=chain, store=store})) +end + +regress.say "OK" diff --git a/regress/95-kdf.lua b/regress/95-kdf.lua new file mode 100755 index 0000000..dd7cff4 --- /dev/null +++ b/regress/95-kdf.lua @@ -0,0 +1,45 @@ +#!/usr/bin/env lua + +local regress = require "regress" +local kdf = require "openssl.kdf" + +local function hexstring(str) + return (str:gsub("..", function(b) return string.char(tonumber(b, 16)) end)) +end + +-- Scrypt Example +regress.check(kdf.derive{ + type = "id-scrypt"; -- the nid short-name is id-scrypt + pass = ""; + salt = ""; + N = 16; + r = 1; + p = 1; + outlen = 64; +} == hexstring"77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906", + "scrypt output doesn't match test vector") + +-- PBKDF2 Example +regress.check(kdf.derive{ + type = "PBKDF2"; + pass = "password"; + salt = "salt"; + iter = 1; + md = "sha1"; + outlen = 20; +} == hexstring"0c60c80f961f0e71f3a9b524af6012062fe037a6", + "PBKDF2 output doesn't match test vector") + +-- TLS1-PRF Example +regress.check(kdf.derive{ + type = "TLS1-PRF"; + md = "md5-sha1"; + secret = hexstring"bded7fa5c1699c010be23dd06ada3a48349f21e5f86263d512c0c5cc379f0e780ec55d9844b2f1db02a96453513568d0"; + seed = "master secret" + .. hexstring"e5acaf549cd25c22d964c0d930fa4b5261d2507fad84c33715b7b9a864020693" + .. hexstring"135e4d557fdf3aa6406d82975d5c606a9734c9334b42136e96990fbd5358cdb2"; + outlen = 48; +} == hexstring"2f6962dfbc744c4b2138bb6b3d33054c5ecc14f24851d9896395a44ab3964efc2090c5bf51a0891209f46c1e1e998f62", + "TLS1-PRF output doesn't match test vector") + +regress.say "OK" diff --git a/regress/regress.lua b/regress/regress.lua index b89e996..5cdd22d 100644 --- a/regress/regress.lua +++ b/regress/regress.lua @@ -3,11 +3,14 @@ local require = require -- may be overloaded by regress.require local regress = { openssl = require"openssl", bignum = require"openssl.bignum", + kdf = require"openssl.kdf", pkey = require"openssl.pkey", x509 = require"openssl.x509", name = require"openssl.x509.name", altname = require"openssl.x509.altname", + chain = require"openssl.x509.chain", store = require"openssl.x509.store", + verify_param = require"openssl.x509.verify_param", pack = table.pack or function (...) local t = { ... } t.n = select("#", ...) 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 |