Implement OID checking for mod_ssl. This code allows for checking of arbitrary client
certificate extensions by OID, in a syntax like:
SSLRequire "BaDCA Generated Certificate" in Oid("2.16.840.1.113730.1.13") \
|| "committers" in Oid("1.3.6.1.4.1.18060.1")
Note the following:
* A given OID can occur multiple times in one cert, with different values. Therefore
the OID function compares the left-hand string against each of the OID values,
until a complete match is found. If none patches, the result is FALSE
* The left hand side can be another expression, so can be a reference to a variable
or an file() invocation etc.
* The OID is also just a reference to a string, or function, or whatever.
* My manual description is very short. Someone else please help improve the description
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@219940
13f79535-47bb-0310-9956-
ffa450edef68
<usage>
<p>
This directive specifies a general access requirement which has to be
-fulfilled in order to allow access. It's a very powerful directive because the
+fulfilled in order to allow access. It is a very powerful directive because the
requirement specification is an arbitrarily complex boolean expression
containing any number of access checks.</p>
<note type="warning">
| word "<strong>></strong>" word | word "<strong>gt</strong>" word
| word "<strong>>=</strong>" word | word "<strong>ge</strong>" word
| word "<strong>in</strong>" "<strong>{</strong>" wordlist "<strong>}</strong>"
+ | word "<strong>in</strong>" "<strong>OID(</strong>" word "<strong>)</strong>"
| word "<strong>=~</strong>" regex
| word "<strong>!~</strong>" regex
and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \<br />
or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
</example>
+<p>The <code>OID()</code> function expects to find zero or more instances
+of the given OID in the client certificate, and compares the left-hand side
+string against the value of matching OID attributes. Every matching OID is
+checked, until a match is found.
+</p>
<p><em>Standard CGI/1.0 and Apache variables:</em></p>
<pre>
#endif
typedef enum {
- op_NOP, op_ListElement,
+ op_NOP, op_ListElement, op_OidListElement,
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
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 char *ssl_expr_eval_func_file(request_rec *, char *);
static int ssl_expr_eval_strcmplex(char *, char *);
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_OidListElement) {
+ char *w3 = ssl_expr_eval_word(r, e3);
+
+ found = ssl_expr_eval_oid(w1, r, 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;
}
}
+static BOOL ssl_expr_eval_oid(const char *word, request_rec *r, const char *oidstr)
+{
+ SSLConnRec *sslconn = myConnConfig(r->connection);
+ SSL *ssl;
+ X509 *xs = NULL;
+ ASN1_OBJECT *oid;
+ int count = 0, j;
+ BOOL result = FALSE;
+
+ if (!oidstr || !sslconn || !sslconn->ssl)
+ return FALSE;
+
+ ssl = sslconn->ssl;
+
+ oid = OBJ_txt2obj(oidstr, 1);
+ if (!oid) {
+ ERR_clear_error();
+ return FALSE;
+ }
+
+ xs = SSL_get_peer_certificate(ssl);
+ if (xs == NULL) {
+ return FALSE;
+ }
+
+ count = X509_get_ext_count(xs);
+
+ for (j = 0; j < count; j++) {
+ X509_EXTENSION *ext = X509_get_ext(xs, j);
+
+ if (OBJ_cmp(ext->object, oid) == 0) {
+ BIO *bio = BIO_new(BIO_s_mem());
+
+ if (X509V3_EXT_print(bio, ext, 0, 0) == 1) {
+ BUF_MEM *buf;
+
+ BIO_get_mem_ptr(bio, &buf);
+
+ if (strcmp(word, buf->data) == 0)
+ result = TRUE;
+ }
+
+ BIO_vfree(bio);
+ if (result != FALSE)
+ break;
+ }
+ }
+
+ X509_free(xs);
+ ERR_clear_error();
+ return result;
+}
+
+
static char *ssl_expr_eval_func_file(request_rec *r, char *filename)
{
apr_file_t *fp;
%token T_OP_REG
%token T_OP_NRE
%token T_OP_IN
+%token T_OP_OID
%token T_OP_OR
%token T_OP_AND
%type <exVal> funccall
%type <exVal> regex
%type <exVal> words
+%type <exVal> wordlist
%type <exVal> 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_OID '(' word ')' { $$ = ssl_expr_make(op_OidListElement, $3, NULL); }
+ | '{' words '}' { $$ = $2 ; }
+ ;
+
words : word { $$ = ssl_expr_make(op_ListElement, $1, NULL); }
| words ',' word { $$ = ssl_expr_make(op_ListElement, $3, $1); }
;
"not" { return T_OP_NOT; }
"!" { return T_OP_NOT; }
"in" { return T_OP_IN; }
+[Oo][Ii][Dd] { return T_OP_OID; }
/*
* Functions