Loading Documentation/kernel-parameters.txt +5 −0 Original line number Diff line number Diff line Loading @@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. possible to determine what the correct size should be. This option provides an override for these situations. ca_keys= [KEYS] This parameter identifies a specific key(s) on the system trusted keyring to be used for certificate trust validation. format: { id:<keyid> | builtin } ccw_timeout_log [S390] See Documentation/s390/CommonIO for details. Loading crypto/asymmetric_keys/asymmetric_keys.h +2 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ * 2 of the Licence, or (at your option) any later version. */ int asymmetric_keyid_match(const char *kid, const char *id); static inline const char *asymmetric_key_id(const struct key *key) { return key->type_data.p[1]; Loading crypto/asymmetric_keys/asymmetric_type.c +32 −19 Original line number Diff line number Diff line Loading @@ -22,6 +22,35 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(asymmetric_key_parsers); static DECLARE_RWSEM(asymmetric_key_parsers_sem); /* * Match asymmetric key id with partial match * @id: key id to match in a form "id:<id>" */ int asymmetric_keyid_match(const char *kid, const char *id) { size_t idlen, kidlen; if (!kid || !id) return 0; /* make it possible to use id as in the request: "id:<id>" */ if (strncmp(id, "id:", 3) == 0) id += 3; /* Anything after here requires a partial match on the ID string */ idlen = strlen(id); kidlen = strlen(kid); if (idlen > kidlen) return 0; kid += kidlen - idlen; if (strcasecmp(id, kid) != 0) return 0; return 1; } EXPORT_SYMBOL_GPL(asymmetric_keyid_match); /* * Match asymmetric keys on (part of) their name * We have some shorthand methods for matching keys. We allow: Loading @@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) { const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); const char *spec = description; const char *id, *kid; const char *id; ptrdiff_t speclen; size_t idlen, kidlen; if (!subtype || !spec || !*spec) return 0; Loading @@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) speclen = id - spec; id++; /* Anything after here requires a partial match on the ID string */ kid = asymmetric_key_id(key); if (!kid) return 0; idlen = strlen(id); kidlen = strlen(kid); if (idlen > kidlen) return 0; kid += kidlen - idlen; if (strcasecmp(id, kid) != 0) return 0; if (speclen == 2 && memcmp(spec, "id", 2) == 0) return 1; if (speclen == 2 && memcmp(spec, "id", 2) == 0) return asymmetric_keyid_match(asymmetric_key_id(key), id); if (speclen == subtype->name_len && memcmp(spec, subtype->name, speclen) == 0) Loading crypto/asymmetric_keys/x509_public_key.c +108 −1 Original line number Diff line number Diff line Loading @@ -18,11 +18,80 @@ #include <linux/asn1_decoder.h> #include <keys/asymmetric-subtype.h> #include <keys/asymmetric-parser.h> #include <keys/system_keyring.h> #include <crypto/hash.h> #include "asymmetric_keys.h" #include "public_key.h" #include "x509_parser.h" static bool use_builtin_keys; static char *ca_keyid; #ifndef MODULE static int __init ca_keys_setup(char *str) { if (!str) /* default system keyring */ return 1; if (strncmp(str, "id:", 3) == 0) ca_keyid = str; /* owner key 'id:xxxxxx' */ else if (strcmp(str, "builtin") == 0) use_builtin_keys = true; return 1; } __setup("ca_keys=", ca_keys_setup); #endif /* * Find a key in the given keyring by issuer and authority. */ static struct key *x509_request_asymmetric_key(struct key *keyring, const char *signer, size_t signer_len, const char *authority, size_t auth_len) { key_ref_t key; char *id; /* Construct an identifier. */ id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); if (!id) return ERR_PTR(-ENOMEM); memcpy(id, signer, signer_len); id[signer_len + 0] = ':'; id[signer_len + 1] = ' '; memcpy(id + signer_len + 2, authority, auth_len); id[signer_len + 2 + auth_len] = 0; pr_debug("Look up: \"%s\"\n", id); key = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key)) pr_debug("Request for module key '%s' err %ld\n", id, PTR_ERR(key)); kfree(id); if (IS_ERR(key)) { switch (PTR_ERR(key)) { /* Hide some search errors */ case -EACCES: case -ENOTDIR: case -EAGAIN: return ERR_PTR(-ENOKEY); default: return ERR_CAST(key); } } pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); return key_ref_to_ptr(key); } /* * Set up the signature parameters in an X.509 certificate. This involves * digesting the signed data and extracting the signature. Loading Loading @@ -102,6 +171,40 @@ int x509_check_signature(const struct public_key *pub, } EXPORT_SYMBOL_GPL(x509_check_signature); /* * Check the new certificate against the ones in the trust keyring. If one of * those is the signing key and validates the new certificate, then mark the * new certificate as being trusted. * * Return 0 if the new certificate was successfully validated, 1 if we couldn't * find a matching parent certificate in the trusted list and an error if there * is a matching certificate but the signature check fails. */ static int x509_validate_trust(struct x509_certificate *cert, struct key *trust_keyring) { struct key *key; int ret = 1; if (!trust_keyring) return -EOPNOTSUPP; if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) return -EPERM; key = x509_request_asymmetric_key(trust_keyring, cert->issuer, strlen(cert->issuer), cert->authority, strlen(cert->authority)); if (!IS_ERR(key)) { if (!use_builtin_keys || test_bit(KEY_FLAG_BUILTIN, &key->flags)) ret = x509_check_signature(key->payload.data, cert); key_put(key); } return ret; } /* * Attempt to parse a data blob for a key as an X509 certificate. */ Loading Loading @@ -155,9 +258,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) /* Check the signature on the key if it appears to be self-signed */ if (!cert->authority || strcmp(cert->fingerprint, cert->authority) == 0) { ret = x509_check_signature(cert->pub, cert); ret = x509_check_signature(cert->pub, cert); /* self-signed */ if (ret < 0) goto error_free_cert; } else if (!prep->trusted) { ret = x509_validate_trust(cert, get_system_trusted_keyring()); if (!ret) prep->trusted = 1; } /* Propose a description */ Loading include/keys/system_keyring.h +9 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,15 @@ #include <linux/key.h> extern struct key *system_trusted_keyring; static inline struct key *get_system_trusted_keyring(void) { return system_trusted_keyring; } #else static inline struct key *get_system_trusted_keyring(void) { return NULL; } #endif #endif /* _KEYS_SYSTEM_KEYRING_H */ Loading
Documentation/kernel-parameters.txt +5 −0 Original line number Diff line number Diff line Loading @@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. possible to determine what the correct size should be. This option provides an override for these situations. ca_keys= [KEYS] This parameter identifies a specific key(s) on the system trusted keyring to be used for certificate trust validation. format: { id:<keyid> | builtin } ccw_timeout_log [S390] See Documentation/s390/CommonIO for details. Loading
crypto/asymmetric_keys/asymmetric_keys.h +2 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ * 2 of the Licence, or (at your option) any later version. */ int asymmetric_keyid_match(const char *kid, const char *id); static inline const char *asymmetric_key_id(const struct key *key) { return key->type_data.p[1]; Loading
crypto/asymmetric_keys/asymmetric_type.c +32 −19 Original line number Diff line number Diff line Loading @@ -22,6 +22,35 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(asymmetric_key_parsers); static DECLARE_RWSEM(asymmetric_key_parsers_sem); /* * Match asymmetric key id with partial match * @id: key id to match in a form "id:<id>" */ int asymmetric_keyid_match(const char *kid, const char *id) { size_t idlen, kidlen; if (!kid || !id) return 0; /* make it possible to use id as in the request: "id:<id>" */ if (strncmp(id, "id:", 3) == 0) id += 3; /* Anything after here requires a partial match on the ID string */ idlen = strlen(id); kidlen = strlen(kid); if (idlen > kidlen) return 0; kid += kidlen - idlen; if (strcasecmp(id, kid) != 0) return 0; return 1; } EXPORT_SYMBOL_GPL(asymmetric_keyid_match); /* * Match asymmetric keys on (part of) their name * We have some shorthand methods for matching keys. We allow: Loading @@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) { const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); const char *spec = description; const char *id, *kid; const char *id; ptrdiff_t speclen; size_t idlen, kidlen; if (!subtype || !spec || !*spec) return 0; Loading @@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) speclen = id - spec; id++; /* Anything after here requires a partial match on the ID string */ kid = asymmetric_key_id(key); if (!kid) return 0; idlen = strlen(id); kidlen = strlen(kid); if (idlen > kidlen) return 0; kid += kidlen - idlen; if (strcasecmp(id, kid) != 0) return 0; if (speclen == 2 && memcmp(spec, "id", 2) == 0) return 1; if (speclen == 2 && memcmp(spec, "id", 2) == 0) return asymmetric_keyid_match(asymmetric_key_id(key), id); if (speclen == subtype->name_len && memcmp(spec, subtype->name, speclen) == 0) Loading
crypto/asymmetric_keys/x509_public_key.c +108 −1 Original line number Diff line number Diff line Loading @@ -18,11 +18,80 @@ #include <linux/asn1_decoder.h> #include <keys/asymmetric-subtype.h> #include <keys/asymmetric-parser.h> #include <keys/system_keyring.h> #include <crypto/hash.h> #include "asymmetric_keys.h" #include "public_key.h" #include "x509_parser.h" static bool use_builtin_keys; static char *ca_keyid; #ifndef MODULE static int __init ca_keys_setup(char *str) { if (!str) /* default system keyring */ return 1; if (strncmp(str, "id:", 3) == 0) ca_keyid = str; /* owner key 'id:xxxxxx' */ else if (strcmp(str, "builtin") == 0) use_builtin_keys = true; return 1; } __setup("ca_keys=", ca_keys_setup); #endif /* * Find a key in the given keyring by issuer and authority. */ static struct key *x509_request_asymmetric_key(struct key *keyring, const char *signer, size_t signer_len, const char *authority, size_t auth_len) { key_ref_t key; char *id; /* Construct an identifier. */ id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); if (!id) return ERR_PTR(-ENOMEM); memcpy(id, signer, signer_len); id[signer_len + 0] = ':'; id[signer_len + 1] = ' '; memcpy(id + signer_len + 2, authority, auth_len); id[signer_len + 2 + auth_len] = 0; pr_debug("Look up: \"%s\"\n", id); key = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key)) pr_debug("Request for module key '%s' err %ld\n", id, PTR_ERR(key)); kfree(id); if (IS_ERR(key)) { switch (PTR_ERR(key)) { /* Hide some search errors */ case -EACCES: case -ENOTDIR: case -EAGAIN: return ERR_PTR(-ENOKEY); default: return ERR_CAST(key); } } pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); return key_ref_to_ptr(key); } /* * Set up the signature parameters in an X.509 certificate. This involves * digesting the signed data and extracting the signature. Loading Loading @@ -102,6 +171,40 @@ int x509_check_signature(const struct public_key *pub, } EXPORT_SYMBOL_GPL(x509_check_signature); /* * Check the new certificate against the ones in the trust keyring. If one of * those is the signing key and validates the new certificate, then mark the * new certificate as being trusted. * * Return 0 if the new certificate was successfully validated, 1 if we couldn't * find a matching parent certificate in the trusted list and an error if there * is a matching certificate but the signature check fails. */ static int x509_validate_trust(struct x509_certificate *cert, struct key *trust_keyring) { struct key *key; int ret = 1; if (!trust_keyring) return -EOPNOTSUPP; if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) return -EPERM; key = x509_request_asymmetric_key(trust_keyring, cert->issuer, strlen(cert->issuer), cert->authority, strlen(cert->authority)); if (!IS_ERR(key)) { if (!use_builtin_keys || test_bit(KEY_FLAG_BUILTIN, &key->flags)) ret = x509_check_signature(key->payload.data, cert); key_put(key); } return ret; } /* * Attempt to parse a data blob for a key as an X509 certificate. */ Loading Loading @@ -155,9 +258,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) /* Check the signature on the key if it appears to be self-signed */ if (!cert->authority || strcmp(cert->fingerprint, cert->authority) == 0) { ret = x509_check_signature(cert->pub, cert); ret = x509_check_signature(cert->pub, cert); /* self-signed */ if (ret < 0) goto error_free_cert; } else if (!prep->trusted) { ret = x509_validate_trust(cert, get_system_trusted_keyring()); if (!ret) prep->trusted = 1; } /* Propose a description */ Loading
include/keys/system_keyring.h +9 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,15 @@ #include <linux/key.h> extern struct key *system_trusted_keyring; static inline struct key *get_system_trusted_keyring(void) { return system_trusted_keyring; } #else static inline struct key *get_system_trusted_keyring(void) { return NULL; } #endif #endif /* _KEYS_SYSTEM_KEYRING_H */