[krbdev.mit.edu #7183] PKINIT should handle CMS SignedData without certificates

Greg Hudson via RT rt-comment at krbdev.mit.edu
Thu Jun 21 16:28:52 EDT 2012


A KDC reply to a Diffie-Hellman PKINIT request contains an RFC 3852 
SignedData object with a payload (the DH reply), an optional set of 
certificates, and a SignerInfo object.  The SignerInfo object contains 
the identifier of the signing certificate and the signature itself.

RFC 4556 explicitly allows the SignedData certificates set to be omitted 
if the request's kdcPkId matches the signer certificate; otherwise the 
certificates "SHOULD be sufficient to construct at least one 
certification path from the KDC certificate to one trust anchor 
acceptable by the client".  If the signer certificate is itself a trust 
anchor as presented by the client, then it could also be considered 
reasonable for the KDC to omit the certificates field of the SignedData, 
as no certificates are needed to construct a path.

At present, we never (at least with OpenSSL) specify a kdcPkId value in 
the request; there is code to construct it, but it relies on 
pkinit_get_kdc_cert() doing something non-trivial, which it currently 
doesn't.  So a KDC will never omit the certificate field on account of a 
kdcPkId value we send, as things stand.

But it is easy enough to tell the client that the KDC certificate is a 
trust anchor, in which case a Heimdal KDC will reply with no 
certificates because it removes trust anchors from the set of 
certificates in the reply.  So we ought to handle at least the case 
where the SignerInfo sid is a trust anchor, rather than a certificate in 
the SignedData message.  We arguably also be able to handle the case 
where the SignerInfo sid is an intermediate certificate (though we don't 
tell the KDC about those, I don't think) or is the ID we put into 
kdcPkId (although we currently never put an ID there).

At current there are three code paths for verifying the CMS SignedData 
value: NSS, OpenSSL 1.0.x with CMS functions, and OpenSSL 0.9.x with the 
older PKCS7 functions.  The NSS code looks like it might already work 
for these cases, but I'm not sure.  The OpenSSL code wants to start by 
extracting the signer cert, verify that cert, and then verify the 
signature against the certificate with CMS_verify or PKCS7_verify.

With OpenSSL 0.9.x, we use PKCS7_cert_from_signer_info(), which only 
works if the SignedData supplies the certificate.  I'm not sure of an 
easy way to fix the bug for this case, and time will eventually carry us 
past having to worry about OpenSSL 0.9.x anyway.

With OpenSSL 1.0.x, we call CMS_set1_signers_certs(cms, NULL, 0) to 
match the signer ID against the certificates in the cms message, and 
then call CMS_SignerInfo_get0_algs to get the certificate which has (we 
hope) been set in the signer info.  We can use the second argument of 
CMS_set1_signers_certs to match the signer ID against other certificates 
sets such as the configured trusted anchors and intermediate certs.  If 
we ever build out pkinit_get_kdc_cert(), we'll need to match against 
that as well.

Thanks to Henry Hotz and Nalin Dahyabhai for their help in investigating 
this issue.


More information about the krb5-bugs mailing list