diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 10 | ||||
-rw-r--r-- | crypto/asymmetric_keys/restrict.c | 40 | ||||
-rw-r--r-- | crypto/asymmetric_keys/verify_pefile.c | 32 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 50 |
4 files changed, 113 insertions, 19 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 4fa769c4bcdb..f0d4ff3c20a8 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -79,16 +79,16 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, } if (sinfo->msgdigest_len != sig->digest_size) { - pr_debug("Sig %u: Invalid digest size (%u)\n", - sinfo->index, sinfo->msgdigest_len); + pr_warn("Sig %u: Invalid digest size (%u)\n", + sinfo->index, sinfo->msgdigest_len); ret = -EBADMSG; goto error; } if (memcmp(sig->digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) { - pr_debug("Sig %u: Message digest doesn't match\n", - sinfo->index); + pr_warn("Sig %u: Message digest doesn't match\n", + sinfo->index); ret = -EKEYREJECTED; goto error; } @@ -478,7 +478,7 @@ int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, const void *data, size_t datalen) { if (pkcs7->data) { - pr_debug("Data already supplied\n"); + pr_warn("Data already supplied\n"); return -EINVAL; } pkcs7->data = data; diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 6b1ac5f5896a..276bdb627498 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -108,6 +108,46 @@ int restrict_link_by_signature(struct key *dest_keyring, return ret; } +/** + * restrict_link_by_ca - Restrict additions to a ring of CA keys + * @dest_keyring: Keyring being linked to. + * @type: The type of key being added. + * @payload: The payload of the new key. + * @trust_keyring: Unused. + * + * Check if the new certificate is a CA. If it is a CA, then mark the new + * certificate as being ok to link. + * + * Returns 0 if the new certificate was accepted, -ENOKEY if the + * certificate is not a CA. -ENOPKG if the signature uses unsupported + * crypto, or some other error if there is a matching certificate but + * the signature check cannot be performed. + */ +int restrict_link_by_ca(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trust_keyring) +{ + const struct public_key *pkey; + + if (type != &key_type_asymmetric) + return -EOPNOTSUPP; + + pkey = payload->data[asym_crypto]; + if (!pkey) + return -ENOPKG; + if (!test_bit(KEY_EFLAG_CA, &pkey->key_eflags)) + return -ENOKEY; + if (!test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags)) + return -ENOKEY; + if (!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING_MAX)) + return 0; + if (test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags)) + return -ENOKEY; + + return 0; +} + static bool match_either_id(const struct asymmetric_key_id **pair, const struct asymmetric_key_id *single) { diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 7553ab18db89..22beaf2213a2 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c @@ -74,7 +74,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen, break; default: - pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic); + pr_warn("Unknown PEOPT magic = %04hx\n", pe32->magic); return -ELIBBAD; } @@ -95,7 +95,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen, ctx->certs_size = ddir->certs.size; if (!ddir->certs.virtual_address || !ddir->certs.size) { - pr_debug("Unsigned PE binary\n"); + pr_warn("Unsigned PE binary\n"); return -ENODATA; } @@ -127,7 +127,7 @@ static int pefile_strip_sig_wrapper(const void *pebuf, unsigned len; if (ctx->sig_len < sizeof(wrapper)) { - pr_debug("Signature wrapper too short\n"); + pr_warn("Signature wrapper too short\n"); return -ELIBBAD; } @@ -135,19 +135,23 @@ static int pefile_strip_sig_wrapper(const void *pebuf, pr_debug("sig wrapper = { %x, %x, %x }\n", wrapper.length, wrapper.revision, wrapper.cert_type); - /* Both pesign and sbsign round up the length of certificate table - * (in optional header data directories) to 8 byte alignment. + /* sbsign rounds up the length of certificate table (in optional + * header data directories) to 8 byte alignment. However, the PE + * specification states that while entries are 8-byte aligned, this is + * not included in their length, and as a result, pesign has not + * rounded up since 0.110. */ - if (round_up(wrapper.length, 8) != ctx->sig_len) { - pr_debug("Signature wrapper len wrong\n"); + if (wrapper.length > ctx->sig_len) { + pr_warn("Signature wrapper bigger than sig len (%x > %x)\n", + ctx->sig_len, wrapper.length); return -ELIBBAD; } if (wrapper.revision != WIN_CERT_REVISION_2_0) { - pr_debug("Signature is not revision 2.0\n"); + pr_warn("Signature is not revision 2.0\n"); return -ENOTSUPP; } if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) { - pr_debug("Signature certificate type is not PKCS\n"); + pr_warn("Signature certificate type is not PKCS\n"); return -ENOTSUPP; } @@ -160,7 +164,7 @@ static int pefile_strip_sig_wrapper(const void *pebuf, ctx->sig_offset += sizeof(wrapper); ctx->sig_len -= sizeof(wrapper); if (ctx->sig_len < 4) { - pr_debug("Signature data missing\n"); + pr_warn("Signature data missing\n"); return -EKEYREJECTED; } @@ -194,7 +198,7 @@ check_len: return 0; } not_pkcs7: - pr_debug("Signature data not PKCS#7\n"); + pr_warn("Signature data not PKCS#7\n"); return -ELIBBAD; } @@ -337,8 +341,8 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen, digest_size = crypto_shash_digestsize(tfm); if (digest_size != ctx->digest_len) { - pr_debug("Digest size mismatch (%zx != %x)\n", - digest_size, ctx->digest_len); + pr_warn("Digest size mismatch (%zx != %x)\n", + digest_size, ctx->digest_len); ret = -EBADMSG; goto error_no_desc; } @@ -369,7 +373,7 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen, * PKCS#7 certificate. */ if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) { - pr_debug("Digest mismatch\n"); + pr_warn("Digest mismatch\n"); ret = -EKEYREJECTED; } else { pr_debug("The digests match!\n"); diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 7a9b084e2043..0a7049b470c1 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -579,6 +579,34 @@ int x509_process_extension(void *context, size_t hdrlen, return 0; } + if (ctx->last_oid == OID_keyUsage) { + /* + * Get hold of the keyUsage bit string + * v[1] is the encoding size + * (Expect either 0x02 or 0x03, making it 1 or 2 bytes) + * v[2] is the number of unused bits in the bit string + * (If >= 3 keyCertSign is missing when v[1] = 0x02) + * v[3] and possibly v[4] contain the bit string + * + * From RFC 5280 4.2.1.3: + * 0x04 is where keyCertSign lands in this bit string + * 0x80 is where digitalSignature lands in this bit string + */ + if (v[0] != ASN1_BTS) + return -EBADMSG; + if (vlen < 4) + return -EBADMSG; + if (v[2] >= 8) + return -EBADMSG; + if (v[3] & 0x80) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_DIGITALSIG; + if (v[1] == 0x02 && v[2] <= 2 && (v[3] & 0x04)) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN; + else if (vlen > 4 && v[1] == 0x03 && (v[3] & 0x04)) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN; + return 0; + } + if (ctx->last_oid == OID_authorityKeyIdentifier) { /* Get hold of the CA key fingerprint */ ctx->raw_akid = v; @@ -586,6 +614,28 @@ int x509_process_extension(void *context, size_t hdrlen, return 0; } + if (ctx->last_oid == OID_basicConstraints) { + /* + * Get hold of the basicConstraints + * v[1] is the encoding size + * (Expect 0x2 or greater, making it 1 or more bytes) + * v[2] is the encoding type + * (Expect an ASN1_BOOL for the CA) + * v[3] is the contents of the ASN1_BOOL + * (Expect 1 if the CA is TRUE) + * vlen should match the entire extension size + */ + if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ)) + return -EBADMSG; + if (vlen < 2) + return -EBADMSG; + if (v[1] != vlen - 2) + return -EBADMSG; + if (vlen >= 4 && v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_CA; + return 0; + } + return 0; } |