X.509: Retain the key verification data
authorDavid Howells <dhowells@redhat.com>
Wed, 6 Apr 2016 15:13:33 +0000 (16:13 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 6 Apr 2016 15:13:33 +0000 (16:13 +0100)
Retain the key verification data (ie. the struct public_key_signature)
including the digest and the key identifiers.

Note that this means that we need to take a separate copy of the digest in
x509_get_sig_params() rather than lumping it in with the crypto layer data.

Signed-off-by: David Howells <dhowells@redhat.com>
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/pkcs7_verify.c
crypto/asymmetric_keys/x509_cert_parser.c
crypto/asymmetric_keys/x509_parser.h
crypto/asymmetric_keys/x509_public_key.c

index 7d7a39b47c6236a85cc5e9b3f5c42528a3c0fbb0..ed8128230dced612addbbfbe940ab849902f4bb5 100644 (file)
@@ -80,16 +80,16 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
                might_sleep();
                last = x509;
-               sig = &last->sig;
+               sig = last->sig;
        }
 
        /* No match - see if the root certificate has a signer amongst the
         * trusted keys.
         */
-       if (last && (last->akid_id || last->akid_skid)) {
+       if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
                key = x509_request_asymmetric_key(trust_keyring,
-                                                 last->akid_id,
-                                                 last->akid_skid,
+                                                 last->sig->auth_ids[0],
+                                                 last->sig->auth_ids[1],
                                                  false);
                if (!IS_ERR(key)) {
                        x509 = last;
index 50be2a15e5318432e2366cb96d92be7356a02197..d8d8d234874eaab8bd339da69906b5ca85ce4c37 100644 (file)
@@ -174,6 +174,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                                  struct pkcs7_signed_info *sinfo)
 {
+       struct public_key_signature *sig;
        struct x509_certificate *x509 = sinfo->signer, *p;
        struct asymmetric_key_id *auth;
        int ret;
@@ -193,14 +194,15 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                        goto maybe_missing_crypto_in_x509;
 
                pr_debug("- issuer %s\n", x509->issuer);
-               if (x509->akid_id)
+               sig = x509->sig;
+               if (sig->auth_ids[0])
                        pr_debug("- authkeyid.id %*phN\n",
-                                x509->akid_id->len, x509->akid_id->data);
-               if (x509->akid_skid)
+                                sig->auth_ids[0]->len, sig->auth_ids[0]->data);
+               if (sig->auth_ids[1])
                        pr_debug("- authkeyid.skid %*phN\n",
-                                x509->akid_skid->len, x509->akid_skid->data);
+                                sig->auth_ids[1]->len, sig->auth_ids[1]->data);
 
-               if ((!x509->akid_id && !x509->akid_skid) ||
+               if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) ||
                    strcmp(x509->subject, x509->issuer) == 0) {
                        /* If there's no authority certificate specified, then
                         * the certificate must be self-signed and is the root
@@ -224,7 +226,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                /* Look through the X.509 certificates in the PKCS#7 message's
                 * list to see if the next one is there.
                 */
-               auth = x509->akid_id;
+               auth = sig->auth_ids[0];
                if (auth) {
                        pr_debug("- want %*phN\n", auth->len, auth->data);
                        for (p = pkcs7->certs; p; p = p->next) {
@@ -234,7 +236,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                                        goto found_issuer_check_skid;
                        }
                } else {
-                       auth = x509->akid_skid;
+                       auth = sig->auth_ids[1];
                        pr_debug("- want %*phN\n", auth->len, auth->data);
                        for (p = pkcs7->certs; p; p = p->next) {
                                if (!p->skid)
@@ -254,8 +256,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                /* We matched issuer + serialNumber, but if there's an
                 * authKeyId.keyId, that must match the CA subjKeyId also.
                 */
-               if (x509->akid_skid &&
-                   !asymmetric_key_id_same(p->skid, x509->akid_skid)) {
+               if (sig->auth_ids[1] &&
+                   !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
                        pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
                                sinfo->index, x509->index, p->index);
                        return -EKEYREJECTED;
index 05251c7f9a0374fae66981ff22f8a337b2731016..a2fefa713614bd7135aa7eb1b3763da468fae3c2 100644 (file)
@@ -48,14 +48,11 @@ void x509_free_certificate(struct x509_certificate *cert)
 {
        if (cert) {
                public_key_free(cert->pub);
+               public_key_signature_free(cert->sig);
                kfree(cert->issuer);
                kfree(cert->subject);
                kfree(cert->id);
                kfree(cert->skid);
-               kfree(cert->akid_id);
-               kfree(cert->akid_skid);
-               kfree(cert->sig.digest);
-               kfree(cert->sig.s);
                kfree(cert);
        }
 }
@@ -78,6 +75,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
        cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
        if (!cert->pub)
                goto error_no_ctx;
+       cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
+       if (!cert->sig)
+               goto error_no_ctx;
        ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
        if (!ctx)
                goto error_no_ctx;
@@ -188,33 +188,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
                return -ENOPKG; /* Unsupported combination */
 
        case OID_md4WithRSAEncryption:
-               ctx->cert->sig.hash_algo = "md4";
-               ctx->cert->sig.pkey_algo = "rsa";
+               ctx->cert->sig->hash_algo = "md4";
+               ctx->cert->sig->pkey_algo = "rsa";
                break;
 
        case OID_sha1WithRSAEncryption:
-               ctx->cert->sig.hash_algo = "sha1";
-               ctx->cert->sig.pkey_algo = "rsa";
+               ctx->cert->sig->hash_algo = "sha1";
+               ctx->cert->sig->pkey_algo = "rsa";
                break;
 
        case OID_sha256WithRSAEncryption:
-               ctx->cert->sig.hash_algo = "sha256";
-               ctx->cert->sig.pkey_algo = "rsa";
+               ctx->cert->sig->hash_algo = "sha256";
+               ctx->cert->sig->pkey_algo = "rsa";
                break;
 
        case OID_sha384WithRSAEncryption:
-               ctx->cert->sig.hash_algo = "sha384";
-               ctx->cert->sig.pkey_algo = "rsa";
+               ctx->cert->sig->hash_algo = "sha384";
+               ctx->cert->sig->pkey_algo = "rsa";
                break;
 
        case OID_sha512WithRSAEncryption:
-               ctx->cert->sig.hash_algo = "sha512";
-               ctx->cert->sig.pkey_algo = "rsa";
+               ctx->cert->sig->hash_algo = "sha512";
+               ctx->cert->sig->pkey_algo = "rsa";
                break;
 
        case OID_sha224WithRSAEncryption:
-               ctx->cert->sig.hash_algo = "sha224";
-               ctx->cert->sig.pkey_algo = "rsa";
+               ctx->cert->sig->hash_algo = "sha224";
+               ctx->cert->sig->pkey_algo = "rsa";
                break;
        }
 
@@ -572,14 +572,14 @@ int x509_akid_note_kid(void *context, size_t hdrlen,
 
        pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
 
-       if (ctx->cert->akid_skid)
+       if (ctx->cert->sig->auth_ids[1])
                return 0;
 
        kid = asymmetric_key_generate_id(value, vlen, "", 0);
        if (IS_ERR(kid))
                return PTR_ERR(kid);
        pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-       ctx->cert->akid_skid = kid;
+       ctx->cert->sig->auth_ids[1] = kid;
        return 0;
 }
 
@@ -611,7 +611,7 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
 
        pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
 
-       if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
+       if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
                return 0;
 
        kid = asymmetric_key_generate_id(value,
@@ -622,6 +622,6 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
                return PTR_ERR(kid);
 
        pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-       ctx->cert->akid_id = kid;
+       ctx->cert->sig->auth_ids[0] = kid;
        return 0;
 }
index dbeed6018e63675db5316e254760f10e4a28a2b4..26a4d83e4e6da63bfbe4564ae3fd56cb73fa9c7d 100644 (file)
@@ -17,13 +17,11 @@ struct x509_certificate {
        struct x509_certificate *next;
        struct x509_certificate *signer;        /* Certificate that signed this one */
        struct public_key *pub;                 /* Public key details */
-       struct public_key_signature sig;        /* Signature parameters */
+       struct public_key_signature *sig;       /* Signature parameters */
        char            *issuer;                /* Name of certificate issuer */
        char            *subject;               /* Name of certificate subject */
        struct asymmetric_key_id *id;           /* Issuer + Serial number */
        struct asymmetric_key_id *skid;         /* Subject + subjectKeyId (optional) */
-       struct asymmetric_key_id *akid_id;      /* CA AuthKeyId matching ->id (optional) */
-       struct asymmetric_key_id *akid_skid;    /* CA AuthKeyId matching ->skid (optional) */
        time64_t        valid_from;
        time64_t        valid_to;
        const void      *tbs;                   /* Signed data */
index 2fcf707fb20867ab92281b4655a2a143f66dd5f2..4cd102de174c8274d9b4865d05f8a1d9f1d324dc 100644 (file)
@@ -153,30 +153,29 @@ EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
  */
 int x509_get_sig_params(struct x509_certificate *cert)
 {
+       struct public_key_signature *sig = cert->sig;
        struct crypto_shash *tfm;
        struct shash_desc *desc;
-       size_t digest_size, desc_size;
-       void *digest;
+       size_t desc_size;
        int ret;
 
        pr_devel("==>%s()\n", __func__);
 
        if (cert->unsupported_crypto)
                return -ENOPKG;
-       if (cert->sig.s)
+       if (sig->s)
                return 0;
 
-       cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size,
-                             GFP_KERNEL);
-       if (!cert->sig.s)
+       sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
+       if (!sig->s)
                return -ENOMEM;
 
-       cert->sig.s_size = cert->raw_sig_size;
+       sig->s_size = cert->raw_sig_size;
 
        /* Allocate the hashing algorithm we're going to need and find out how
         * big the hash operational data will be.
         */
-       tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0);
+       tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
        if (IS_ERR(tfm)) {
                if (PTR_ERR(tfm) == -ENOENT) {
                        cert->unsupported_crypto = true;
@@ -186,29 +185,28 @@ int x509_get_sig_params(struct x509_certificate *cert)
        }
 
        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-       digest_size = crypto_shash_digestsize(tfm);
+       sig->digest_size = crypto_shash_digestsize(tfm);
 
-       /* We allocate the hash operational data storage on the end of the
-        * digest storage space.
-        */
        ret = -ENOMEM;
-       digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
-                        GFP_KERNEL);
-       if (!digest)
+       sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
+       if (!sig->digest)
                goto error;
 
-       cert->sig.digest = digest;
-       cert->sig.digest_size = digest_size;
+       desc = kzalloc(desc_size, GFP_KERNEL);
+       if (!desc)
+               goto error;
 
-       desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
        desc->tfm = tfm;
        desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ret = crypto_shash_init(desc);
        if (ret < 0)
-               goto error;
+               goto error_2;
        might_sleep();
-       ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
+       ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
+
+error_2:
+       kfree(desc);
 error:
        crypto_free_shash(tfm);
        pr_devel("<==%s() = %d\n", __func__, ret);
@@ -230,7 +228,7 @@ int x509_check_signature(const struct public_key *pub,
        if (ret < 0)
                return ret;
 
-       ret = public_key_verify_signature(pub, &cert->sig);
+       ret = public_key_verify_signature(pub, cert->sig);
        if (ret == -ENOPKG)
                cert->unsupported_crypto = true;
        pr_debug("Cert Verification: %d\n", ret);
@@ -250,17 +248,18 @@ EXPORT_SYMBOL_GPL(x509_check_signature);
 static int x509_validate_trust(struct x509_certificate *cert,
                               struct key *trust_keyring)
 {
+       struct public_key_signature *sig = cert->sig;
        struct key *key;
        int ret = 1;
 
        if (!trust_keyring)
                return -EOPNOTSUPP;
 
-       if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
+       if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
                return -EPERM;
 
        key = x509_request_asymmetric_key(trust_keyring,
-                                         cert->akid_id, cert->akid_skid,
+                                         sig->auth_ids[0], sig->auth_ids[1],
                                          false);
        if (!IS_ERR(key))  {
                if (!use_builtin_keys
@@ -292,8 +291,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        pr_devel("Cert Subject: %s\n", cert->subject);
 
        if (!cert->pub->pkey_algo ||
-           !cert->sig.pkey_algo ||
-           !cert->sig.hash_algo) {
+           !cert->sig->pkey_algo ||
+           !cert->sig->hash_algo) {
                ret = -ENOPKG;
                goto error_free_cert;
        }
@@ -301,15 +300,15 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
        pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
        pr_devel("Cert Signature: %s + %s\n",
-                cert->sig.pkey_algo,
-                cert->sig.hash_algo);
+                cert->sig->pkey_algo,
+                cert->sig->hash_algo);
 
        cert->pub->id_type = "X509";
 
        /* Check the signature on the key if it appears to be self-signed */
-       if ((!cert->akid_skid && !cert->akid_id) ||
-           asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
-           asymmetric_key_id_same(cert->id, cert->akid_id)) {
+       if ((!cert->sig->auth_ids[0] && !cert->sig->auth_ids[1]) ||
+           asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]) ||
+           asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0])) {
                ret = x509_check_signature(cert->pub, cert); /* self-signed */
                if (ret < 0)
                        goto error_free_cert;
@@ -353,6 +352,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        prep->payload.data[asym_subtype] = &public_key_subtype;
        prep->payload.data[asym_key_ids] = kids;
        prep->payload.data[asym_crypto] = cert->pub;
+       prep->payload.data[asym_auth] = cert->sig;
        prep->description = desc;
        prep->quotalen = 100;
 
@@ -360,6 +360,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        cert->pub = NULL;
        cert->id = NULL;
        cert->skid = NULL;
+       cert->sig = NULL;
        desc = NULL;
        ret = 0;