From 7f8da9915fcc6386edf86471bf31e162845930a4 Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Thu, 2 Mar 2023 11:46:47 -0500 Subject: KEYS: Create static version of public_key_verify_signature The kernel test robot reports undefined reference to public_key_verify_signature when CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not defined. Create a static version in this case and return -EINVAL. Fixes: db6c43bd2132 ("crypto: KEYS: convert public key and digsig asym to the akcipher api") Reported-by: kernel test robot Signed-off-by: Eric Snowberg Reviewed-by: Mimi Zohar Reviewed-by: Petr Vorel Reviewed-by: Jarkko Sakkinen Tested-by: Mimi Zohar Signed-off-by: Jarkko Sakkinen --- include/crypto/public_key.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include') diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 68f7aa2a7e55..6d61695e1cde 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -80,7 +80,16 @@ extern int create_signature(struct kernel_pkey_params *, const void *, void *); extern int verify_signature(const struct key *, const struct public_key_signature *); +#if IS_REACHABLE(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) int public_key_verify_signature(const struct public_key *pkey, const struct public_key_signature *sig); +#else +static inline +int public_key_verify_signature(const struct public_key *pkey, + const struct public_key_signature *sig) +{ + return -EINVAL; +} +#endif #endif /* _LINUX_PUBLIC_KEY_H */ -- cgit v1.2.3 From 30eae2b037af54b24109dcaea21db46f6285c69b Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Thu, 2 Mar 2023 11:46:49 -0500 Subject: KEYS: X.509: Parse Basic Constraints for CA Parse the X.509 Basic Constraints. The basic constraints extension identifies whether the subject of the certificate is a CA. BasicConstraints ::= SEQUENCE { cA BOOLEAN DEFAULT FALSE, pathLenConstraint INTEGER (0..MAX) OPTIONAL } If the CA is true, store it in the public_key. This will be used in a follow on patch that requires knowing if the public key is a CA. Link: https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.9 Signed-off-by: Eric Snowberg Reviewed-by: Mimi Zohar Reviewed-by: Jarkko Sakkinen Tested-by: Mimi Zohar Signed-off-by: Jarkko Sakkinen --- crypto/asymmetric_keys/x509_cert_parser.c | 22 ++++++++++++++++++++++ include/crypto/public_key.h | 2 ++ 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 7a9b084e2043..77547d4bd94d 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -586,6 +586,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; } diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 6d61695e1cde..c401762850f2 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -28,6 +28,8 @@ struct public_key { bool key_is_private; const char *id_type; const char *pkey_algo; + unsigned long key_eflags; /* key extension flags */ +#define KEY_EFLAG_CA 0 /* set if the CA basic constraints is set */ }; extern void public_key_free(struct public_key *key); -- cgit v1.2.3 From 567671281a751b80918a4531c4ba84b90a2a42c0 Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Thu, 2 Mar 2023 11:46:50 -0500 Subject: KEYS: X.509: Parse Key Usage Parse the X.509 Key Usage. The key usage extension defines the purpose of the key contained in the certificate. id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } KeyUsage ::= BIT STRING { digitalSignature (0), contentCommitment (1), keyEncipherment (2), dataEncipherment (3), keyAgreement (4), keyCertSign (5), cRLSign (6), encipherOnly (7), decipherOnly (8) } If the keyCertSign or digitalSignature is set, store it in the public_key structure. Having the purpose of the key being stored during parsing, allows enforcement on the usage field in the future. This will be used in a follow on patch that requires knowing the certificate key usage type. Link: https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3 Signed-off-by: Eric Snowberg Reviewed-by: Mimi Zohar Reviewed-by: Jarkko Sakkinen Tested-by: Mimi Zohar Signed-off-by: Jarkko Sakkinen --- crypto/asymmetric_keys/x509_cert_parser.c | 28 ++++++++++++++++++++++++++++ include/crypto/public_key.h | 2 ++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 77547d4bd94d..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; diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index c401762850f2..03c3fb990d59 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -30,6 +30,8 @@ struct public_key { const char *pkey_algo; unsigned long key_eflags; /* key extension flags */ #define KEY_EFLAG_CA 0 /* set if the CA basic constraints is set */ +#define KEY_EFLAG_DIGITALSIG 1 /* set if the digitalSignature usage is set */ +#define KEY_EFLAG_KEYCERTSIGN 2 /* set if the keyCertSign usage is set */ }; extern void public_key_free(struct public_key *key); -- cgit v1.2.3 From 76adb2fbc69a13c80b39042aab4d34e99309c8d4 Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Thu, 2 Mar 2023 11:46:51 -0500 Subject: KEYS: CA link restriction Add a new link restriction. Restrict the addition of keys in a keyring based on the key to be added being a CA. Signed-off-by: Eric Snowberg Reviewed-by: Mimi Zohar Reviewed-by: Jarkko Sakkinen Tested-by: Mimi Zohar Signed-off-by: Jarkko Sakkinen --- crypto/asymmetric_keys/restrict.c | 38 ++++++++++++++++++++++++++++++++++++++ include/crypto/public_key.h | 15 +++++++++++++++ 2 files changed, 53 insertions(+) (limited to 'include') diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 6b1ac5f5896a..48457c6f33f9 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -108,6 +108,44 @@ 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 (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/include/crypto/public_key.h b/include/crypto/public_key.h index 03c3fb990d59..653992a6e941 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -75,6 +75,21 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring, const union key_payload *payload, struct key *trusted); +#if IS_REACHABLE(CONFIG_ASYMMETRIC_KEY_TYPE) +extern int restrict_link_by_ca(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trust_keyring); +#else +static inline int restrict_link_by_ca(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trust_keyring) +{ + return 0; +} +#endif + extern int query_asymmetric_key(const struct kernel_pkey_params *, struct kernel_pkey_query *); -- cgit v1.2.3