diff options
Diffstat (limited to 'src/openssl.c')
-rw-r--r-- | src/openssl.c | 575 |
1 files changed, 476 insertions, 99 deletions
diff --git a/src/openssl.c b/src/openssl.c index 9fc5b97..1b11207 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -75,7 +75,7 @@ #include <lualib.h> #include <lauxlib.h> -#include "compat52.h" +#include "../vendor/compat53/c-api/compat-5.3.h" #define GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p)) #define GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= GNUC_2VER((M), (m), (p))) @@ -83,11 +83,16 @@ #define MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p)) #define MSC_PREREQ(M, m, p) (_MSC_FULL_VER > 0 && _MSC_FULL_VER >= MSC_2VER((M), (m), (p))) -#define OPENSSL_PREREQ(M, m, p) \ - (OPENSSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12)) && !defined LIBRESSL_VERSION_NUMBER) - +#ifdef LIBRESSL_VERSION_NUMBER +#define OPENSSL_PREREQ(M, m, p) (0) #define LIBRESSL_PREREQ(M, m, p) \ (LIBRESSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12))) +#else +#define OPENSSL_PREREQ(M, m, p) \ + (OPENSSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12))) +#define LIBRESSL_PREREQ(M, m, p) (0) +#endif + #ifndef __has_builtin #define __has_builtin(x) 0 @@ -146,7 +151,11 @@ #endif #ifndef HAVE_DTLSV1_CLIENT_METHOD -#define HAVE_DTLSV1_CLIENT_METHOD (!defined OPENSSL_NO_DTLS1) +#ifdef OPENSSL_NO_DTLS1 +#define HAVE_DTLSV1_CLIENT_METHOD (0) +#else +#define HAVE_DTLSV1_CLIENT_METHOD (1) +#endif #endif #ifndef HAVE_DTLSV1_SERVER_METHOD @@ -154,7 +163,11 @@ #endif #ifndef HAVE_DTLS_CLIENT_METHOD -#define HAVE_DTLS_CLIENT_METHOD (OPENSSL_PREREQ(1,0,2) && !defined OPENSSL_NO_DTLS1) +#ifdef OPENSSL_NO_DTLS1 +#define HAVE_DTLS_CLIENT_METHOD (0) +#else +#define HAVE_DTLS_CLIENT_METHOD OPENSSL_PREREQ(1,0,2) +#endif #endif #ifndef HAVE_DTLS_SERVER_METHOD @@ -162,7 +175,11 @@ #endif #ifndef HAVE_DTLSV1_2_CLIENT_METHOD -#define HAVE_DTLSV1_2_CLIENT_METHOD (OPENSSL_PREREQ(1,0,2) && !defined OPENSSL_NO_DTLS1) +#ifdef OPENSSL_NO_DTLS1 +#define HAVE_DTLSV1_2_CLIENT_METHOD (0) +#else +#define HAVE_DTLSV1_2_CLIENT_METHOD OPENSSL_PREREQ(1,0,2) +#endif #endif #ifndef HAVE_DTLSV1_2_SERVER_METHOD @@ -229,10 +246,6 @@ #define HAVE_RSA_GET0_KEY OPENSSL_PREREQ(1,1,0) #endif -#ifndef HAVE_RSA_PKCS1_PSS_PADDING -#define HAVE_RSA_PKCS1_PSS_PADDING (defined RSA_PKCS1_PSS_PADDING || OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) -#endif - #ifndef HAVE_RSA_SET0_CRT_PARAMS #define HAVE_RSA_SET0_CRT_PARAMS OPENSSL_PREREQ(1,1,0) #endif @@ -253,6 +266,14 @@ #define HAVE_SSL_CTX_GET0_PARAM OPENSSL_PREREQ(1,0,2) #endif +#ifndef HAVE_SSL_CTX_SET_CURVES_LIST +#define HAVE_SSL_CTX_SET_CURVES_LIST (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,1)) +#endif + +#ifndef HAVE_SSL_CTX_SET_ECDH_AUTO +#define HAVE_SSL_CTX_SET_ECDH_AUTO ((OPENSSL_PREREQ(1,0,2) && !OPENSSL_PREREQ(1,1,0)) || LIBRESSL_PREREQ(2,1,2)) +#endif + #ifndef HAVE_SSL_CTX_SET_ALPN_PROTOS #define HAVE_SSL_CTX_SET_ALPN_PROTOS (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,1,3)) #endif @@ -261,6 +282,10 @@ #define HAVE_SSL_CTX_SET_ALPN_SELECT_CB HAVE_SSL_CTX_SET_ALPN_PROTOS #endif +#ifndef HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK +#define HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK OPENSSL_PREREQ(1,0,0) +#endif + #ifndef HAVE_SSL_CTX_SET1_CERT_STORE #define HAVE_SSL_CTX_SET1_CERT_STORE (HAVE_SSL_CTX_set1_cert_store || 0) /* backwards compatible with old macro name */ #endif @@ -293,6 +318,10 @@ #define HAVE_SSL_SET_ALPN_PROTOS HAVE_SSL_CTX_SET_ALPN_PROTOS #endif +#ifndef HAVE_SSL_SET_CURVES_LIST +#define HAVE_SSL_SET_CURVES_LIST (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,1)) +#endif + #ifndef HAVE_SSL_SET1_PARAM #define HAVE_SSL_SET1_PARAM OPENSSL_PREREQ(1,0,2) #endif @@ -309,12 +338,32 @@ #define HAVE_SSL_UP_REF OPENSSL_PREREQ(1,1,0) #endif -#ifndef HAVE_SSLV2_CLIENT_METHOD -#define HAVE_SSLV2_CLIENT_METHOD (!OPENSSL_PREREQ(1,1,0) && !defined OPENSSL_NO_SSL2) +#ifndef HAVE_SSL_OP_NO_SSL_MASK +#define HAVE_SSL_OP_NO_SSL_MASK OPENSSL_PREREQ(1,0,2) #endif -#ifndef HAVE_SSLV2_SERVER_METHOD -#define HAVE_SSLV2_SERVER_METHOD (!OPENSSL_PREREQ(1,1,0) && !defined OPENSSL_NO_SSL2) +#ifndef HAVE_SSL_OP_NO_DTLS_MASK +#define HAVE_SSL_OP_NO_DTLS_MASK OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_STACK_OPENSSL_STRING_FUNCS +#define HAVE_STACK_OPENSSL_STRING_FUNCS (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) +#endif + +#ifndef HAVE_X509_CRL_GET0_LASTUPDATE +#define HAVE_X509_CRL_GET0_LASTUPDATE OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_X509_CRL_GET0_NEXTUPDATE +#define HAVE_X509_CRL_GET0_NEXTUPDATE OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_X509_CRL_SET1_LASTUPDATE +#define HAVE_X509_CRL_SET1_LASTUPDATE OPENSSL_PREREQ(1,1,0) +#endif + +#ifndef HAVE_X509_CRL_SET1_NEXTUPDATE +#define HAVE_X509_CRL_SET1_NEXTUPDATE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_X509_GET_SIGNATURE_NID @@ -358,7 +407,11 @@ #endif #ifndef STRERROR_R_CHAR_P -#define STRERROR_R_CHAR_P (defined __GLIBC__ && (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600))) +#ifdef __GLIBC__ +#define STRERROR_R_CHAR_P (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)) +#else +#define STRERROR_R_CHAR_P (0) +#endif #endif #ifndef LIST_HEAD @@ -678,6 +731,44 @@ static void *loadfield_udata(lua_State *L, int index, const char *k, const char } /* loadfield_udata() */ +/* Forward declaration */ +static SSL *ssl_push(lua_State *, SSL *); + +/* push an ssl object into lua in a way that is safe from OOM + * Lua 5.1 does not support normally returning values from lua_cpcall + * to return a value, we instead return it via an error object + */ +static int ssl_pushsafe_helper(lua_State *L) { + ssl_push(L, lua_touserdata(L, 1)); +#if LUA_VERSION_NUM <= 501 + return lua_error(L); +#else + return 1; +#endif +} + +static int ssl_pushsafe(lua_State *L, SSL *ssl) { + int status; +#if LUA_VERSION_NUM <= 501 + status = lua_cpcall(L, ssl_pushsafe_helper, ssl); + if (status == LUA_ERRRUN) + status = LUA_OK; + else if (status == LUA_OK) + /* this should be impossible */ + status = LUA_ERRRUN; + else + lua_pop(L, 1); +#else + lua_pushcfunction(L, ssl_pushsafe_helper); + lua_pushlightuserdata(L, ssl); + status = lua_pcall(L, 1, 1, 0); + if (status != LUA_OK) + lua_pop(L, 1); +#endif + return status; +} + + /* * Auxiliary C routines * @@ -1623,6 +1714,22 @@ static int compat_SSL_up_ref(SSL *ssl) { } /* compat_SSL_up_ref() */ #endif +#if !HAVE_SSL_OP_NO_SSL_MASK +/* SSL_OP_NO_SSL_MASK was introduced in 1.0.2 + 1.0.1 had up to TLSv1_2 + 0.9.8-1.0.0 had up to TLSv1 +*/ +#ifdef SSL_OP_NO_TLSv1_2 +#define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2) +#else +#define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1) +#endif +#endif + +#if !HAVE_SSL_OP_NO_DTLS_MASK && HAVE_DTLS_CLIENT_METHOD +#define SSL_OP_NO_DTLS_MASK (SSL_OP_NO_DTLSv1|SSL_OP_NO_DTLSv1_2) +#endif + #if !HAVE_SSL_CTX_GET0_PARAM #define SSL_CTX_get0_param(ctx) compat_SSL_CTX_get0_param((ctx)) @@ -1639,6 +1746,12 @@ static int compat_SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) { } /* compat_SSL_CTX_set1_param() */ #endif +#if !HAVE_STACK_OPENSSL_STRING_FUNCS +#define sk_OPENSSL_STRING_num(s) sk_num(s) +#define sk_OPENSSL_STRING_value(s, i) sk_value((s), (i)) +#define sk_OPENSSL_STRING_free(s) X509_email_free(s) +#endif + #if !HAVE_X509_GET0_EXT #define X509_get0_ext(crt, i) X509_get_ext((crt), (i)) #endif @@ -1651,6 +1764,22 @@ static int compat_SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) { #define X509_CRL_get0_ext(crt, i) X509_CRL_get_ext((crt), (i)) #endif +#if !HAVE_X509_CRL_GET0_LASTUPDATE +#define X509_CRL_get0_lastUpdate(crl) ((const ASN1_TIME*)X509_CRL_get_lastUpdate(crl)) +#endif + +#if !HAVE_X509_CRL_GET0_NEXTUPDATE +#define X509_CRL_get0_nextUpdate(crl) ((const ASN1_TIME*)X509_CRL_get_nextUpdate(crl)) +#endif + +#if !HAVE_X509_CRL_SET1_LASTUPDATE +#define X509_CRL_set1_lastUpdate(crl, s) X509_CRL_set_lastUpdate((crl), (ASN1_TIME*)(s)) +#endif + +#if !HAVE_X509_CRL_SET1_NEXTUPDATE +#define X509_CRL_set1_nextUpdate(crl, s) X509_CRL_set_nextUpdate((crl), (ASN1_TIME*)(s)) +#endif + #if !HAVE_X509_EXTENSION_GET0_OBJECT #define X509_EXTENSION_get0_object(ext) X509_EXTENSION_get_object((ext)) #endif @@ -1784,6 +1913,7 @@ static int compat_init(void) { if (done) goto epilog; +#if defined compat_X509_STORE_free /* * We need to unconditionally install at least one external * application data callback. Because these can never be @@ -1792,7 +1922,6 @@ static int compat_init(void) { if ((error = dl_anchor())) goto epilog; -#if defined compat_X509_STORE_free /* * Test if X509_STORE_free obeys reference counts by installing an * onfree callback. @@ -1929,6 +2058,7 @@ struct ex_data { enum { EX_SSL_CTX_ALPN_SELECT_CB, + EX_SSL_CTX_TLSEXT_SERVERNAME_CB, }; static struct ex_type { @@ -1938,6 +2068,7 @@ static struct ex_type { int (*set_ex_data)(); } ex_type[] = { [EX_SSL_CTX_ALPN_SELECT_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, + [EX_SSL_CTX_TLSEXT_SERVERNAME_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, }; #if OPENSSL_PREREQ(1,1,0) @@ -3081,7 +3212,8 @@ static int pk_new(lua_State *L) { if (lua_istable(L, 1) || lua_isnil(L, 1)) { int type = EVP_PKEY_RSA; unsigned bits = 1024; - unsigned exp = 65537; + BIGNUM *exp = NULL; + int generator = 2; int curve = NID_X9_62_prime192v1; const char *id; const char *dhparam = NULL; @@ -3111,23 +3243,46 @@ static int pk_new(lua_State *L) { luaL_argcheck(L, type != NID_undef, 1, lua_pushfstring(L, "%s: invalid key type", id)); } - if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { - luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); - bits = (unsigned)n; - } + switch(type) { + case EVP_PKEY_RSA: + if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { + luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); + bits = (unsigned)n; + } - if (loadfield(L, 1, "exp", LUA_TNUMBER, &n)) { - luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `exp' invalid", n)); - exp = (unsigned)n; - } + if (!getfield(L, 1, "exp")) { + exp = checkbig(L, -1); + } else { + /* default to 65537 */ + exp = bn_push(L); + if (!BN_add_word(exp, 65537)) + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + } + break; + case EVP_PKEY_DH: + /* dhparam field can contain a PEM encoded string. + The "dhparam" field takes precedence over "bits" */ + if (loadfield(L, 1, "dhparam", LUA_TSTRING, &dhparam)) + break; - if (loadfield(L, 1, "curve", LUA_TSTRING, &id)) { - if (!auxS_txt2nid(&curve, id)) - luaL_argerror(L, 1, lua_pushfstring(L, "%s: invalid curve", id)); - } + if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { + luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); + bits = (unsigned)n; + } - /* dhparam field can contain a PEM encoded string. */ - loadfield(L, 1, "dhparam", LUA_TSTRING, &dhparam); + /* compat: DH used to use the 'exp' field for the generator */ + if (loadfield(L, 1, "generator", LUA_TNUMBER, &n) || loadfield(L, 1, "exp", LUA_TNUMBER, &n)) { + luaL_argcheck(L, n > 0 && n <= INT_MAX, 1, lua_pushfstring(L, "%f: `exp' invalid", n)); + generator = (int)n; + } + break; + case EVP_PKEY_EC: + if (loadfield(L, 1, "curve", LUA_TSTRING, &id)) { + if (!auxS_txt2nid(&curve, id)) + luaL_argerror(L, 1, lua_pushfstring(L, "%s: invalid curve", id)); + } + break; + } creat: if (!(*ud = EVP_PKEY_new())) @@ -3137,9 +3292,14 @@ creat: case EVP_PKEY_RSA: { RSA *rsa; - if (!(rsa = RSA_generate_key(bits, exp, 0, 0))) + if (!(rsa = RSA_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + if (!RSA_generate_key_ex(rsa, bits, exp, 0)) { + RSA_free(rsa); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + } + EVP_PKEY_set1_RSA(*ud, rsa); RSA_free(rsa); @@ -3149,9 +3309,14 @@ creat: case EVP_PKEY_DSA: { DSA *dsa; - if (!(dsa = DSA_generate_parameters(bits, 0, 0, 0, 0, 0, 0))) + if (!(dsa = DSA_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + if (!DSA_generate_parameters_ex(dsa, bits, 0, 0, 0, 0, 0)) { + DSA_free(dsa); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + } + if (!DSA_generate_key(dsa)) { DSA_free(dsa); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); @@ -3179,8 +3344,15 @@ creat: BIO_free(bio); if (!dh) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); - } else if (!(dh = DH_generate_parameters(bits, exp, 0, 0))) - return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + } else { + if (!(dh = DH_new())) + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + + if (!DH_generate_parameters_ex(dh, bits, generator, 0)) { + DH_free(dh); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); + } + } if (!DH_generate_key(dh)) { @@ -4319,7 +4491,7 @@ static const auxL_IntegerReg pk_rsa_pad_opts[] = { { "RSA_NO_PADDING", RSA_NO_PADDING }, // no padding { "RSA_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING }, // OAEP padding (encrypt and decrypt only) { "RSA_X931_PADDING", RSA_X931_PADDING }, // (signature operations only) -#if HAVE_RSA_PKCS1_PSS_PADDING +#if RSA_PKCS1_PSS_PADDING { "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING }, // (sign and verify only) #endif { NULL, 0 }, @@ -5523,17 +5695,17 @@ static _Bool scan(int *i, char **cp, int n, int signok) { } /* scan() */ -static double timeutc(ASN1_TIME *time) { +static double timeutc(const ASN1_TIME *time) { char buf[32] = "", *cp; struct tm tm = { 0 }; int gmtoff = 0, year, i; - if (!ASN1_TIME_check(time)) + if (!ASN1_TIME_check((ASN1_STRING *)time)) return 0; cp = strncpy(buf, (const char *)ASN1_STRING_get0_data((ASN1_STRING *)time), sizeof buf - 1); - if (ASN1_STRING_type(time) == V_ASN1_GENERALIZEDTIME) { + if (ASN1_STRING_type((ASN1_STRING *)time) == V_ASN1_GENERALIZEDTIME) { if (!scan(&year, &cp, 4, 1)) goto badfmt; } else { @@ -5595,7 +5767,7 @@ badfmt: static int xc_getLifetime(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); double begin = INFINITY, end = INFINITY; - ASN1_TIME *time; + const ASN1_TIME *time; if ((time = X509_get_notBefore(crt))) begin = timeutc(time); @@ -6684,10 +6856,21 @@ static int xx_new(lua_State *L) { if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); } else { + ASN1_TIME *tm; + if (!(*ud = X509_CRL_new())) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); - X509_gmtime_adj(X509_CRL_get_lastUpdate(*ud), 0); + /* initialize last updated time to now */ + if (!(tm = ASN1_TIME_set(NULL, time(NULL)))) + return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); + + if (!X509_CRL_set1_lastUpdate(*ud, tm)) { + ASN1_TIME_free(tm); + return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); + } + + ASN1_TIME_free(tm); } return 1; @@ -6724,9 +6907,9 @@ static int xx_setVersion(lua_State *L) { static int xx_getLastUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updated = INFINITY; - ASN1_TIME *time; + const ASN1_TIME *time; - if ((time = X509_CRL_get_lastUpdate(crl))) + if ((time = X509_CRL_get0_lastUpdate(crl))) updated = timeutc(time); if (isfinite(updated)) @@ -6741,23 +6924,30 @@ static int xx_getLastUpdate(lua_State *L) { static int xx_setLastUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updated = luaL_checknumber(L, 2); + ASN1_TIME *time; - /* lastUpdate always present */ - if (!ASN1_TIME_set(X509_CRL_get_lastUpdate(crl), updated)) - return auxL_error(L, auxL_EOPENSSL, "x509.crl:setLastUpdate"); + if (!(time = ASN1_TIME_set(NULL, updated))) + goto error; + + if (!X509_CRL_set1_lastUpdate(crl, time)) + goto error; lua_pushboolean(L, 1); return 1; +error: + ASN1_TIME_free(time); + + return auxL_error(L, auxL_EOPENSSL, "x509.crl:setLastUpdate"); } /* xx_setLastUpdate() */ static int xx_getNextUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updateby = INFINITY; - ASN1_TIME *time; + const ASN1_TIME *time; - if ((time = X509_CRL_get_nextUpdate(crl))) + if ((time = X509_CRL_get0_nextUpdate(crl))) updateby = timeutc(time); if (isfinite(updateby)) @@ -6772,30 +6962,19 @@ static int xx_getNextUpdate(lua_State *L) { static int xx_setNextUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updateby = luaL_checknumber(L, 2); - ASN1_TIME *time = NULL; - - if (X509_CRL_get_nextUpdate(crl)) { - if (!ASN1_TIME_set(X509_CRL_get_nextUpdate(crl), updateby)) - goto error; - } else { - if (!(time = ASN1_TIME_new())) - goto error; - - if (!(ASN1_TIME_set(time, updateby))) - goto error; + ASN1_TIME *time; - if (!X509_CRL_set_nextUpdate(crl, time)) - goto error; + if (!(time = ASN1_TIME_set(NULL, updateby))) + goto error; - time = NULL; - } + if (!X509_CRL_set1_nextUpdate(crl, time)) + goto error; lua_pushboolean(L, 1); return 1; error: - if (time) - ASN1_TIME_free(time); + ASN1_TIME_free(time); return auxL_error(L, auxL_EOPENSSL, "x509.crl:setNextUpdate"); } /* xx_setNextUpdate() */ @@ -7670,11 +7849,6 @@ int luaopen__openssl_pkcs12(lua_State *L) { * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * NOTE: TLS methods and flags were added in tandem. For example, if the - * macro SSL_OP_NO_TLSv1_1 is defined we know TLSv1_1_server_method is also - * declared and defined. - */ static int sx_new(lua_State *L) { static const char *const opts[] = { [0] = "SSL", @@ -7690,81 +7864,109 @@ static int sx_new(lua_State *L) { [14] = "DTLSv1_2", [15] = "DTLSv1.2", NULL }; - /* later versions of SSL declare a const qualifier on the return type */ - __typeof__(&TLSv1_client_method) method = &TLSv1_client_method; + int method_enum; _Bool srv; SSL_CTX **ud; int options = 0; lua_settop(L, 2); + method_enum = auxL_checkoption(L, 1, "TLS", opts, 1); srv = lua_toboolean(L, 2); - switch (auxL_checkoption(L, 1, "TLS", opts, 1)) { + switch (method_enum) { case 0: /* SSL */ - method = (srv)? &SSLv23_server_method : &SSLv23_client_method; options = SSL_OP_NO_SSLv2; break; case 1: /* TLS */ - method = (srv)? &SSLv23_server_method : &SSLv23_client_method; options = SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; break; -#if HAVE_SSLV2_CLIENT_METHOD && HAVE_SSLV2_SERVER_METHOD case 2: /* SSLv2 */ - method = (srv)? &SSLv2_server_method : &SSLv2_client_method; + options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_SSLv2; break; -#endif -#ifndef OPENSSL_NO_SSL3 case 3: /* SSLv3 */ - method = (srv)? &SSLv3_server_method : &SSLv3_client_method; + options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_SSLv3; break; -#endif case 4: /* SSLv23 */ - method = (srv)? &SSLv23_server_method : &SSLv23_client_method; break; case 5: /* TLSv1 */ case 6: /* TLSv1.0 */ - method = (srv)? &TLSv1_server_method : &TLSv1_client_method; + options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1; break; #if defined SSL_OP_NO_TLSv1_1 case 7: /* TLSv1_1 */ case 8: /* TLSv1.1 */ - method = (srv)? &TLSv1_1_server_method : &TLSv1_1_client_method; + options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1_1; break; #endif #if defined SSL_OP_NO_TLSv1_2 case 9: /* TLSv1_2 */ case 10: /* TLSv1.2 */ - method = (srv)? &TLSv1_2_server_method : &TLSv1_2_client_method; + options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1_2; break; #endif #if HAVE_DTLS_CLIENT_METHOD case 11: /* DTLS */ - method = (srv)? &DTLS_server_method : &DTLS_client_method; break; -#endif -#if HAVE_DTLSV1_CLIENT_METHOD +#ifdef SSL_OP_NO_DTLSv1 case 12: /* DTLSv1 */ case 13: /* DTLSv1.0 */ - method = (srv)? &DTLSv1_server_method : &DTLSv1_client_method; + options = SSL_OP_NO_DTLS_MASK & ~SSL_OP_NO_DTLSv1; break; #endif -#if HAVE_DTLSV1_2_CLIENT_METHOD +#ifdef SSL_OP_NO_DTLSv1_2 case 14: /* DTLSv1_2 */ case 15: /* DTLSv1.2 */ - method = (srv)? &DTLSv1_server_method : &DTLSv1_client_method; + options = SSL_OP_NO_DTLS_MASK & ~SSL_OP_NO_DTLSv1_2; break; #endif +#endif default: return luaL_argerror(L, 1, "invalid option"); } ud = prepsimple(L, SSL_CTX_CLASS); - if (!(*ud = SSL_CTX_new(method()))) + switch (method_enum) { + case 0: /* SSL */ + case 1: /* TLS */ + case 2: /* SSLv2 */ + case 3: /* SSLv3 */ + case 4: /* SSLv23 */ + case 5: /* TLSv1 */ + case 6: /* TLSv1.0 */ + case 7: /* TLSv1_1 */ + case 8: /* TLSv1.1 */ + case 9: /* TLSv1_2 */ + case 10: /* TLSv1.2 */ + *ud = SSL_CTX_new(srv?SSLv23_server_method():SSLv23_client_method()); + break; +#if HAVE_DTLS_CLIENT_METHOD + case 11: /* DTLS */ + case 12: /* DTLSv1 */ + case 13: /* DTLSv1.0 */ + case 14: /* DTLSv1_2 */ + case 15: /* DTLSv1.2 */ + *ud = SSL_CTX_new(srv?DTLS_server_method():DTLS_client_method()); + break; +#endif + default: + NOTREACHED; + } + + if (!*ud) return auxL_error(L, auxL_EOPENSSL, "ssl.context.new"); SSL_CTX_set_options(*ud, options); +#if HAVE_SSL_CTX_SET_ECDH_AUTO + /* OpenSSL 1.0.2 introduced SSL_CTX_set_ecdh_auto to automatically select + * from the curves set via SSL_CTX_set1_curves_list. However as of OpenSSL + * 1.1.0, the functionality was turned on permanently and the option + * removed. */ + if (!SSL_CTX_set_ecdh_auto(*ud, 1)) + return auxL_error(L, auxL_EOPENSSL, "ssl.context.new"); +#endif + return 1; } /* sx_new() */ @@ -7940,6 +8142,21 @@ static int sx_setCipherList(lua_State *L) { } /* sx_setCipherList() */ +#if HAVE_SSL_CTX_SET_CURVES_LIST +static int sx_setCurvesList(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + const char *curves = luaL_checkstring(L, 2); + + if (!SSL_CTX_set1_curves_list(ctx, curves)) + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCurvesList"); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setCurvesList() */ +#endif + + static int sx_setEphemeralKey(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); @@ -8013,9 +8230,8 @@ static int sx_setAlpnProtos(lua_State *L) { } /* sx_setAlpnProtos() */ #endif -#if HAVE_SSL_CTX_SET_ALPN_SELECT_CB -static SSL *ssl_push(lua_State *, SSL *); +#if HAVE_SSL_CTX_SET_ALPN_SELECT_CB static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *_ctx) { SSL_CTX *ctx = _ctx; lua_State *L = NULL; @@ -8033,12 +8249,12 @@ static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned cha otop = lua_gettop(L) - n; - /* TODO: Install temporary panic handler to catch OOM errors */ - /* pass SSL object as 1st argument */ - ssl_push(L, ssl); + if (ssl_pushsafe(L, ssl)) + goto fatal; lua_insert(L, otop + 3); + /* TODO: Install temporary panic handler to catch OOM errors */ /* pass table of protocol names as 2nd argument */ pushprotos(L, in, inlen); lua_insert(L, otop + 4); @@ -8110,6 +8326,74 @@ static int sx_setAlpnSelect(lua_State *L) { #endif +#if HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK +static int sx_setHostNameCallback_cb(SSL *ssl, int *ad, void *_ctx) { + SSL_CTX *ctx = _ctx; + lua_State *L = NULL; + size_t n; + int otop, status, ret = SSL_TLSEXT_ERR_ALERT_FATAL; + + *ad = SSL_AD_INTERNAL_ERROR; + + /* expect at least one value: closure */ + if ((n = ex_getdata(&L, EX_SSL_CTX_TLSEXT_SERVERNAME_CB, ctx)) < 1) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + otop = lua_gettop(L) - n; + + /* pass SSL object as 1st argument */ + if (ssl_pushsafe(L, ssl)) + goto done; + + lua_insert(L, otop + 2); + + if (LUA_OK != (status = lua_pcall(L, 1 + (n - 1), 2, 0))) + goto done; + + /* callback should return a boolean for OK/NOACK + * or nil + an integer for a controlled error + * everything else will be a fatal internal error + */ + if (lua_isboolean(L, -2)) { + ret = lua_toboolean(L, -2) ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK; + } else { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + if (lua_isnil(L, -2) && lua_isinteger(L, -1)) + *ad = lua_tointeger(L, -1); + } + +done: + lua_settop(L, otop); + + return ret; +} /* sx_setHostNameCallback_cb() */ + + +static int sx_setHostNameCallback(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + int error; + + luaL_checktype(L, 2, LUA_TFUNCTION); + + if ((error = ex_setdata(L, EX_SSL_CTX_TLSEXT_SERVERNAME_CB, ctx, lua_gettop(L) - 1))) { + if (error > 0) { + return luaL_error(L, "unable to set hostname selection callback: %s", aux_strerror(error)); + } else if (error == auxL_EOPENSSL && !ERR_peek_error()) { + return luaL_error(L, "unable to set hostname selection callback: Unknown internal error"); + } else { + return auxL_error(L, error, "ssl.context:setHostNameCallback"); + } + } + SSL_CTX_set_tlsext_servername_callback(ctx, sx_setHostNameCallback_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, ctx); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setHostNameCallback() */ +#endif + + int TLSEXT_STATUSTYPEs[] = { TLSEXT_STATUSTYPE_ocsp }; const char *TLSEXT_STATUSTYPEs_names[] = { "ocsp", NULL }; #define checkTLSEXT_STATUSTYPE(L, idx) \ @@ -8122,7 +8406,7 @@ static int sx_setTLSextStatusType(lua_State *L) { int type = checkTLSEXT_STATUSTYPE(L, 2); if(!SSL_CTX_set_tlsext_status_type(ctx, type)) - return auxL_error(L, auxL_EOPENSSL, "ssl:setTLSextStatusType"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setTLSextStatusType"); lua_pushboolean(L, 1); @@ -8177,6 +8461,9 @@ static const auxL_Reg sx_methods[] = { { "setCertificate", &sx_setCertificate }, { "setPrivateKey", &sx_setPrivateKey }, { "setCipherList", &sx_setCipherList }, +#if HAVE_SSL_CTX_SET_CURVES_LIST + { "setCurvesList", &sx_setCurvesList }, +#endif { "setEphemeralKey", &sx_setEphemeralKey }, #if HAVE_SSL_CTX_SET_ALPN_PROTOS { "setAlpnProtos", &sx_setAlpnProtos }, @@ -8184,6 +8471,9 @@ static const auxL_Reg sx_methods[] = { #if HAVE_SSL_CTX_SET_ALPN_SELECT_CB { "setAlpnSelect", &sx_setAlpnSelect }, #endif +#if HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK + { "setHostNameCallback", &sx_setHostNameCallback }, +#endif #if HAVE_SSL_CTX_SET_TLSEXT_STATUS_TYPE { "setTLSextStatusType", &sx_setTLSextStatusType }, #endif @@ -8374,6 +8664,33 @@ static int ssl_getParam(lua_State *L) { } /* ssl_getParam() */ +static int ssl_setVerify(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + int mode = luaL_optinteger(L, 2, -1); + int depth = luaL_optinteger(L, 3, -1); + + if (mode != -1) + SSL_set_verify(ssl, mode, 0); + + if (depth != -1) + SSL_set_verify_depth(ssl, depth); + + lua_pushboolean(L, 1); + + return 1; +} /* ssl_setVerify() */ + + +static int ssl_getVerify(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + + lua_pushinteger(L, SSL_get_verify_mode(ssl)); + lua_pushinteger(L, SSL_get_verify_depth(ssl)); + + return 2; +} /* ssl_getVerify() */ + + static int ssl_getVerifyResult(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); long res = SSL_get_verify_result(ssl); @@ -8383,6 +8700,44 @@ static int ssl_getVerifyResult(lua_State *L) { } /* ssl_getVerifyResult() */ +static int ssl_setCertificate(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + X509 *crt = X509_dup(checksimple(L, 2, X509_CERT_CLASS)); + int ok; + + ok = SSL_use_certificate(ssl, crt); + X509_free(crt); + + if (!ok) + return auxL_error(L, auxL_EOPENSSL, "ssl:setCertificate"); + + lua_pushboolean(L, 1); + + return 1; +} /* ssl_setCertificate() */ + + +static int ssl_setPrivateKey(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); + /* + * NOTE: No easy way to dup the key, but a shared reference should + * be okay as keys are less mutable than certificates. + * + * FIXME: SSL_use_PrivateKey will return true even if the + * EVP_PKEY object has no private key. Instead, we'll just get a + * segfault during the SSL handshake. We need to check that a + * private key is actually defined in the object. + */ + if (!SSL_use_PrivateKey(ssl, key)) + return auxL_error(L, auxL_EOPENSSL, "ssl:setPrivateKey"); + + lua_pushboolean(L, 1); + + return 1; +} /* ssl_setPrivateKey() */ + + static int ssl_getPeerCertificate(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509 **x509 = prepsimple(L, X509_CERT_CLASS); @@ -8433,6 +8788,21 @@ static int ssl_getCipherInfo(lua_State *L) { } /* ssl_getCipherInfo() */ +#if HAVE_SSL_SET_CURVES_LIST +static int ssl_setCurvesList(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + const char *curves = luaL_checkstring(L, 2); + + if (!SSL_set1_curves_list(ssl, curves)) + return auxL_error(L, auxL_EOPENSSL, "ssl:setCurvesList"); + + lua_pushboolean(L, 1); + + return 1; +} /* ssl_setCurvesList() */ +#endif + + static int ssl_getHostName(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const char *host; @@ -8679,10 +9049,17 @@ static const auxL_Reg ssl_methods[] = { { "clearOptions", &ssl_clearOptions }, { "setParam", &ssl_setParam }, { "getParam", &ssl_getParam }, + { "setVerify", &ssl_setVerify }, + { "getVerify", &ssl_getVerify }, { "getVerifyResult", &ssl_getVerifyResult }, + { "setCertificate", &ssl_setCertificate }, + { "setPrivateKey", &ssl_setPrivateKey }, { "getPeerCertificate", &ssl_getPeerCertificate }, { "getPeerChain", &ssl_getPeerChain }, { "getCipherInfo", &ssl_getCipherInfo }, +#if HAVE_SSL_SET_CURVES_LIST + { "setCurvesList", &ssl_setCurvesList }, +#endif { "getHostName", &ssl_getHostName }, { "setHostName", &ssl_setHostName }, { "getVersion", &ssl_getVersion }, |