diff options
author | daurnimator <quae@daurnimator.com> | 2019-06-12 13:21:40 +1000 |
---|---|---|
committer | daurnimator <quae@daurnimator.com> | 2019-06-12 13:21:40 +1000 |
commit | 7faf03f7efeffc6a97eaf351930cdc3806c52270 (patch) | |
tree | 30fce6ecd311ce43270dc3899569abf2decec656 | |
parent | feb050aeec4301f6febd576bf8321bd81eaf5e42 (diff) | |
parent | 1e91b246c8696f9b51c1d64a60218fac2c016dda (diff) | |
download | luaossl-7faf03f7efeffc6a97eaf351930cdc3806c52270.tar.gz luaossl-7faf03f7efeffc6a97eaf351930cdc3806c52270.tar.bz2 luaossl-7faf03f7efeffc6a97eaf351930cdc3806c52270.zip |
Merge branch 'x509-verify'
-rw-r--r-- | doc/luaossl.pdf | bin | 313323 -> 174953 bytes | |||
-rw-r--r-- | doc/luaossl.tex | 13 | ||||
-rwxr-xr-x | regress/167-verify-cert.lua | 47 | ||||
-rw-r--r-- | regress/regress.lua | 2 | ||||
-rw-r--r-- | src/openssl.c | 160 |
5 files changed, 198 insertions, 24 deletions
diff --git a/doc/luaossl.pdf b/doc/luaossl.pdf Binary files differindex 1f9d84d..4442b34 100644 --- a/doc/luaossl.pdf +++ b/doc/luaossl.pdf diff --git a/doc/luaossl.tex b/doc/luaossl.tex index 8561957..b874e89 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. 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/regress.lua b/regress/regress.lua index 19ee065..5cdd22d 100644 --- a/regress/regress.lua +++ b/regress/regress.lua @@ -8,7 +8,9 @@ local regress = { 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/openssl.c b/src/openssl.c index 9e0447f..0387fb4 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -479,6 +479,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 @@ -2129,6 +2133,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, @@ -7160,6 +7182,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 }, @@ -7311,6 +7439,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 }, @@ -8290,16 +8419,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; @@ -8312,21 +8443,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() */ @@ -8544,19 +8667,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)) { |