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; }