Index: ssl_expr_eval.c =================================================================== --- ssl_expr_eval.c (revision 226665) +++ ssl_expr_eval.c (working copy) @@ -40,6 +40,58 @@ static char *ssl_expr_eval_func_file(request_rec *, char *); static int ssl_expr_eval_strcmplex(char *, char *); +/* Define AP_X509v3_EXT_DEBUG to list the actual + * OIDs found. + */ +#define AP_ASN1_IS_STRING(x) (\ + (x) == V_ASN1_OCTET_STRING || \ + (x) == V_ASN1_IA5STRING ||\ + (x) == V_ASN1_T61STRING || \ + (x) == V_ASN1_PRINTABLESTRING || \ + (x) == V_ASN1_UTF8STRING) + +/* Perl code to generate groups or just single strings.. + +#!/usr/bin/perl +# +use Convert::ASN1; +use strict; +$|++; + +my @groups = @ARGV + or die "Syntax: $0 ...\n"; + +my $asn = Convert::ASN1->new; + +# The difference between SEQUENCE and SET is in the order of transmission +# of the fields: for SEQUENCE, a sender is required to transmit them in +# the order listed in the notation; for SET, the order of transmission is +# an implementation option for the sender. The mod_ssl module detects +# both types. +# +my $bytes=''; +if ($#groups) { + $asn->prepare('str SET OF STRING'); # we're not order sensitive. + $bytes = $asn->encode(str => \@groups) + or die $!; +} else { + $asn->prepare('str STRING'); + $bytes = $asn->encode(str => $groups[0]) + or die $!; +} + +my $bytes = $asn->encode(str => \@groups) + or die $!; + +print "Line to include in OPENSSL config:\n"; + +print "DER"; +map { printf ":%02X",$_; } unpack('C*', $bytes);print "\n"; + +exit 0; + +*/ + BOOL ssl_expr_eval(request_rec *r, ssl_expr *node) { switch (node->node_op) { @@ -199,7 +251,6 @@ } #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) { int count = 0, j; @@ -229,7 +280,29 @@ /* Loop over all extensions, extract the desired oids */ for (j = 0; j < count; j++) { X509_EXTENSION *ext = X509_get_ext(xs, j); +#if AP_X509v3_EXT_DEBUG + { + char buff[16*1024]; + BUF_MEM *buf; + BIO *bio = BIO_new(BIO_s_mem()); + OBJ_obj2txt(buff, sizeof(buff), ext->object, 0); + if (X509V3_EXT_print(bio, ext, /* X509V3_EXT_ERROR_UNKNOWN */ X509V3_EXT_PARSE_UNKNOWN /* X509V3_EXT_DUMP_UNKNOWN */, 0) == 1) { + BIO_get_mem_ptr(bio, &buf); + + /* XXX for some reason the PARSE_UNK do not have a trailing \0 */ + buf->data[ buf->length -1 ] = 0; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "Extension '%s': %s", buff,buf->data); + }; + BIO_vfree(bio); + + }; +#endif +/* XXX not the most efficient way of doing this - we propably want to cache + * the strings extracted on the first call - and then serve from a cache + * for the repeated lookups on other oidstr's. + */ if (OBJ_cmp(ext->object, oid) == 0) { BIO *bio = BIO_new(BIO_s_mem()); @@ -238,13 +311,44 @@ char **new = apr_array_push(val_array); BIO_get_mem_ptr(bio, &buf); - *new = apr_pstrdup(r->pool, buf->data); - } - + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "X509v3 extension %s == '%s' found.", oidstr, *new); + } else + /* The above X509V3_EXT_print() only captures OID's which are a) hardcoded in openssl its objects.txt + * file, b) referenced in the asn1 parsing and c) listed as valid in the 509v3 extension code. Below + * we simply also accept any fields which have a normalish string in them. + */ + if (AP_ASN1_IS_STRING(ext->value->data[0])) { + char **new = apr_array_push(val_array); + *new = apr_pstrmemdup(r->pool, &(ext->value->data[2]), ext->value->data[1]); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Raw X509v3 extension %s == <%s> found in client certificate", oidstr, *new); + } else + /* And likewise accept any thing in a SET or SEQUENCE where at least the first + * element is a normal(ish) string. + */ + if (((ext->value->data[0] & 0x1F) == V_ASN1_SET || (ext->value->data[0] & 0x1F) == V_ASN1_SEQUENCE) && + (ext->value->data[1]>3) && (AP_ASN1_IS_STRING(ext->value->data[2]))) + { + int len = ext->value->data[1]; + int i = 2, j = 0; + while(i < len) { + j++; + if (AP_ASN1_IS_STRING(ext->value->data[i])) { + char **new = apr_array_push(val_array); + *new = apr_pstrmemdup(r->pool, &(ext->value->data[i+2]), ext->value->data[i+1]); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Raw set of X509v3 extensions %s, item %d <%s> found in client certificate", oidstr, j, *new); + } else + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Raw set of X509v3 extensions %s, ignoring item %d (not a string)", oidstr, j); + i += ext->value->data[i+1] + 2; + } + }; BIO_vfree(bio); } - } + } /* loop over all extensions */ X509_free(xs); ERR_clear_error();