ssl: getpeercertificate(n) and getpeerchain()

Sun, 05 Dec 2010 23:45:10 -0800

author
Paul Aurich <paul@darkrain42.org>
date
Sun, 05 Dec 2010 23:45:10 -0800
changeset 37
8904bda2369f
parent 36
96f23601ce7a
child 38
4ecd7b0e67ea

ssl: getpeercertificate(n) and getpeerchain()

src/ssl.c file | annotate | diff | comparison | revisions
--- 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},

mercurial