Skip to content

Commit

Permalink
KEYS: verify a certificate is signed by a 'trusted' key
Browse files Browse the repository at this point in the history
Only public keys, with certificates signed by an existing
'trusted' key on the system trusted keyring, should be added
to a trusted keyring.  This patch adds support for verifying
a certificate's signature.

This is derived from David Howells pkcs7_request_asymmetric_key() patch.

Changelog v6:
- on error free key - Dmitry
- validate trust only for not already trusted keys - Dmitry
- formatting cleanup

Changelog:
- define get_system_trusted_keyring() to fix kbuild issues

Signed-off-by: Mimi Zohar <[email protected]>
Signed-off-by: David Howells <[email protected]>
Acked-by: Dmitry Kasatkin <[email protected]>
  • Loading branch information
Mimi Zohar committed Jul 17, 2014
1 parent a4e3b8d commit 3be4bea
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 2 deletions.
87 changes: 86 additions & 1 deletion crypto/asymmetric_keys/x509_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,61 @@
#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"

/*
* 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.
Expand Down Expand Up @@ -102,6 +152,37 @@ 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)
{
const struct public_key *pk;
struct key *key;
int ret = 1;

if (!trust_keyring)
return -EOPNOTSUPP;

key = x509_request_asymmetric_key(trust_keyring,
cert->issuer, strlen(cert->issuer),
cert->authority,
strlen(cert->authority));
if (!IS_ERR(key)) {
pk = key->payload.data;
ret = x509_check_signature(pk, cert);
key_put(key);
}
return ret;
}

/*
* Attempt to parse a data blob for a key as an X509 certificate.
*/
Expand Down Expand Up @@ -155,9 +236,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 */
Expand Down
10 changes: 9 additions & 1 deletion include/keys/system_keyring.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 3be4bea

Please sign in to comment.