Fri, 05 Nov 2010 16:38:10 +0000
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; }