aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/luaossl.pdfbin289161 -> 269289 bytes
-rw-r--r--doc/luaossl.tex27
-rw-r--r--src/compat52.h8
-rw-r--r--src/openssl.c200
4 files changed, 207 insertions, 28 deletions
diff --git a/doc/luaossl.pdf b/doc/luaossl.pdf
index dccba97..459a9cc 100644
--- a/doc/luaossl.pdf
+++ b/doc/luaossl.pdf
Binary files differ
diff --git a/doc/luaossl.tex b/doc/luaossl.tex
index 7db7463..49e8e0e 100644
--- a/doc/luaossl.tex
+++ b/doc/luaossl.tex
@@ -286,8 +286,13 @@ field & type:default & description\\\hline
.exp & number:65537 & RSA or Diffie-Hellman exponent \\
+.dhparam & string & PEM encoded string with precomputed DH parameters \\
+
.curve & string:prime192v1 & for elliptic curve keys, the OpenSSL string identifier of the curve
\end{ctabular}
+
+The DH parameters ``dhparam'' will be generated on the fly, ``bits'' wide. This is a slow process, and especially for larger sizes, you would precompute those; for example: ``openssl dhparam -2 -out dh-2048.pem -outform PEM 2048''. Using the field ``dhparam'' overrides the ``bits'' field.
+
\subsubsection[\fn{pkey.interpose}]{\fn{pkey.interpose($name$, $function$)}}
Add or interpose a pkey class method. Returns the previous method, if any.
@@ -389,7 +394,19 @@ Binds the X.509 extension OpenSSL object.
\subsubsection[\fn{extension.new}]{\fn{extension.new($name$, $value$ [, $data$])}}
-Returns a new X.509 extension. If $value$ is the string ``DER'' or ``critical,DER'', then $data$ is an ASN.1-encoded octet string. Otherwise, $name$ and $value$ are plain text strings in \href{https://www.openssl.org/docs/apps/x509v3_config.html#ARBITRARY_EXTENSIONS}{OpenSSL's arbitrary extension format}; and if specified, $data$ is an OpenSSL configuration string defining any referenced identifiers in $value$.
+Returns a new X.509 extension.
+If $value$ is the string ``DER'' or ``critical,DER'', then $data$ is an ASN.1-encoded octet string.
+Otherwise, $name$ and $value$ are plain text strings in \href{https://www.openssl.org/docs/apps/x509v3_config.html#ARBITRARY_EXTENSIONS}{OpenSSL's arbitrary extension format}; and if specified, $data$ is either an OpenSSL configuration string defining any referenced identifiers in $value$, or a table with members:
+
+\begin{ctabular}{ l | l | p{8cm} }
+field & type:default & description\\\hline
+.db & string:$nil$ & OpenSSL configuration string\\
+.issuer & \module{openssl.x509}:$nil$ & issuer certificate\\
+.subject & \module{openssl.x509}:$nil$ & subject certificate\\
+.request & \module{openssl.x509.csr}:$nil$ & certificate signing request\\
+.crl & \module{openssl.x509.crl}:$nil$ & certificate revocation list\\
+.flags & integer:$0$ & a bitwise combination of flags
+\end{ctabular}
\subsubsection[\fn{extension.interpose}]{\fn{extension.interpose($name$, $function$)}}
@@ -688,6 +705,10 @@ Returns the integer count of the number of extensions.
Signs the instance CRL using the \module{openssl.pkey} $key$.
+\subsubsection[\fn{crl:verify}]{\fn{crl:verify($publickey$)}}
+
+Verifies the instance CRL using a public key.
+
\subsubsection[\fn{crl:text}]{\fn{crl:text()}}
Returns a human-readable textual representation of the instance CRL.
@@ -763,6 +784,10 @@ Add or interpose a store class method. Returns the previous method, if any.
Returns a PKCS \#12 binary encoded string.
+\subsubsection[\fn{pkcs12.parse}]{\fn{pkcs12.parse($bag$[, $passphrase$])}}
+
+Parses a PKCS\#12 bag, presented as a binary string $bag$. The second parameter $passphrase$ is the passphrase required to decrypt the PKCS\#12 bag. The function returns three items; namely the key, certificate and the CA chain, as their respective objects. If an item is absent, it will be substituted with nil.
+
\end{Module}
diff --git a/src/compat52.h b/src/compat52.h
index 0057b3c..22541f7 100644
--- a/src/compat52.h
+++ b/src/compat52.h
@@ -23,6 +23,14 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE.
* ==========================================================================
*/
+
+
+#if LUA_VERSION_NUM < 503
+
+#define lua_getfield(L, i, f) (lua_getfield(L, (i), (f)), lua_type(L, -1))
+
+#endif
+
#if LUA_VERSION_NUM < 502
#define LUA_OK 0
diff --git a/src/openssl.c b/src/openssl.c
index dd406bc..ab729d4 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -74,9 +74,7 @@
#include <lualib.h>
#include <lauxlib.h>
-#if LUA_VERSION_NUM < 502
#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)))
@@ -3070,6 +3068,7 @@ static int pk_new(lua_State *L) {
unsigned exp = 65537;
int curve = NID_X9_62_prime192v1;
const char *id;
+ const char *dhparam = NULL;
lua_Number n;
if (!lua_istable(L, 1))
@@ -3111,6 +3110,9 @@ static int pk_new(lua_State *L) {
luaL_argerror(L, 1, lua_pushfstring(L, "%s: invalid curve", id));
}
+ /* dhparam field can contain a PEM encoded string. */
+ loadfield(L, 1, "dhparam", LUA_TSTRING, &dhparam);
+
creat:
if (!(*ud = EVP_PKEY_new()))
return auxL_error(L, auxL_EOPENSSL, "pkey.new");
@@ -3148,9 +3150,23 @@ creat:
case EVP_PKEY_DH: {
DH *dh;
- if (!(dh = DH_generate_parameters(bits, exp, 0, 0)))
+ /* DH Parameter Generation can take a long time, therefore we look
+ * at the "dhparam" field, provided by the user.
+ * The "dhparam" field takes precedence over "bits"
+ */
+ if (dhparam) {
+ BIO *bio = BIO_new_mem_buf((void*)dhparam, strlen(dhparam));
+ if (!bio)
+ return auxL_error(L, auxL_EOPENSSL, "pkey.new");
+
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ 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");
+
if (!DH_generate_key(dh)) {
DH_free(dh);
return auxL_error(L, auxL_EOPENSSL, "pkey.new");
@@ -4966,6 +4982,25 @@ static _Bool xe_new_isder(const char *value, _Bool *crit) {
return 0;
} /* xs_new_isder() */
+static CONF* loadconf(lua_State *L, int idx) {
+ CONF *conf;
+ size_t len;
+ const char *cdata = luaL_checklstring(L, idx, &len);
+ BIO *bio = getbio(L);
+ if (BIO_write(bio, cdata, len) < 0)
+ return NULL;
+
+ if (!(conf = NCONF_new(NULL)))
+ return NULL;
+
+ if (!NCONF_load_bio(conf, bio, NULL)) {
+ NCONF_free(conf);
+ return NULL;
+ }
+
+ return conf;
+}
+
static int xe_new(lua_State *L) {
const char *name = luaL_checkstring(L, 1);
const char *value = luaL_checkstring(L, 2);
@@ -4974,42 +5009,87 @@ static int xe_new(lua_State *L) {
CONF *conf = NULL;
X509V3_CTX cbuf = { 0 }, *ctx = NULL;
X509_EXTENSION **ud;
+ _Bool crit;
lua_settop(L, 3);
ud = prepsimple(L, X509_EXT_CLASS);
- if (!lua_isnil(L, 3)) {
+ if (xe_new_isder(value, &crit)) {
size_t len;
- const char *cdata = luaL_checklstring(L, 3, &len);
- _Bool crit;
+ const char *cdata = lua_tolstring(L, 3, &len);
+ if (!(obj = OBJ_txt2obj(name, 0)))
+ goto error;
+ if (!(oct = ASN1_STRING_new()))
+ goto error;
+ if (!ASN1_STRING_set(oct, cdata, len))
+ goto error;
+ if (!(*ud = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct)))
+ goto error;
- if (xe_new_isder(value, &crit)) {
- if (!(obj = OBJ_txt2obj(name, 0)))
- goto error;
- if (!(oct = ASN1_STRING_new()))
- goto error;
- if (!ASN1_STRING_set(oct, cdata, len))
- goto error;
- if (!(*ud = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct)))
+ ASN1_OBJECT_free(obj);
+ ASN1_STRING_free(oct);
+
+ return 1;
+ }
+
+ switch (lua_type(L, 3)) {
+ case LUA_TNONE:
+ case LUA_TNIL:
+ break;
+ case LUA_TSTRING: {
+ if (!(conf = loadconf(L, 3)))
+ goto error;
+
+ ctx = &cbuf;
+ X509V3_set_nconf(ctx, conf);
+ break;
+ }
+ case LUA_TTABLE: {
+ X509 *issuer = NULL;
+ X509 *subject = NULL;
+ X509_REQ *request = NULL;
+ X509_CRL *crl = NULL;
+ int flags = 0;
+
+ ctx = &cbuf;
+
+ if (lua_getfield(L, 3, "db") != LUA_TNIL) {
+ if (!(conf = loadconf(L, -1)))
goto error;
+ X509V3_set_nconf(ctx, conf);
+ }
+ lua_pop(L, 1);
+
+ if (lua_getfield(L, 3, "issuer") != LUA_TNIL) {
+ issuer = checksimple(L, -1, X509_CERT_CLASS);
+ }
+ lua_pop(L, 1);
- ASN1_OBJECT_free(obj);
- ASN1_STRING_free(oct);
+ if (lua_getfield(L, 3, "subject") != LUA_TNIL) {
+ subject = checksimple(L, -1, X509_CERT_CLASS);
+ }
+ lua_pop(L, 1);
- return 1;
+ if (lua_getfield(L, 3, "request") != LUA_TNIL) {
+ request = checksimple(L, -1, X509_CSR_CLASS);
}
+ lua_pop(L, 1);
- BIO *bio = getbio(L);
- if (BIO_puts(bio, cdata) < 0)
- goto error;
+ if (lua_getfield(L, 3, "crl") != LUA_TNIL) {
+ crl = checksimple(L, -1, X509_CRL_CLASS);
+ }
+ lua_pop(L, 1);
- if (!(conf = NCONF_new(NULL)))
- goto error;
- if (!NCONF_load_bio(conf, bio, NULL))
- goto error;
+ if (lua_getfield(L, 3, "flags") != LUA_TNIL) {
+ flags = luaL_checkinteger(L, -1);
+ }
+ lua_pop(L, 1);
- ctx = &cbuf;
- X509V3_set_nconf(ctx, conf);
+ X509V3_set_ctx(ctx, issuer, subject, request, crl, flags);
+ break;
+ }
+ default:
+ return luaL_argerror(L, 3, "invalid extra parameter (expected string, table or nil)");
}
/*
@@ -6630,7 +6710,7 @@ static int xx_getNextUpdate(lua_State *L) {
updateby = timeutc(time);
if (isfinite(updateby))
- lua_pushnumber(L, 1);
+ lua_pushnumber(L, updateby);
else
lua_pushnil(L);
@@ -6820,6 +6900,19 @@ static int xx_sign(lua_State *L) {
} /* xx_sign() */
+static int xx_verify(lua_State *L) {
+ X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS);
+ EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS);
+
+ if (!X509_CRL_verify(crl, key))
+ return auxL_error(L, auxL_EOPENSSL, "x509.crl:verify");
+
+ lua_pushboolean(L, 1);
+
+ return 1;
+} /* xx_verify() */
+
+
static int xx_text(lua_State *L) {
X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS);
@@ -6889,6 +6982,7 @@ static const auxL_Reg xx_methods[] = {
{ "getExtension", &xx_getExtension },
{ "getExtensionCount", &xx_getExtensionCount },
{ "sign", &xx_sign },
+ { "verify", &xx_verify },
{ "text", &xx_text },
{ "tostring", &xx__tostring },
{ NULL, NULL },
@@ -7416,6 +7510,57 @@ static int p12_interpose(lua_State *L) {
} /* p12_interpose() */
+static int p12_parse(lua_State *L) {
+ /* parse a p12 binary string and return the parts */
+ PKCS12 *p12;
+
+ /* gather input parameters */
+ size_t len;
+ const char *blob = luaL_checklstring(L, 1, &len);
+ const char *passphrase = luaL_optstring(L, 2, NULL);
+
+ /* prepare return values */
+ EVP_PKEY **ud_pkey = prepsimple(L, PKEY_CLASS);
+ X509 **ud_cert = prepsimple(L, X509_CERT_CLASS);
+ STACK_OF(X509) **ud_chain = prepsimple(L, X509_CHAIN_CLASS);
+ /* Note: *ud_chain must be initialised to NULL, which prepsimple does. */
+
+ /* read PKCS#12 data into OpenSSL memory buffer */
+ BIO *bio = BIO_new_mem_buf((void*)blob, len);
+ if (!bio)
+ return auxL_error(L, auxL_EOPENSSL, "pkcs12.parse");
+ p12 = d2i_PKCS12_bio(bio, NULL);
+ BIO_free(bio);
+ if (!p12)
+ return auxL_error(L, auxL_EOPENSSL, "pkcs12.parse");
+
+ /* the p12 pointer holds the data we're interested in */
+ int rc = PKCS12_parse(p12, passphrase, ud_pkey, ud_cert, ud_chain);
+ PKCS12_free(p12);
+ if (!rc)
+ auxL_error(L, auxL_EOPENSSL, "pkcs12.parse");
+
+ /* replace the return values by nil if the ud pointers are NULL */
+ if (*ud_pkey == NULL) {
+ lua_pushnil(L);
+ lua_replace(L, -4);
+ }
+
+ if (*ud_cert == NULL) {
+ lua_pushnil(L);
+ lua_replace(L, -3);
+ }
+
+ /* other certificates (a chain, STACK_OF(X509) *) */
+ if (*ud_chain == NULL) {
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ }
+
+ return 3;
+} /* p12_parse() */
+
+
static int p12__tostring(lua_State *L) {
PKCS12 *p12 = checksimple(L, 1, PKCS12_CLASS);
BIO *bio = getbio(L);
@@ -7459,6 +7604,7 @@ static const auxL_Reg p12_metatable[] = {
static const auxL_Reg p12_globals[] = {
{ "new", &p12_new },
{ "interpose", &p12_interpose },
+ { "parse", &p12_parse },
{ NULL, NULL },
};