Refactoring of :getpeercertificate(), support for subjectAltName extensions

Fri, 05 Nov 2010 16:38:10 +0000

author
Matthew Wild <mwild1@gmail.com>
date
Fri, 05 Nov 2010 16:38:10 +0000
changeset 11
8d7698d3fd26
parent 10
a4a1fd8c1b43
child 12
ac943b31f40c

Refactoring of :getpeercertificate(), support for subjectAltName extensions

src/ssl.c file | annotate | diff | comparison | revisions
--- a/src/ssl.c	Fri Nov 05 02:22:20 2010 +0000
+++ b/src/ssl.c	Fri Nov 05 16:38:10 2010 +0000
@@ -7,6 +7,7 @@
 #include <string.h>
 
 #include <openssl/ssl.h>
+#include <openssl/x509v3.h>
 #include <openssl/err.h>
 
 #include <lua.h>
@@ -18,6 +19,8 @@
 #include "socket.h"
 #include "ssl.h"
 
+#define min(a, b) (a<b)?a:b
+
 /**
  * Map error code into string.
  */
@@ -373,12 +376,49 @@
   }
 }
 
+void luasec_push_asn1_objname(lua_State* L, ASN1_OBJECT *object, int no_name)
+{
+  char buffer[256];
+  int len = OBJ_obj2txt(buffer, sizeof(buffer), object, no_name);
+  lua_pushlstring(L, buffer, min(sizeof(buffer),len));
+}
+
+void luasec_push_asn1_string(lua_State* L, ASN1_STRING *string)
+{
+  if(string)
+    lua_pushlstring(L, (char*)ASN1_STRING_data(string), ASN1_STRING_length(string));
+  else
+    lua_pushnil(L);
+}
+
+int luasec_push_subtable(lua_State* L, int idx)
+{
+
+        lua_pushvalue(L, -1);
+        lua_gettable(L, idx-1);
+
+        if(lua_isnil(L, -1))
+        {
+        	lua_pop(L, 1);
+        	lua_newtable(L);
+        	lua_pushvalue(L, -2);
+        	lua_pushvalue(L, -2);
+        	lua_settable(L, idx-3);
+
+        	lua_replace(L, -2); /* Replace key with table */
+        	return 1;
+        }
+       	lua_replace(L, -2); /* Replace key with table */
+        return 0;
+}
+
 /**
  * Return the peer certificate.
  */
 static int meth_getpeercertificate(lua_State *L)
 {
   X509 *peer;
+  int i, j;
   p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
   peer = SSL_get_peer_certificate(ssl->ssl);
   if (peer == NULL) {
@@ -389,8 +429,7 @@
   else
   {
     X509_NAME *subject;
-    int i, n_entries, len;
-    char buffer[4096];
+    int n_entries;
 
     lua_newtable(L); /* ret */
 
@@ -408,48 +447,99 @@
     {
       X509_NAME_ENTRY *entry;
       ASN1_OBJECT *object;
-      ASN1_STRING *value;
-      int len;
 
       entry = X509_NAME_get_entry(subject, i);
       object = X509_NAME_ENTRY_get_object(entry);
 
-      /* Get numeric ID as string into buffer */
-      len = OBJ_obj2txt(buffer, sizeof(buffer), object, 1);
-
-      if(len == 0)
-        continue;
-
-      /* Push numeric ID to Lua (e.g. 1.22.3...) */
-      lua_pushlstring(L, buffer, (len>sizeof(buffer))?sizeof(buffer):(len));
+      luasec_push_asn1_objname(L, object, 1);
 
-      lua_pushvalue(L, -1); /* k */
-      lua_gettable(L, -4); /* ret.subject[k] */
-
-      if(lua_isnil(L, -1))
+      if(luasec_push_subtable(L, -2))
       {
-      	lua_pop(L, 1);
-        lua_newtable(L);
-        lua_pushvalue(L, -2); /* k */
-        lua_pushvalue(L, -2); /* v */
-        lua_settable(L, -5); /* ret.subject[k] = v */
         /* Get short/long name of the entry */
-        len = OBJ_obj2txt(buffer, sizeof(buffer), object, 0);
-        lua_pushlstring(L, buffer, (len>sizeof(buffer))?sizeof(buffer):(len));
+        luasec_push_asn1_objname(L, object, 0);
         lua_setfield(L, -2, "name");
       }
 
-      value = X509_NAME_ENTRY_get_data(entry);
-      if(value)
-      {
-        lua_pushlstring(L, (char*)ASN1_STRING_data(value), ASN1_STRING_length(value));
-        lua_rawseti(L, -2, lua_objlen(L, -2)+1);
-      }
+      luasec_push_asn1_string(L, X509_NAME_ENTRY_get_data(entry));
+      lua_rawseti(L, -2, lua_objlen(L, -2)+1);
 
-      lua_pop(L, 2); /* k, v */
+      lua_pop(L, 1);
     }
   }
   lua_pop(L, 1); /* ret.subject */
+
+  lua_newtable(L); /* {} */
+  lua_pushvalue(L, -1);
+  lua_setfield(L, -3, "extensions"); /* ret.extensions = {} */
+  
+  i = -1;
+  while((i = X509_get_ext_by_NID(peer, NID_subject_alt_name, i)) != -1)
+  {
+    X509_EXTENSION *extension;
+    STACK_OF(GENERAL_NAME) *values;
+    int n_general_names;
+    
+    extension = X509_get_ext(peer, i);
+    if(extension == NULL)
+      break;
+    
+    values = X509V3_EXT_d2i(extension);
+    if(values == NULL)
+      break;
+
+    /* Push ret.extensions[oid] */
+    luasec_push_asn1_objname(L, extension->object, 1);
+    luasec_push_subtable(L, -2);
+    /* Set ret.extensions[oid].name = name */
+    luasec_push_asn1_objname(L, extension->object, 0);
+    lua_setfield(L, -2, "name");
+
+    n_general_names = sk_GENERAL_NAME_num(values);
+    for(j = 0; j < n_general_names; j++)
+    {
+      GENERAL_NAME *general_name;
+
+      general_name = sk_GENERAL_NAME_value(values, j);
+
+      switch(general_name->type)
+      {
+      case GEN_OTHERNAME:
+      {
+        OTHERNAME *otherName = general_name->d.otherName;
+
+        luasec_push_asn1_objname(L, otherName->type_id, 1);
+
+        if(luasec_push_subtable(L, -2))
+        {
+          luasec_push_asn1_objname(L, otherName->type_id, 0);
+          lua_setfield(L, -2, "name");
+        }
+
+        luasec_push_asn1_string(L, otherName->value->value.asn1_string);
+        lua_rawseti(L, -2, lua_objlen(L, -2)+1);
+
+        lua_pop(L, 1);
+        break;
+      }
+      case GEN_DNS:
+      {
+        lua_pushstring(L, "dNSName");
+	luasec_push_subtable(L, -2);
+        luasec_push_asn1_string(L, general_name->d.dNSName);
+        lua_rawseti(L, -2, lua_objlen(L, -2)+1);
+        lua_pop(L, 1);
+        break;
+      }
+      default:
+        break;
+      }
+    }
+
+    lua_pop(L, 1); /* array */
+    i++; /* Next extension */
+  }
+  lua_pop(L, 1); /* ret.extensions */
+
   return 1;
 }
 

mercurial