]> granicus.if.org Git - apache/commitdiff
Allow extraction of the values of SSL certificate extensions into
authorMartin Kraemer <martin@apache.org>
Fri, 22 Jul 2005 12:11:55 +0000 (12:11 +0000)
committerMartin Kraemer <martin@apache.org>
Fri, 22 Jul 2005 12:11:55 +0000 (12:11 +0000)
environment variables, so that their value can be used by any
module that is aware of environment variables, as in:

  SetEnvIf OID("2.16.840.1.113730.1.13") "(.*) Generated (Certificate)" ca=$1
sets
  ca=TinyCA
if the cert was issued by TinyCA.

Similarly,
  SetenvIf OID("2.16.840.1.113730.1.13") "(.*)" NetscapeComment=$1
will set $NetscapeComment to the whole string.

It is technically allowed to have multiple instances of an extension
field, all with the same oid. In this case, the environment variable
will be set to the list of all fields, separated by commas.

The [PATCH] uses a cross-module call from mod_setenvif to
mod_ssl (the latter may also be missing: in this case the
variable will never be set). It calls a common function
in the ssl module that is also used for the SSLRequire
directive's test.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@220307 13f79535-47bb-0310-9956-ffa450edef68

modules/metadata/mod_setenvif.c
modules/ssl/mod_ssl.c
modules/ssl/mod_ssl.h
modules/ssl/ssl_expr_eval.c

index f07a9f5925e99deb1881f957f0d5c4f91650df1f..0010e3a94376869de31dc56d6c698ad5b0e922f1 100644 (file)
@@ -102,7 +102,8 @@ enum special {
     SPECIAL_REQUEST_URI,
     SPECIAL_REQUEST_METHOD,
     SPECIAL_REQUEST_PROTOCOL,
-    SPECIAL_SERVER_ADDR
+    SPECIAL_SERVER_ADDR,
+    SPECIAL_OID_VALUE
 };
 typedef struct {
     char *name;                 /* header name */
@@ -120,6 +121,12 @@ typedef struct {
 } sei_cfg_rec;
 
 module AP_MODULE_DECLARE_DATA setenvif_module;
+#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
+#include "mod_ssl.h"
+#else
+APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr));
+#endif
+static APR_OPTIONAL_FN_TYPE(ssl_extlist_by_oid) *ssl_extlist_by_oid_func = NULL;
 
 /*
  * These routines, the create- and merge-config functions, are called
@@ -345,6 +352,31 @@ static const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
         else if (!strcasecmp(fname, "server_addr")) {
             new->special_type = SPECIAL_SERVER_ADDR;
         }
+        else if (!strncasecmp(fname, "oid(",4)) {
+            ap_regmatch_t match[AP_MAX_REG_MATCH];
+
+            new->special_type = SPECIAL_OID_VALUE;
+
+            /* Syntax check and extraction of the OID as a regex: */
+            new->pnamereg = ap_pregcomp(cmd->pool,
+                                        "^oid\\(\"?([0-9.]+)\"?\\)$",
+                                        (AP_REG_EXTENDED // | AP_REG_NOSUB
+                                         | AP_REG_ICASE));
+            /* this can never happen, as long as pcre works:
+              if (new->pnamereg == NULL)
+                    return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                       "OID regex could not be compiled.", NULL);
+             */
+            if (ap_regexec(new->pnamereg, fname, AP_MAX_REG_MATCH, match, 0) == AP_REG_NOMATCH) {
+                return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                       "OID syntax is: oid(\"1.2.3.4.5\"); error in: ",
+                                       fname, NULL);
+            }
+            new->pnamereg = NULL;
+            /* The name field is used for the stripped oid string */
+            new->name = fname = apr_pstrdup(cmd->pool, fname+match[1].rm_so);
+            fname[match[1].rm_eo - match[1].rm_so] = '\0';
+        }
         else {
             new->special_type = SPECIAL_NOT;
             /* Handle fname as a regular expression.
@@ -475,6 +507,8 @@ static int match_headers(request_rec *r)
          * same header.  Remember we don't need to strcmp the two header
          * names because we made sure the pointers were equal during
          * configuration.
+         * In the case of SPECIAL_OID_VALUE values, each oid string is
+         * dynamically allocated, thus there are no duplicates.
          */
         if (b->name != last_name) {
             last_name = b->name;
@@ -498,6 +532,34 @@ static int match_headers(request_rec *r)
             case SPECIAL_REQUEST_PROTOCOL:
                 val = r->protocol;
                 break;
+            case SPECIAL_OID_VALUE:
+                /* If mod_ssl is not loaded, the accessor function is NULL */
+                if (ssl_extlist_by_oid_func != NULL)
+                {
+                    apr_array_header_t *oid_array;
+                    char **oid_value;
+                    int j, len = 0;
+                    char *retval = NULL;
+
+                    /* The given oid can occur multiple times. Concatenate the values */
+                    if ((oid_array = ssl_extlist_by_oid_func(r, b->name)) != NULL) {
+                        oid_value = (char **) oid_array->elts;
+                        /* pass 1: determine the size of the string */
+                        for (len=j=0; j < oid_array->nelts; j++) {
+                          len += strlen(oid_value[j]) + 1; /* +1 for ',' or terminating NIL */
+                        }
+                        retval = apr_palloc(r->pool, len);
+                        /* pass 2: fill the string */
+                        for (j=0; j < oid_array->nelts; j++) {
+                          if (j > 0) {
+                              strcat(retval, ",");
+                          }
+                          strcat(retval, oid_value[j]);
+                        }
+                    }
+                    val = retval;
+                }
+                break;
             case SPECIAL_NOT:
                 if (b->pnamereg) {
                     /* Matching headers_in against a regex. Iterate through
@@ -568,10 +630,19 @@ static int match_headers(request_rec *r)
     return DECLINED;
 }
 
+static int
+setenvif_post_config()
+{
+    ssl_extlist_by_oid_func = APR_RETRIEVE_OPTIONAL_FN(ssl_extlist_by_oid);
+    return OK;
+}
+
 static void register_hooks(apr_pool_t *p)
 {
     ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
+    /* post config handling */
+    ap_hook_post_config(setenvif_post_config, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 module AP_MODULE_DECLARE_DATA setenvif_module =
index 0fcbd5228310431b235e9f66110e6675184eeffd..4fcb172dfa2940629aa7c12becd67cf62c85784d 100644 (file)
@@ -503,6 +503,8 @@ static void ssl_register_hooks(apr_pool_t *p)
 
     APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
     APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
+
+    APR_REGISTER_OPTIONAL_FN(ssl_extlist_by_oid);
 }
 
 module AP_MODULE_DECLARE_DATA ssl_module = {
index fdde6411965b2230b829bb07223f2b0a4745d5c3..5cc37c1ee64fda7050b36fc797e1310c18b4b0d4 100644 (file)
@@ -49,4 +49,7 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
 
 APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
 
+extern apr_array_header_t *ssl_extlist_by_oid(request_rec *r, const char *oidstr);
+APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr));
+
 #endif /* __MOD_SSL_H__ */
index 4492eaf944b4689450a002835f760195ce49c63e..3350437a9485081c5e2717c81c74fdfba158217d 100644 (file)
@@ -36,7 +36,7 @@
 
 static BOOL  ssl_expr_eval_comp(request_rec *, ssl_expr *);
 static char *ssl_expr_eval_word(request_rec *, ssl_expr *);
-static BOOL  ssl_expr_eval_oid(const char *w, request_rec *r, const char *oidstr);
+static BOOL  ssl_expr_eval_oid(request_rec *r, const char *word, const char *oidstr);
 static char *ssl_expr_eval_func_file(request_rec *, char *);
 static int   ssl_expr_eval_strcmplex(char *, char *);
 
@@ -121,7 +121,7 @@ static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node)
                 if (op == op_OidListElement) {
                     char *w3 = ssl_expr_eval_word(r, e3);
 
-                    found = ssl_expr_eval_oid(w1, r, w3);
+                    found = ssl_expr_eval_oid(r, w1, w3);
 
                     /* There will be no more nodes on the list, so the result is authoritative */
                     break;
@@ -198,33 +198,35 @@ static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node)
     }
 }
 
-static BOOL ssl_expr_eval_oid(const char *word, request_rec *r, const char *oidstr)
+#define NUM_OID_ELTS 8 /* start with 8 oid slots, resize when needed */
+
+apr_array_header_t *ssl_extlist_by_oid(request_rec *r, const char *oidstr)
 {
-    SSLConnRec *sslconn = myConnConfig(r->connection);
-    SSL *ssl;
+    int count = 0, j;
     X509 *xs = NULL;
     ASN1_OBJECT *oid;
-    int count = 0, j;
-    BOOL result = FALSE;
-
-    if (!oidstr || !sslconn || !sslconn->ssl)
-        return FALSE;
+    apr_array_header_t *val_array;
+    SSLConnRec *sslconn = myConnConfig(r->connection);
 
-    ssl = sslconn->ssl;
+    /* trivia */
+    if (oidstr == NULL || sslconn == NULL || sslconn->ssl == NULL)
+        return NULL;
 
-    oid = OBJ_txt2obj(oidstr, 1);
-    if (!oid) {
+    /* Determine the oid we are looking for */
+    if ((oid = OBJ_txt2obj(oidstr, 1)) == NULL) {
         ERR_clear_error();
-        return FALSE;
+        return NULL;
     }
 
-    xs = SSL_get_peer_certificate(ssl);
-    if (xs == NULL) {
-        return FALSE;
+    /* are there any extensions in the cert? */
+    if ((xs = SSL_get_peer_certificate(sslconn->ssl)) == NULL ||
+        (count = X509_get_ext_count(xs)) == 0) {
+        return NULL;
     }
 
-    count = X509_get_ext_count(xs);
+    val_array = apr_array_make(r->pool, NUM_OID_ELTS, sizeof(char *));
 
+    /* Loop over all extensions, extract the desired oids */
     for (j = 0; j < count; j++) {
         X509_EXTENSION *ext = X509_get_ext(xs, j);
 
@@ -233,21 +235,45 @@ static BOOL ssl_expr_eval_oid(const char *word, request_rec *r, const char *oids
 
             if (X509V3_EXT_print(bio, ext, 0, 0) == 1) {
                 BUF_MEM *buf;
+                char **new = apr_array_push(val_array);
 
                 BIO_get_mem_ptr(bio, &buf);
 
-                if (strcmp(word, buf->data) == 0)
-                    result = TRUE;
+                *new = apr_pstrdup(r->pool, buf->data);
             }
 
             BIO_vfree(bio);
-            if (result != FALSE)
-                break;
         }
     }
 
     X509_free(xs);
     ERR_clear_error();
+
+    if (val_array->nelts == 0)
+        return NULL;
+    else
+        return val_array;
+}
+
+static BOOL ssl_expr_eval_oid(request_rec *r, const char *word, const char *oidstr)
+{
+    SSLConnRec *sslconn = myConnConfig(r->connection);
+    int j;
+    BOOL result = FALSE;
+    apr_array_header_t *oid_array;
+    char **oid_value;
+
+    if (NULL == (oid_array = ssl_extlist_by_oid(r, oidstr))) {
+        return FALSE;
+    }
+
+    oid_value = (char **) oid_array->elts;
+    for (j = 0; j < oid_array->nelts; j++) {
+        if (strcmp(word, oid_value[j]) == 0) {
+            result = TRUE;
+            break;
+        }
+    }
     return result;
 }