diff options
-rw-r--r-- | src/openssl.c | 199 |
1 files changed, 155 insertions, 44 deletions
diff --git a/src/openssl.c b/src/openssl.c index d4f75aa..ee2cd68 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -77,12 +77,38 @@ #include "compat52.h" #endif +#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))) + +#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) #define LIBRESSL_PREREQ(M, m, p) \ (LIBRESSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12))) +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_extension +#define __has_extension(x) 0 +#endif + +#ifndef HAVE_C___ASSUME +#define HAVE_C___ASSUME MSC_PREREQ(8,0,0) +#endif + +#ifndef HAVE_C___BUILTIN_UNREACHABLE +#define HAVE_C___BUILTIN_UNREACHABLE (GNUC_PREREQ(4,5,0) || __has_builtin(__builtin_unreachable)) +#endif + +#ifndef HAVE_C___DECLSPEC_NORETURN +#define HAVE_C___DECLSPEC_NORETURN MSC_PREREQ(8,0,0) +#endif + #ifndef HAVE_ASN1_STRING_GET0_DATA #define HAVE_ASN1_STRING_GET0_DATA OPENSSL_PREREQ(1,1,0) #endif @@ -316,6 +342,13 @@ #define NOTUSED #endif +#if HAVE_C___BUILTIN_UNREACHABLE +#define NOTREACHED __builtin_unreachable() +#elif HAVE_C___ASSUME +#define NOTREACHED __assume(0) +#else +#define NOTREACHED (void)0 +#endif #define countof(a) (sizeof (a) / sizeof *(a)) #define endof(a) (&(a)[countof(a)]) @@ -710,6 +743,8 @@ static size_t auxS_obj2txt(void *dst, size_t lim, const ASN1_OBJECT *obj) { return auxS_obj2id(dst, lim, obj); } /* auxS_obj2txt() */ +static const EVP_MD *auxS_todigest(const char *name, EVP_PKEY *key, const EVP_MD *def); + static _Bool auxS_isoid(const char *txt) { return (*txt >= '0' && *txt <= '9'); } /* auxS_isoid() */ @@ -1096,8 +1131,9 @@ static const char *auxL_pusherror(lua_State *L, int error, const char *fun) { static int auxL_error(lua_State *L, int error, const char *fun) { auxL_pusherror(L, error, fun); - - return lua_error(L); + lua_error(L); + NOTREACHED; + return 0; } /* auxL_error() */ static const char *auxL_pushnid(lua_State *L, int nid) { @@ -1112,6 +1148,8 @@ static const char *auxL_pushnid(lua_State *L, int nid) { return lua_tostring(L, -1); } /* auxL_pushnid() */ +static const EVP_MD *auxL_optdigest(lua_State *L, int index, EVP_PKEY *key, const EVP_MD *def); + /* * dl - dynamically loaded module management @@ -1704,6 +1742,53 @@ sslerr: /* + * Auxiliary OpenSSL API routines (with dependencies on OpenSSL compat) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static const EVP_MD *auxS_todigest(const char *name, EVP_PKEY *key, const EVP_MD *def) { + const EVP_MD *md; + int nid; + + if (name) { + if ((md = EVP_get_digestbyname(name))) + return md; + } else if (key) { + if ((EVP_PKEY_get_default_digest_nid(key, &nid) > 0)) { + if ((md = EVP_get_digestbynid(nid))) + return md; + } + } + + return def; +} /* auxS_todigest() */ + + +/* + * Auxiliary Lua API routines (with dependencies on OpenSSL compat) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static const EVP_MD *auxL_optdigest(lua_State *L, int index, EVP_PKEY *key, const EVP_MD *def) { + const char *name = luaL_optstring(L, index, NULL); + const EVP_MD *md; + + if ((md = auxS_todigest(name, key, NULL))) + return md; + + if (name) { + luaL_argerror(L, index, lua_pushfstring(L, "invalid digest type (%s)", name)); + NOTREACHED; + } else if (key) { + luaL_argerror(L, index, lua_pushfstring(L, "no digest type for key type (%d)", EVP_PKEY_base_id(key))); + NOTREACHED; + } + + return def; +} /* auxL_optdigest() */ + + +/* * External Application Data Hooks * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -3353,18 +3438,11 @@ static int pk_toPEM(lua_State *L) { static int pk_getDefaultDigestName(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int nid; - char txt[256]; - size_t len; if (!(EVP_PKEY_get_default_digest_nid(key, &nid) > 0)) return auxL_error(L, auxL_EOPENSSL, "pkey:getDefaultDigestName"); - if (!(len = auxS_nid2txt(txt, sizeof txt, nid))) - return auxL_error(L, auxL_EOPENSSL, "pkey:getDefaultDigestName"); - if (len > sizeof txt) - return auxL_error(L, EOVERFLOW, "pkey:getDefaultDigestName"); - - lua_pushlstring(L, txt, len); + auxL_pushnid(L, nid); return 1; } /* pk_getDefaultDigestName() */ @@ -5672,49 +5750,50 @@ static int xc_setPublicKey(lua_State *L) { static int xc_getPublicKeyDigest(lua_State *L) { - ASN1_BIT_STRING *pk = X509_get0_pubkey_bitstr(checksimple(L, 1, X509_CERT_CLASS)); - const char *id = luaL_optstring(L, 2, "sha1"); + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + EVP_PKEY *key; const EVP_MD *md; + ASN1_BIT_STRING *bitstr; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int len; - if (!(md = EVP_get_digestbyname(id))) - return luaL_error(L, "x509.cert:getPublicKeyDigest: %s: invalid digest type", id); + if (!(key = X509_get_pubkey(crt))) + return luaL_argerror(L, 1, "no public key"); + md = auxL_optdigest(L, 2, key, NULL); + bitstr = X509_get0_pubkey_bitstr(crt); - if (!EVP_Digest(pk->data, pk->length, digest, &len, md, NULL)) + if (!EVP_Digest(bitstr->data, bitstr->length, digest, &len, md, NULL)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:getPublicKeyDigest"); - lua_pushlstring(L, (char *)digest, len); return 1; } /* xc_getPublicKeyDigest() */ -static const EVP_MD *xc_signature(lua_State *L, int index, EVP_PKEY *key) { - const char *id; - const EVP_MD *md; +#if 0 +/* + * TODO: X509_get_signature_type always seems to return NID_undef. Are we + * using it wrong or is it broken? + */ +static int xc_getSignatureName(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); int nid; - if ((id = luaL_optstring(L, index, NULL))) { - if (!(md = EVP_get_digestbyname(id))) - goto unknown; - } else { - if (!(EVP_PKEY_get_default_digest_nid(key, &nid) > 0)) - goto unknown; - if (!(md = EVP_get_digestbynid(nid))) - goto unknown; - } + if (NID_undef == (nid = X509_get_signature_type(crt))) + return 0; + + auxL_pushnid(L, nid); + + return 1; +} /* xc_getSignatureName() */ +#endif - return md; -unknown: - return EVP_sha1(); -} /* xc_signature() */ static int xc_sign(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); - if (!X509_sign(crt, key, xc_signature(L, 3, key))) + if (!X509_sign(crt, key, auxL_optdigest(L, 3, key, NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.cert:sign"); lua_pushboolean(L, 1); @@ -5854,6 +5933,9 @@ static const auxL_Reg xc_methods[] = { { "getPublicKey", &xc_getPublicKey }, { "setPublicKey", &xc_setPublicKey }, { "getPublicKeyDigest", &xc_getPublicKeyDigest }, +#if 0 + { "getSignatureName", &xc_getSignatureName }, +#endif { "sign", &xc_sign }, { "text", &xc_text }, { "tostring", &xc__tostring }, @@ -6107,7 +6189,7 @@ static int xr_sign(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); - if (!X509_REQ_sign(csr, key, xc_signature(L, 3, key))) + if (!X509_REQ_sign(csr, key, auxL_optdigest(L, 3, key, NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.csr:sign"); lua_pushboolean(L, 1); @@ -6482,7 +6564,7 @@ static int xx_sign(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); - if (!X509_CRL_sign(crl, key, xc_signature(L, 3, key))) + if (!X509_CRL_sign(crl, key, auxL_optdigest(L, 3, key, NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.crl:sign"); lua_pushboolean(L, 1); @@ -6778,17 +6860,24 @@ static int xs_interpose(lua_State *L) { static int xs_add(lua_State *L) { X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); int i, top = lua_gettop(L); + X509 *crt, *crt_dup; + X509_CRL *crl, *crl_dup; for (i = 2; i <= top; i++) { - if (lua_isuserdata(L, i)) { - X509 *crt = checksimple(L, i, X509_CERT_CLASS); - X509 *dup; + if ((crt = testsimple(L, i, X509_CERT_CLASS))) { + if (!(crt_dup = X509_dup(crt))) + return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); - if (!(dup = X509_dup(crt))) + if (!X509_STORE_add_cert(store, crt_dup)) { + X509_free(crt_dup); + return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); + } + } else if ((crl = testsimple(L, i, X509_CRL_CLASS))) { + if (!(crl_dup = X509_CRL_dup(crl))) return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); - if (!X509_STORE_add_cert(store, dup)) { - X509_free(dup); + if (!X509_STORE_add_crl(store, crl_dup)) { + X509_CRL_free(crl_dup); return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); } } else { @@ -6815,6 +6904,18 @@ static int xs_add(lua_State *L) { } /* xs_add() */ +static int xs_addDefaults(lua_State *L) { + X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); + + if (!X509_STORE_set_default_paths(store)) + return auxL_error(L, auxL_EOPENSSL, "x509.store:addDefaults"); + + lua_pushvalue(L, 1); + + return 1; +} /* xs_addDefaults() */ + + static int xs_verify(lua_State *L) { X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); X509 *crt = checksimple(L, 2, X509_CERT_CLASS); @@ -6897,9 +6998,10 @@ static int xs__gc(lua_State *L) { static const auxL_Reg xs_methods[] = { - { "add", &xs_add }, - { "verify", &xs_verify }, - { NULL, NULL }, + { "add", &xs_add }, + { "addDefaults", &xs_addDefaults }, + { "verify", &xs_verify }, + { NULL, NULL }, }; static const auxL_Reg xs_metatable[] = { @@ -6918,6 +7020,15 @@ int luaopen__openssl_x509_store(lua_State *L) { auxL_newlib(L, xs_globals, 0); + lua_pushstring(L, X509_get_default_cert_dir()); + lua_setfield(L, -2, "CERT_DIR"); + lua_pushstring(L, X509_get_default_cert_file()); + lua_setfield(L, -2, "CERT_FILE"); + lua_pushstring(L, X509_get_default_cert_dir_env()); + lua_setfield(L, -2, "CERT_DIR_EVP"); + lua_pushstring(L, X509_get_default_cert_file_env()); + lua_setfield(L, -2, "CERT_FILE_EVP"); + return 1; } /* luaopen__openssl_x509_store() */ |