# HG changeset patch # User Paul Aurich # Date 1291621510 28800 # Node ID 8904bda2369fdd24273086cea2e68d613b48456e # Parent 96f23601ce7aafd87fbbedead57bbff4ab409a8c ssl: getpeercertificate(n) and getpeerchain() diff -r 96f23601ce7a -r 8904bda2369f src/ssl.c --- a/src/ssl.c Sun Dec 12 22:21:36 2010 +0000 +++ b/src/ssl.c Sun Dec 05 23:45:10 2010 -0800 @@ -413,23 +413,83 @@ return 2; } -/** - * Return the peer certificate. - */ -static int meth_getpeercertificate(lua_State *L) +static void luasec_push_cert(lua_State *L, X509 *cert) { - X509 *peer; - p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); - peer = SSL_get_peer_certificate(ssl->ssl); - if (peer == NULL) { - /* No client certificate available */ + if (cert == NULL) { lua_pushnil(L); } else { - /* Push metatabled peer */ - luasec_push_x509(L, peer); + luasec_push_x509(L, cert); + } +} + +/** + * Return the nth certificate of the peer's chain. + */ +static int meth_getpeercertificate(lua_State *L) +{ + p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); + int n = luaL_optint(L, 2, 1); /* Default to the first cert */ + STACK_OF(X509) *certs; + X509 *cert; + + /* This function is 1-based, but OpenSSL is 0-based */ + --n; + if (n < 0) { + lua_pushnil(L); + lua_pushliteral(L, "n must be positive"); + return 2; + } + + if (n == 0) { + luasec_push_cert(L, SSL_get_peer_certificate(ssl->ssl)); + return 1; } + + /* + * In a server-context, the stack doesn't contain the peer cert, so + * adjust accordingly. + */ + if (ssl->ssl->server) + --n; + + certs = SSL_get_peer_cert_chain(ssl->ssl); + if (n >= sk_X509_num(certs)) { + lua_pushnil(L); + lua_pushliteral(L, "no certificate at this index"); + return 2; + } + cert = sk_X509_value(certs, n); + /* Locking...the same as in SSL_get_peer_certificate */ + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); + luasec_push_cert(L, cert); + return 1; +} + +static int meth_getpeerchain(lua_State *L) +{ + p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); + STACK_OF(X509) *certs; + int n_certs, i; + + lua_newtable(L); + + if (ssl->ssl->server) { + luasec_push_cert(L, SSL_get_peer_certificate(ssl->ssl)); + lua_rawseti(L, -2, 1); + } + + certs = SSL_get_peer_cert_chain(ssl->ssl); + n_certs = sk_X509_num(certs); + for (i = 0; i < n_certs; ++i) { + X509 *cert = sk_X509_value(certs, i); + /* Locking...the same as in SSL_get_peer_certificate */ + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); + luasec_push_cert(L, cert); + lua_rawseti(L, -2, lua_objlen(L, -2)+1); + } + return 1; } @@ -486,6 +546,7 @@ {"want", meth_want}, {"compression", meth_compression}, {"getpeercertificate",meth_getpeercertificate}, + {"getpeerchain", meth_getpeerchain}, {"getpeerchainvalid", meth_getpeerchainvalid}, {"getfinished", meth_getfinished}, {"getpeerfinished", meth_getpeerfinished},