Fix the verification function so it doesn't pass for everyone on invalid purpose errors.

Sun, 03 Jul 2011 13:13:36 -0700

author
Paul Aurich <paul@darkrain42.org>
date
Sun, 03 Jul 2011 13:13:36 -0700
changeset 41
e26f1f91118a
parent 40
85d59ac3328b
child 42
b6271d3bae0b

Fix the verification function so it doesn't pass for everyone on invalid purpose errors.

Inspiration and code partially from Matthew

src/context.c file | annotate | diff | comparison | revisions
src/context.h file | annotate | diff | comparison | revisions
src/ssl.c file | annotate | diff | comparison | revisions
src/ssl.h file | annotate | diff | comparison | revisions
--- a/src/context.c	Sun Jul 03 13:13:36 2011 -0700
+++ b/src/context.c	Sun Jul 03 13:13:36 2011 -0700
@@ -7,11 +7,14 @@
 #include <string.h>
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
 
 #include <lua.h>
 #include <lauxlib.h>
 
 #include "context.h"
+#include "ssl.h"
 
 struct ssl_option_s {
   const char *name;
@@ -249,7 +252,8 @@
     lua_pushnil(L);
     lua_pushstring(L, "error creating context");
     return 2;
-  }  
+  }
+  ctx->L = L;
   ctx->context = SSL_CTX_new(method);
   if (!ctx->context) {
     lua_pushnil(L);
@@ -403,11 +407,37 @@
   return 1;
 }
 
+static void
+luasec_push_cert_error(lua_State *L, int ref, int depth, int err)
+{
+  int created = 0;
+
+  lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+  lua_rawgeti(L, -1, depth + 1);
+  if (!lua_istable(L, -1)) {
+    /* If the table doesn't exist, create it */
+    created = 1;
+    lua_pop(L, 1);
+    lua_newtable(L);
+  }
+
+  lua_pushstring(L, X509_verify_cert_error_string(err));
+  lua_rawseti(L, -2, lua_objlen(L, -2)+1);
+
+  if (created) {
+    lua_rawseti(L, -2, depth + 1);
+    lua_pop(L, 1);
+  } else
+    lua_pop(L, 2);
+}
+
 int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 {
   SSL_CTX *context;
   SSL *ssl;
   p_context l_ctx;
+  p_ssl l_ssl;
+  int err, depth;
 
   /* Short-circuit optimization */
   if (preverify_ok)
@@ -415,21 +445,37 @@
 
   ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
   context = ssl->ctx;
+  l_ssl = SSL_get_ex_data(ssl, luasec_ssl_idx);
   l_ctx = SSL_CTX_get_ex_data(context, luasec_sslctx_idx);
 
-  if (l_ctx->verify_flags & LUASEC_VERIFY_FLAGS_IGNORE_PURPOSE) {
-    int err, depth;
+  err = X509_STORE_CTX_get_error(x509_ctx);
+  depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+
+  if (err != X509_V_OK) {
+    if (l_ssl->t_cert_errors == LUA_NOREF) {
+      lua_newtable(l_ctx->L);
+      l_ssl->t_cert_errors = luaL_ref(l_ctx->L, LUA_REGISTRYINDEX);
+    }
+
+    luasec_push_cert_error(l_ctx->L, l_ssl->t_cert_errors, depth, err);
+  }
 
-    err = X509_STORE_CTX_get_error(x509_ctx);
-    depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+  return (l_ctx->verify_flags & LUASEC_VERIFY_FLAGS_ALWAYS_CONTINUE ? 1 : preverify_ok);
+}
 
-    if (depth == 0 && err == X509_V_ERR_INVALID_PURPOSE) {
-      /* You see nothing! */
-      X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
-      preverify_ok = 1;
+static int luasec_verify(X509_STORE_CTX *x509_ctx, void *ptr)
+{
+  p_context ctx = ptr;
+
+  if (ctx->verify_flags & LUASEC_VERIFY_FLAGS_IGNORE_PURPOSE) {
+    X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(x509_ctx);
+    if (param) {
+      X509_VERIFY_PARAM_set_purpose(param, X509_PURPOSE_SSL_SERVER);
+      X509_VERIFY_PARAM_set_trust(param, X509_TRUST_SSL_SERVER);
     }
   }
-  return (l_ctx->verify_flags & LUASEC_VERIFY_FLAGS_ALWAYS_CONTINUE ? 1 : preverify_ok);
+
+  return X509_verify_cert(x509_ctx);
 }
 
 /**
@@ -463,6 +509,7 @@
       }
     }
     SSL_CTX_set_verify(ctx->context, flag, ctx->verify_flags ? verify_cb : NULL);
+    SSL_CTX_set_cert_verify_callback(ctx->context, luasec_verify, ctx);
     if(vflag)
     {
       X509_STORE *store = SSL_CTX_get_cert_store(ctx->context);
--- a/src/context.h	Sun Jul 03 13:13:36 2011 -0700
+++ b/src/context.h	Sun Jul 03 13:13:36 2011 -0700
@@ -26,6 +26,7 @@
 
 typedef struct t_context_ {
   SSL_CTX *context;
+  lua_State *L;
   unsigned int verify_flags;
   char mode;
 } t_context;
--- a/src/ssl.c	Sun Jul 03 13:13:36 2011 -0700
+++ b/src/ssl.c	Sun Jul 03 13:13:36 2011 -0700
@@ -23,7 +23,7 @@
 /* index into the SSL storage where the t_ssl is.
  * see SSL_get_ex_data().
  */
- static int luasec_ssl_idx;
+ int luasec_ssl_idx;
 
 /**
  * Map error code into string.
@@ -61,6 +61,8 @@
     SSL_free(ssl->ssl);
     ssl->ssl = NULL;
   }
+  luaL_unref(L, LUA_REGISTRYINDEX, ssl->t_cert_errors);
+  ssl->t_cert_errors = LUA_NOREF;
   return 0;
 }
 
@@ -251,6 +253,7 @@
 #endif
 
   SSL_set_ex_data(ssl->ssl, luasec_ssl_idx, ssl);
+  ssl->t_cert_errors = LUA_NOREF;
 
   if (mode == MD_CTX_SERVER)
     SSL_set_accept_state(ssl->ssl);
@@ -403,18 +406,12 @@
 /**
  * Return the validation state of the peer chain
  */
-static int meth_getpeerchainvalid(lua_State *L)
+static int meth_getpeerverification(lua_State *L)
 {
   p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
-  long result = SSL_get_verify_result(ssl->ssl);
 
-  if (result == X509_V_OK) {
-    lua_pushboolean(L, 1);
-    return 1;
-  }
-
-  lua_pushboolean(L, 0);
-  lua_pushstring(L, X509_verify_cert_error_string(result));
+  lua_pushboolean(L, SSL_get_verify_result(ssl->ssl) == X509_V_OK);
+  lua_rawgeti(L, LUA_REGISTRYINDEX, ssl->t_cert_errors);
   return 2;
 }
 
@@ -552,7 +549,7 @@
   {"compression",       meth_compression},
   {"getpeercertificate",meth_getpeercertificate},
   {"getpeerchain",      meth_getpeerchain},
-  {"getpeerchainvalid", meth_getpeerchainvalid},
+  {"getpeerverification", meth_getpeerverification},
   {"getfinished",       meth_getfinished},
   {"getpeerfinished",   meth_getpeerfinished},
   {NULL,                NULL}
--- a/src/ssl.h	Sun Jul 03 13:13:36 2011 -0700
+++ b/src/ssl.h	Sun Jul 03 13:13:36 2011 -0700
@@ -28,9 +28,11 @@
   SSL *ssl;
   char state;
   int error;
+  int t_cert_errors; /* reference to a table of cert errors...or LUA_NOREF */
 } t_ssl;
 typedef t_ssl* p_ssl;
 
+extern int luasec_ssl_idx;
 LUASEC_API int luaopen_ssl_core(lua_State *L);
 
 #endif

mercurial