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