PKCS#7: Support CMS messages also [RFC5652]
[firefly-linux-kernel-4.4.55.git] / crypto / asymmetric_keys / pkcs7_parser.c
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;