Hi,

The joined patch allows the use of client certificate extensions values (by 
long/short name or OID) in
the mod_ssl/SSLRequire directive.

This functionnality is available in the 2.2.x and trunk branches but hasn't 
been backported
in the 2.0.61, while this can be a very usefull feature (at least we need it 
for our product).

The backport is taken from trunk since it allows the use of long/short extensions names and it takes into account the token-name change done between 2.2.x and trunk (OID became PeerExtList): the patch allows both names to be used so that configuration files won't need changes.

Any hope this could be part of the 2.0.x branch so I won't need to patch the 
official release ?

Thanks for your comments,
yl.
diff -ruap httpd-2.0.61/modules/ssl/Makefile.in httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/Makefile.in
--- httpd-2.0.61/modules/ssl/Makefile.in	2006-07-12 09:40:55.000000000 +0200
+++ httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/Makefile.in	2007-12-18 13:06:19.000000000 +0100
@@ -36,3 +36,6 @@ ssl_expr_parse.c ssl_expr_parse.h: $(top
 	sed -e 's;yy;ssl_expr_yy;g' \
 	    <y.tab.h >ssl_expr_parse.h && rm -f y.tab.h
 
+clean:
+	rm -f ssl_expr_scan.c ssl_expr_parse.c ssl_expr_parse.h
+
diff -ruap httpd-2.0.61/modules/ssl/ssl_expr_eval.c httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr_eval.c
--- httpd-2.0.61/modules/ssl/ssl_expr_eval.c	2006-07-12 09:40:55.000000000 +0200
+++ httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr_eval.c	2007-12-18 13:38:37.000000000 +0100
@@ -36,6 +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_peer_ext_list(request_rec *r, const char *word, const char *extension);
 static char *ssl_expr_eval_func_file(request_rec *, char *);
 static int   ssl_expr_eval_strcmplex(char *, char *);
 
@@ -113,8 +114,19 @@ static BOOL ssl_expr_eval_comp(request_r
             char *w1 = ssl_expr_eval_word(r, e1);
             BOOL found = FALSE;
             do {
+                ssl_expr_node_op op = e2->node_op;
                 e3 = (ssl_expr *)e2->node_arg1;
                 e2 = (ssl_expr *)e2->node_arg2;
+
+                if (op == op_PeerExtElement) {
+                    char *w3 = ssl_expr_eval_word(r, e3);
+
+                    found = ssl_expr_eval_peer_ext_list(r, w1, w3);
+
+                    /* There will be no more nodes on the list, so the result is authoritative */
+                    break;
+                }
+
                 if (strcmp(w1, ssl_expr_eval_word(r, e3)) == 0) {
                     found = TRUE;
                     break;
@@ -186,6 +198,103 @@ static char *ssl_expr_eval_word(request_
     }
 }
 
+static apr_array_header_t *ssl_peer_ext_list(request_rec *r, const char *extension)
+{
+    int count = 0, j;
+    X509 *xs = NULL;
+    ASN1_OBJECT *obj;
+    apr_array_header_t *array;
+    SSLConnRec *sslconn = myConnConfig(r->connection);
+
+    /* trivia */
+    if (extension == NULL || sslconn == NULL || sslconn->ssl == NULL)
+        return NULL;
+
+    /* We accept the "extension" string to be converted as
+     * a long name (nsComment), short name (DN) or
+     * numeric OID (1.2.3.4).
+     */
+    if ((obj = OBJ_txt2obj(extension, 0)) == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "Failed to create an object for extension '%s'",
+                     extension);
+        ERR_clear_error();
+        return NULL;
+    }
+
+    /* are there any extensions in the cert? */
+    if ((xs = SSL_get_peer_certificate(sslconn->ssl)) == NULL) {
+        return NULL;
+    }
+
+    /* Compute the number of extensions in the cert */
+    if ((count = X509_get_ext_count(xs)) > 0) {
+    	/* Create an array large enough to accomodate every extension. This is
+     	 * likely overkill, but safe.
+     	 */
+    	array = apr_array_make(r->pool, count, sizeof(char *));
+
+    	/* Loop over all extensions, extract the desired values */
+    	for (j = 0; j < count; j++) {
+        	X509_EXTENSION *ext = X509_get_ext(xs, j);
+
+        	if (OBJ_cmp(ext->object, obj) == 0) {
+            		BIO *bio = BIO_new(BIO_s_mem());
+
+            		/* We want to obtain a string representation of the extensions
+             		 * value and add it to the array we're building.
+             		 * X509V3_EXT_print() doesn't know about all the possible
+             		 * data types, but the value is stored as an ASN1_OCTET_STRING
+             		 * allowing us a fallback in case of X509V3_EXT_print
+             		 * not knowing how to handle the data.
+             		 */
+            		if (X509V3_EXT_print(bio, ext, 0, 0) == 1 ||
+                		ASN1_STRING_print(bio, ext->value) == 1) {
+                		BUF_MEM *buf;
+                		char **ptr = apr_array_push(array);
+                		BIO_get_mem_ptr(bio, &buf);
+                		*ptr = apr_pstrmemdup(r->pool, buf->data, buf->length);
+            		} else {
+                		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             		"Found an extension '%s', but failed to "
+                             		"create a string from it", extension);
+            		}
+
+            		BIO_vfree(bio);
+        	}
+    	}
+
+    	if (array->nelts == 0)
+        	array = NULL;
+    }
+
+    X509_free(xs);
+
+    ERR_clear_error();
+    return array;
+}
+
+static BOOL ssl_expr_eval_peer_ext_list(request_rec *r, const char *word, const char *extension)
+{
+    int j;
+    BOOL result = FALSE;
+    apr_array_header_t *ext_array;
+    char **ext_values;
+
+    if (NULL == (ext_array = ssl_peer_ext_list(r, extension))) {
+        return FALSE;
+    }
+
+    ext_values = (char **) ext_array->elts;
+    for (j = 0; j < ext_array->nelts; j++) {
+        if (strcmp(word, ext_values[j]) == 0) {
+            result = TRUE;
+            break;
+        }
+    }
+    return result;
+}
+
 static char *ssl_expr_eval_func_file(request_rec *r, char *filename)
 {
     apr_file_t *fp;
diff -ruap httpd-2.0.61/modules/ssl/ssl_expr.h httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr.h
--- httpd-2.0.61/modules/ssl/ssl_expr.h	2006-07-12 09:40:55.000000000 +0200
+++ httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr.h	2007-12-18 13:06:19.000000000 +0100
@@ -61,7 +61,7 @@
 #endif
 
 typedef enum {
-    op_NOP, op_ListElement,
+    op_NOP, op_ListElement, op_PeerExtElement,
     op_True, op_False, op_Not, op_Or, op_And, op_Comp,
     op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE,
     op_Digit, op_String, op_Regex, op_Var, op_Func
diff -ruap httpd-2.0.61/modules/ssl/ssl_expr_parse.y httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr_parse.y
--- httpd-2.0.61/modules/ssl/ssl_expr_parse.y	2007-09-04 21:58:07.000000000 +0200
+++ httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr_parse.y	2007-12-18 14:03:58.000000000 +0100
@@ -61,6 +61,7 @@
 %token  T_OP_REG
 %token  T_OP_NRE
 %token  T_OP_IN
+%token  T_OP_PEEREXTLIST
 
 %token  T_OP_OR
 %token  T_OP_AND
@@ -75,6 +76,7 @@
 %type   <exVal>   funccall
 %type   <exVal>   regex
 %type   <exVal>   words
+%type   <exVal>   wordlist
 %type   <exVal>   word
 
 %%
@@ -97,11 +99,15 @@ comparison: word T_OP_EQ word           
           | word T_OP_LE word            { $$ = ssl_expr_make(op_LE,  $1, $3); }
           | word T_OP_GT word            { $$ = ssl_expr_make(op_GT,  $1, $3); }
           | word T_OP_GE word            { $$ = ssl_expr_make(op_GE,  $1, $3); }
-          | word T_OP_IN '{' words '}'   { $$ = ssl_expr_make(op_IN,  $1, $4); }
+          | word T_OP_IN wordlist        { $$ = ssl_expr_make(op_IN,  $1, $3); }
           | word T_OP_REG regex          { $$ = ssl_expr_make(op_REG, $1, $3); }
           | word T_OP_NRE regex          { $$ = ssl_expr_make(op_NRE, $1, $3); }
           ;
 
+wordlist  : T_OP_PEEREXTLIST '(' word ')'	 { $$ = ssl_expr_make(op_PeerExtElement, $3, NULL); }
+          | '{' words '}'                { $$ = $2 ; }
+          ;
+
 words     : word                         { $$ = ssl_expr_make(op_ListElement, $1, NULL); }
           | words ',' word               { $$ = ssl_expr_make(op_ListElement, $3, $1);   }
           ;
diff -ruap httpd-2.0.61/modules/ssl/ssl_expr_scan.l httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr_scan.l
--- httpd-2.0.61/modules/ssl/ssl_expr_scan.l	2007-09-04 21:58:08.000000000 +0200
+++ httpd-2.0.61+ssl_expr_peer_ext_list/modules/ssl/ssl_expr_scan.l	2007-12-18 13:30:56.000000000 +0100
@@ -175,6 +175,12 @@ int yyinput(char *buf, int max_size);
 "in"  { return T_OP_IN; }
 
  /*
+  * Backward compatibility "PeerExtList" <=> "OID"
+  */
+[Pp][Ee][Ee][Rr][Ee][Xx][Tt][Ll][Ii][Ss][Tt] |
+[Oo][Ii][Dd] { return T_OP_PEEREXTLIST; }
+
+ /*
   * Functions
   */
 "file" { return T_FUNC_FILE; }

Reply via email to