PKCS#7: Support CMS messages also [RFC5652]
authorDavid Howells <dhowells@redhat.com>
Mon, 20 Jul 2015 20:16:33 +0000 (21:16 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 12 Aug 2015 16:01:01 +0000 (17:01 +0100)
Since CMS is an evolution of PKCS#7, with much of the ASN.1 being
compatible, add support for CMS signed-data messages also [RFC5652 sec 5].

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-By: David Woodhouse <David.Woodhouse@intel.com>
crypto/asymmetric_keys/pkcs7.asn1
crypto/asymmetric_keys/pkcs7_parser.c
crypto/asymmetric_keys/pkcs7_parser.h

index 05504431e1c13afa15c6f438f90bb201cfaf8eb9..6bf8ff4f7414ee7bb9aa7ae833e212f6aa010178 100644 (file)
@@ -69,7 +69,7 @@ SignerInfos ::= CHOICE {
 
 SignerInfo ::= SEQUENCE {
        version                 INTEGER ({ pkcs7_note_signerinfo_version }),
-       issuerAndSerialNumber   IssuerAndSerialNumber,
+       sid                     SignerIdentifier, -- CMS variant, not PKCS#7
        digestAlgorithm         DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
        authenticatedAttributes CHOICE {
                aaSet           [0] IMPLICIT SetOfAuthenticatedAttribute
@@ -88,6 +88,12 @@ SignerInfo ::= SEQUENCE {
        } OPTIONAL
 } ({ pkcs7_note_signed_info })
 
+SignerIdentifier ::= CHOICE {
+       -- RFC5652 sec 5.3
+       issuerAndSerialNumber IssuerAndSerialNumber,
+        subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier
+}
+
 IssuerAndSerialNumber ::= SEQUENCE {
        issuer                  Name ({ pkcs7_sig_note_issuer }),
        serialNumber            CertificateSerialNumber ({ pkcs7_sig_note_serial })
@@ -95,6 +101,8 @@ IssuerAndSerialNumber ::= SEQUENCE {
 
 CertificateSerialNumber ::= INTEGER
 
+SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid })
+
 SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
 
 AuthenticatedAttribute ::= SEQUENCE {
index ab427f04b2992e9310fce22ec37e84dabcf7356c..826e2f3f507bd8b233ccd428f3b78bb550dfa67b 100644 (file)
@@ -33,6 +33,9 @@ struct pkcs7_parse_context {
        unsigned        raw_serial_size;
        unsigned        raw_issuer_size;
        const void      *raw_issuer;
+       const void      *raw_skid;
+       unsigned        raw_skid_size;
+       bool            expect_skid;
 };
 
 /*
@@ -249,15 +252,21 @@ int pkcs7_note_signeddata_version(void *context, size_t hdrlen,
                                  unsigned char tag,
                                  const void *value, size_t vlen)
 {
+       struct pkcs7_parse_context *ctx = context;
        unsigned version;
 
        if (vlen != 1)
                goto unsupported;
 
-       version = *(const u8 *)value;
+       ctx->msg->version = version = *(const u8 *)value;
        switch (version) {
        case 1:
-               /* PKCS#7 SignedData [RFC2315 sec 9.1] */
+               /* PKCS#7 SignedData [RFC2315 sec 9.1]
+                * CMS ver 1 SignedData [RFC5652 sec 5.1]
+                */
+               break;
+       case 3:
+               /* CMS ver 3 SignedData [RFC2315 sec 5.1] */
                break;
        default:
                goto unsupported;
@@ -277,6 +286,7 @@ int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
                                  unsigned char tag,
                                  const void *value, size_t vlen)
 {
+       struct pkcs7_parse_context *ctx = context;
        unsigned version;
 
        if (vlen != 1)
@@ -285,7 +295,18 @@ int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
        version = *(const u8 *)value;
        switch (version) {
        case 1:
-               /* PKCS#7 SignerInfo [RFC2315 sec 9.2] */
+               /* PKCS#7 SignerInfo [RFC2315 sec 9.2]
+                * CMS ver 1 SignerInfo [RFC5652 sec 5.3]
+                */
+               if (ctx->msg->version != 1)
+                       goto version_mismatch;
+               ctx->expect_skid = false;
+               break;
+       case 3:
+               /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
+               if (ctx->msg->version == 1)
+                       goto version_mismatch;
+               ctx->expect_skid = true;
                break;
        default:
                goto unsupported;
@@ -296,6 +317,9 @@ int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
 unsupported:
        pr_warn("Unsupported SignerInfo version\n");
        return -EINVAL;
+version_mismatch:
+       pr_warn("SignedData-SignerInfo version mismatch\n");
+       return -EBADMSG;
 }
 
 /*
@@ -439,6 +463,22 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
        return 0;
 }
 
+/*
+ * Note the issuing cert's subjectKeyIdentifier
+ */
+int pkcs7_sig_note_skid(void *context, size_t hdrlen,
+                       unsigned char tag,
+                       const void *value, size_t vlen)
+{
+       struct pkcs7_parse_context *ctx = context;
+
+       pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
+
+       ctx->raw_skid = value;
+       ctx->raw_skid_size = vlen;
+       return 0;
+}
+
 /*
  * Note the signature data
  */
@@ -472,13 +512,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
        struct asymmetric_key_id *kid;
 
        /* Generate cert issuer + serial number key ID */
-       kid = asymmetric_key_generate_id(ctx->raw_serial,
-                                        ctx->raw_serial_size,
-                                        ctx->raw_issuer,
-                                        ctx->raw_issuer_size);
+       if (!ctx->expect_skid) {
+               kid = asymmetric_key_generate_id(ctx->raw_serial,
+                                                ctx->raw_serial_size,
+                                                ctx->raw_issuer,
+                                                ctx->raw_issuer_size);
+       } else {
+               kid = asymmetric_key_generate_id(ctx->raw_skid,
+                                                ctx->raw_skid_size,
+                                                "", 0);
+       }
        if (IS_ERR(kid))
                return PTR_ERR(kid);
 
+       pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
+
        sinfo->signing_cert_id = kid;
        sinfo->index = ++ctx->sinfo_index;
        *ctx->ppsinfo = sinfo;
index efc7dc9b8f9cfbc2ac9223e141239efb43bd60ae..790dd7cec82c3640135e728ceaac080eb7434054 100644 (file)
@@ -33,7 +33,9 @@ struct pkcs7_signed_info {
        unsigned        authattrs_len;
        const void      *authattrs;
 
-       /* Issuing cert serial number and issuer's name */
+       /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
+        * or issuing cert's SKID [CMS ver 3].
+        */
        struct asymmetric_key_id *signing_cert_id;
 
        /* Message signature.
@@ -50,6 +52,7 @@ struct pkcs7_message {
        struct x509_certificate *certs; /* Certificate list */
        struct x509_certificate *crl;   /* Revocation list */
        struct pkcs7_signed_info *signed_infos;
+       u8              version;        /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
 
        /* Content Data (or NULL) */
        enum OID        data_type;      /* Type of Data */