[Mono-dev] CRL Checking

Sebastien Pouliot sebastien.pouliot at gmail.com
Wed Aug 19 09:44:32 EDT 2009


Hello Alex,

On Wed, 2009-08-19 at 14:07 +0100, Alex Mason wrote:
> I'm attempting to use the Mono store system to store CRL files as part
> of a manual implementation of online CRL checking with
> X509Chain.Build(). Whereas X509Crl is an open object,
> Mono.Security.X509.X509Store has no public constructor, and seemingly
> no way to instantiate it or access it directly from a user program.

Have a look at X509Stores class to access well-known (properties) or
custom (the Open method) stores.

http://www.go-mono.org/docs/index.aspx?link=T%
3AMono.Security.X509.X509Stores.Names%2F*

>  This class contains the Import function for CRLs, although as far as
> I can tell it isn't called anywhere else within Mono. 

No, I never got the time to complete a full (gui) certificate manager
(nor some other features that would be required for one).

> At the moment I've implemented the online check by generating a chain,
> walking the elements and manually fetching the certificates, writing
> them to the correct file name for the CRL so they can be picked up by
> X509Chain.FindCrl

The "right way" is to query, from the store, a CRL for each certificate
(in the chain). If one is available then check if it's still valid. If
not (available or out-of-date) then you download a new one and update
the store.

This is important as some CRL are rarely updated and the certificate can
be used several times (e.g. check against a server) leading to severe
performance problems.

> Obviously it's be useful to have some way to access the Mono X509Store
> instead of relying on these hacks. I've not that familiar with the
> codebase, but if I'm not mistaken there's currently no way, and so I
> was thinking maybe it's possible to provide a public constructor for
> the store, or some system to allow importing and retrieval of CRLs?

see above

> On another note, I noticed X509Crl.Parse() assumes an unencoded format
> for CRLs,

as long as "unencoded == ASN.1 encoded" that right ;-)

>  although upon downloading a few test ones I realised quite a few come
> base64 encoded, so I created the following function, based on
> Mono.Security.X509. X509Certificate.PEM 
>  
>         private static byte[] _DecodeCrlBase64(byte[] data)
>         {
>             string crl = Encoding.ASCII.GetString(data);
>  
>             string header = String.Format("-----BEGIN {0}-----", "X509
> CRL");
>             int start = crl.IndexOf(header) + header.Length;
>  
>             if (start - header.Length == -1)
>                 return data;
>  
>             string footer = String.Format("-----END {0}-----", "X509
> CRL");
>             int end = crl.IndexOf(footer, start);
>             
>             string base64 = crl.Substring(start, (end - start));
>             return Convert.FromBase64String(base64);
>         }
>  
>  
> I also had troubles with FindCrl, mainly:
>  
>         if ((ski.Length == 0) || (ski == GetAuthorityKeyIdentifier
> (crl)))
>      return crl;
>  
> this line seems to impose a mandatory Authority Key Identifier
> (2.5.29.35) check. According to
> http://www.redhat.com/docs/manuals/cert-system/admin/7.1/app_ext.html

Avoid using old, pre-standard, documents (2001) and refer to the newer
RFC (e.g. 3280).

>  this extension is non-critical and "If this extension is not present,
> then the issuer name alone is used to identify the issuer
> certificate.".

Criticality can be suggested/mandated by a profile (like PKIX/RFC3280
are) but (the fun part) is that everyone got it's own profile ;-) Anyway
the code itself cannot assume something is [non-]critical - but must
deal with how the extension is encoded.

>  
> Hence, I believe the check should be optional, replacing the above
> line in both places with something along the lines of:
>  
>         string aki = GetAuthorityKeyIdentifier (crl);
>   
>         if ((ski.Length == 0) || (String.IsNullOrEmpty(aki) || ski ==
> aki))
>             return crl;

I would need to re-read the spec before changing this.

> I haven't got any real functional knowledge of the theory behind the
> CRL checks, apart from checking the related RFCs, specs and general
> internet resources. However, I would like to contribute with this, and
> it'd be great to get online CRL checking working in a future release
> of Mono, as well as opening up the functionality for dealing with CRLs
> in the store. 

There's not a big distinction between them. "online" does not mean
"always download CRL", it means that it can update the stored [delta]
CRL and use OCSP (when available). "offline" means its limited to what's
available in the store.

> I know on top of just downloading if not found, there should be some
> checking to ensure CRls are updated should they be found to be out of
> date, although I don't know if this should occur in the
> X509Chain.Build method or not.

My original idea was to provide an optional, cron-based, script/tool to
update all CRL from every store (when they become out-of-date). That
would reduce the need (and impact) of downloading CRL from X509Chain
itself.
 
> Hopefully someone more knowledge can give advice on how best to go
> about all of this.

Have a look at the existing unit tests, in particular the ones that are
disabled by default (the PKITS-based tests). See the README inside
/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/pkits/
for more details. Many sections are not yet tested (because the features
were missing) and no (existing) tests should regress when adding the new
features.

Sebastien




More information about the Mono-devel-list mailing list