On Thu, Oct 15, 2009 at 03:43:36PM +0200, Graham Leggett wrote:
> Joe Orton wrote:
> 
> > Are you trying to match against the contents of the (single) extKeyUsage 
> > extension?  That isn't how PeerExtList works, or at least, was written 
> > and documented to work, AFAICT: PeerExtList will return a list of the 
> > value of each extension in the cert with the given OID.
> > 
> > Does that make sense?  This is just from reading the trunk code/docs, I 
> > may be missing something.
> > 
> > To solve your problem: parsing the string which OpenSSL spits out as a 
> > representation of the extKeyUsage list would sound a bit hacky.  I guess 
> > I'd recommend doing it as a set of custom variables:
> > 
> >    SSL_{CLIENT,SERVER}_EXT_KEYUSAGE_{CLIENT_AUTH,EMAIL_PROTECTION,...}
> > 
> > which evaluate to 0 or 1 depending on whether the indicated usage is 
> > present in the extKeyUsage extension.  Would something like that work?
> 
> The problem I'm trying to solve is that we'll be issuing certs with our
> own extKeyUsage values, and I would imagine they would be inventing
> values with custom oids for various purposes, so something generic would
> be needed, as opposed to fixed "well known" oids.

OK, fair enough.  So, maybe just a function (bleh) which takes an OID 
and returns true/false if there is an extended key usage extension 
present with the given key purpose OID listed?

    SSLRequire PeerKeyPurpose("OID")

> One of the key things I was struggling with was trying to understand how
> it currently was supposed to work, so I didn't hack it in the wrong
> direction.
> 
> >From what I can see, we have a set of oid values (which in this case,
> extKeyUsage, which contains just one value: "A,B,C") associated with a
> key, which can in turn can contain a set of values (which in this case
> contains "A", "B" and "C").

Kind of.  A certificate can have any number of extensions.  Each 
extension is a (key, value) pair, where the key is an OID, and the value 
is an ASN.1 structure specific to the key.  When evaluating "foo in 
PeerExtList(bar)", mod_ssl will look at each extension with key OID 
'bar' and transform the associated ASN.1 structure to a string, then 
return true if any of those strings match 'foo'.

The "extended key usage" extension is defined simply as a list of OIDs - 
from the ASN.1 in RFC 5280:

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId 

KeyPurposeId ::= OBJECT IDENTIFIER

when you use PeerExtList on that structure, OpenSSL will do something 
random, unspecified, and possibly useful to that ASN.1 structure, to 
transform it into a string.  From your testing results, it makes a 
comma-separated string of the OID numbers.

The wrong way to solve this is to have OpenSSL go through all those 
hoops to transform the ASN.1 extension value into a string, parse the 
string, and then match against the returned OIDs.  The way OpenSSL does 
that is unspecified and may change - maybe it will use spaces to 
separate the OIDs in a future version, for example.  Who knows.

The right way to solve this is to extract the EXTENDED_KEY_USAGE OpenSSL 
data structure and match against the OIDs, without converting it to a 
string. SSL_X509_isSGC has an example of how to do this, though uses an 
older extension API; ssl_engine_ocsp.c:extract_responder_uri is a better 
example of using the OpenSSL extension API.

> Looking further at the expression syntax of SSLRequire, it looks like
> this might do the trick:
> 
>   SSLRequire "1.3.6.1.5.5.7.3.4" in { PeerExtList("2.5.29.37") }

This won't match the grammar - the docs do show this accurately, it must 
be SSLRequire "foo" in PeerExtList("..."), if you look at the code in 
ssl_expr_eval.c it has a special case for PeerExtList in the code 
handling the "in" operator.

Regards, Joe

Reply via email to