|
@@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup);
|
|
|
/**
|
|
|
* x509_request_asymmetric_key - Request a key by X.509 certificate params.
|
|
|
* @keyring: The keys to search.
|
|
|
- * @kid: The key ID.
|
|
|
+ * @id: The issuer & serialNumber to look for or NULL.
|
|
|
+ * @skid: The subjectKeyIdentifier to look for or NULL.
|
|
|
* @partial: Use partial match if true, exact if false.
|
|
|
*
|
|
|
- * Find a key in the given keyring by subject name and key ID. These might,
|
|
|
- * for instance, be the issuer name and the authority key ID of an X.509
|
|
|
- * certificate that needs to be verified.
|
|
|
+ * Find a key in the given keyring by identifier. The preferred identifier is
|
|
|
+ * the issuer + serialNumber and the fallback identifier is the
|
|
|
+ * subjectKeyIdentifier. If both are given, the lookup is by the former, but
|
|
|
+ * the latter must also match.
|
|
|
*/
|
|
|
struct key *x509_request_asymmetric_key(struct key *keyring,
|
|
|
- const struct asymmetric_key_id *kid,
|
|
|
+ const struct asymmetric_key_id *id,
|
|
|
+ const struct asymmetric_key_id *skid,
|
|
|
bool partial)
|
|
|
{
|
|
|
- key_ref_t key;
|
|
|
- char *id, *p;
|
|
|
-
|
|
|
+ struct key *key;
|
|
|
+ key_ref_t ref;
|
|
|
+ const char *lookup;
|
|
|
+ char *req, *p;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ if (id) {
|
|
|
+ lookup = id->data;
|
|
|
+ len = id->len;
|
|
|
+ } else {
|
|
|
+ lookup = skid->data;
|
|
|
+ len = skid->len;
|
|
|
+ }
|
|
|
+
|
|
|
/* Construct an identifier "id:<keyid>". */
|
|
|
- p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
|
|
|
- if (!id)
|
|
|
+ p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
|
|
|
+ if (!req)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
if (partial) {
|
|
@@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
|
|
|
*p++ = 'x';
|
|
|
}
|
|
|
*p++ = ':';
|
|
|
- p = bin2hex(p, kid->data, kid->len);
|
|
|
+ p = bin2hex(p, lookup, len);
|
|
|
*p = 0;
|
|
|
|
|
|
- pr_debug("Look up: \"%s\"\n", id);
|
|
|
+ pr_debug("Look up: \"%s\"\n", req);
|
|
|
|
|
|
- key = keyring_search(make_key_ref(keyring, 1),
|
|
|
- &key_type_asymmetric, id);
|
|
|
- if (IS_ERR(key))
|
|
|
- pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
|
|
|
- kfree(id);
|
|
|
+ ref = keyring_search(make_key_ref(keyring, 1),
|
|
|
+ &key_type_asymmetric, req);
|
|
|
+ if (IS_ERR(ref))
|
|
|
+ pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
|
|
|
+ kfree(req);
|
|
|
|
|
|
- if (IS_ERR(key)) {
|
|
|
- switch (PTR_ERR(key)) {
|
|
|
+ if (IS_ERR(ref)) {
|
|
|
+ switch (PTR_ERR(ref)) {
|
|
|
/* Hide some search errors */
|
|
|
case -EACCES:
|
|
|
case -ENOTDIR:
|
|
|
case -EAGAIN:
|
|
|
return ERR_PTR(-ENOKEY);
|
|
|
default:
|
|
|
- return ERR_CAST(key);
|
|
|
+ return ERR_CAST(ref);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ key = key_ref_to_ptr(ref);
|
|
|
+ if (id && skid) {
|
|
|
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
|
|
|
+ if (!kids->id[1]) {
|
|
|
+ pr_debug("issuer+serial match, but expected SKID missing\n");
|
|
|
+ goto reject;
|
|
|
+ }
|
|
|
+ if (!asymmetric_key_id_same(skid, kids->id[1])) {
|
|
|
+ pr_debug("issuer+serial match, but SKID does not\n");
|
|
|
+ goto reject;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
|
|
|
+ return key;
|
|
|
|
|
|
- pr_devel("<==%s() = 0 [%x]\n", __func__,
|
|
|
- key_serial(key_ref_to_ptr(key)));
|
|
|
- return key_ref_to_ptr(key);
|
|
|
+reject:
|
|
|
+ key_put(key);
|
|
|
+ return ERR_PTR(-EKEYREJECTED);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
|
|
|
|
|
@@ -230,7 +260,8 @@ static int x509_validate_trust(struct x509_certificate *cert,
|
|
|
if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
|
|
|
return -EPERM;
|
|
|
|
|
|
- key = x509_request_asymmetric_key(trust_keyring, cert->akid_skid,
|
|
|
+ key = x509_request_asymmetric_key(trust_keyring,
|
|
|
+ cert->akid_id, cert->akid_skid,
|
|
|
false);
|
|
|
if (!IS_ERR(key)) {
|
|
|
if (!use_builtin_keys
|
|
@@ -287,8 +318,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
|
cert->pub->id_type = PKEY_ID_X509;
|
|
|
|
|
|
/* Check the signature on the key if it appears to be self-signed */
|
|
|
- if (!cert->akid_skid ||
|
|
|
- asymmetric_key_id_same(cert->skid, cert->akid_skid)) {
|
|
|
+ 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)) {
|
|
|
ret = x509_check_signature(cert->pub, cert); /* self-signed */
|
|
|
if (ret < 0)
|
|
|
goto error_free_cert;
|