Skip to content

Commit

Permalink
KEYS: Overhaul key identification when searching for asymmetric keys
Browse files Browse the repository at this point in the history
Make use of the new match string preparsing to overhaul key identification
when searching for asymmetric keys.  The following changes are made:

 (1) Use the previously created asymmetric_key_id struct to hold the following
     key IDs derived from the X.509 certificate or PKCS#7 message:

	id: serial number + issuer
	skid: subjKeyId + subject
	authority: authKeyId + issuer

 (2) Replace the hex fingerprint attached to key->type_data[1] with an
     asymmetric_key_ids struct containing the id and the skid (if present).

 (3) Make the asymmetric_type match data preparse select one of two searches:

     (a) An iterative search for the key ID given if prefixed with "id:".  The
     	 prefix is expected to be followed by a hex string giving the ID to
     	 search for.  The criterion key ID is checked against all key IDs
     	 recorded on the key.

     (b) A direct search if the key ID is not prefixed with "id:".  This will
     	 look for an exact match on the key description.

 (4) Make x509_request_asymmetric_key() take a key ID.  This is then converted
     into "id:<hex>" and passed into keyring_search() where match preparsing
     will turn it back into a binary ID.

 (5) X.509 certificate verification then takes the authority key ID and looks
     up a key that matches it to find the public key for the certificate
     signature.

 (6) PKCS#7 certificate verification then takes the id key ID and looks up a
     key that matches it to find the public key for the signed information
     block signature.

Additional changes:

 (1) Multiple subjKeyId and authKeyId values on an X.509 certificate cause the
     cert to be rejected with -EBADMSG.

 (2) The 'fingerprint' ID is gone.  This was primarily intended to convey PGP
     public key fingerprints.  If PGP is supported in future, this should
     generate a key ID that carries the fingerprint.

 (3) Th ca_keyid= kernel command line option is now converted to a key ID and
     used to match the authority key ID.  Possibly this should only match the
     actual authKeyId part and not the issuer as well.

Signed-off-by: David Howells <[email protected]>
Acked-by: Vivek Goyal <[email protected]>
  • Loading branch information
dhowells committed Sep 16, 2014
1 parent 7901c1a commit 46963b7
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 186 deletions.
4 changes: 2 additions & 2 deletions crypto/asymmetric_keys/asymmetric_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
* 2 of the Licence, or (at your option) any later version.
*/

int asymmetric_keyid_match(const char *kid, const char *id);
extern bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
const struct asymmetric_key_id *match_id);

extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);

static inline const char *asymmetric_key_id(const struct key *key)
static inline
const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
{
return key->type_data.p[1];
}
133 changes: 56 additions & 77 deletions crypto/asymmetric_keys/asymmetric_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,76 +112,15 @@ struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
}

/*
* 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:
*
* "<desc>" - request a key by description
* "id:<id>" - request a key matching the ID
* "<subtype>:<id>" - request a key of a subtype
* Match asymmetric keys by ID.
*/
static bool asymmetric_key_cmp(const struct key *key,
const struct key_match_data *match_data)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *description = match_data->raw_data;
const char *spec = description;
const char *id;
ptrdiff_t speclen;

if (!subtype || !spec || !*spec)
return 0;

/* See if the full key description matches as is */
if (key->description && strcmp(key->description, description) == 0)
return 1;

/* All tests from here on break the criterion description into a
* specifier, a colon and then an identifier.
*/
id = strchr(spec, ':');
if (!id)
return 0;

speclen = id - spec;
id++;

if (speclen == 2 && memcmp(spec, "id", 2) == 0)
return asymmetric_keyid_match(asymmetric_key_id(key), id);
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
const struct asymmetric_key_id *match_id = match_data->preparsed;

if (speclen == subtype->name_len &&
memcmp(spec, subtype->name, speclen) == 0)
return 1;

return 0;
return asymmetric_match_key_ids(kids, match_id);
}

/*
Expand All @@ -198,8 +137,30 @@ static bool asymmetric_key_cmp(const struct key *key,
*/
static int asymmetric_key_match_preparse(struct key_match_data *match_data)
{
match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
struct asymmetric_key_id *match_id;
const char *spec = match_data->raw_data;
const char *id;

if (!spec || !*spec)
return -EINVAL;
if (spec[0] == 'i' &&
spec[1] == 'd' &&
spec[2] == ':') {
id = spec + 3;
} else {
goto default_match;
}

match_id = asymmetric_key_hex_to_key_id(id);
if (!match_id)
return -ENOMEM;

match_data->preparsed = match_id;
match_data->cmp = asymmetric_key_cmp;
match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
return 0;

default_match:
return 0;
}

Expand All @@ -208,6 +169,7 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
*/
static void asymmetric_key_match_free(struct key_match_data *match_data)
{
kfree(match_data->preparsed);
}

/*
Expand All @@ -216,22 +178,27 @@ static void asymmetric_key_match_free(struct key_match_data *match_data)
static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *kid = asymmetric_key_id(key);
size_t n;
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
const struct asymmetric_key_id *kid;
const unsigned char *p;
int n;

seq_puts(m, key->description);

if (subtype) {
seq_puts(m, ": ");
subtype->describe(key, m);

if (kid) {
if (kids && kids->id[0]) {
kid = kids->id[0];
seq_putc(m, ' ');
n = strlen(kid);
if (n <= 8)
seq_puts(m, kid);
else
seq_puts(m, kid + n - 8);
n = kid->len;
p = kid->data;
if (n > 8) {
p += n - 8;
n = 8;
}
seq_printf(m, "%*phN", n, p);
}

seq_puts(m, " [");
Expand Down Expand Up @@ -282,14 +249,19 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
{
struct asymmetric_key_subtype *subtype = prep->type_data[0];
struct asymmetric_key_ids *kids = prep->type_data[1];

pr_devel("==>%s()\n", __func__);

if (subtype) {
subtype->destroy(prep->payload[0]);
module_put(subtype->owner);
}
kfree(prep->type_data[1]);
if (kids) {
kfree(kids->id[0]);
kfree(kids->id[1]);
kfree(kids);
}
kfree(prep->description);
}

Expand All @@ -299,13 +271,20 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
static void asymmetric_key_destroy(struct key *key)
{
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
struct asymmetric_key_ids *kids = key->type_data.p[1];

if (subtype) {
subtype->destroy(key->payload.data);
module_put(subtype->owner);
key->type_data.p[0] = NULL;
}
kfree(key->type_data.p[1]);
key->type_data.p[1] = NULL;

if (kids) {
kfree(kids->id[0]);
kfree(kids->id[1]);
kfree(kids);
key->type_data.p[1] = NULL;
}
}

struct key_type key_type_asymmetric = {
Expand Down
38 changes: 27 additions & 11 deletions crypto/asymmetric_keys/pkcs7_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ struct pkcs7_parse_context {
enum OID last_oid; /* Last OID encountered */
unsigned x509_index;
unsigned sinfo_index;
const void *raw_serial;
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer;
};

/*
Expand All @@ -39,6 +43,7 @@ static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
if (sinfo) {
mpi_free(sinfo->sig.mpi[0]);
kfree(sinfo->sig.digest);
kfree(sinfo->signing_cert_id);
kfree(sinfo);
}
}
Expand Down Expand Up @@ -251,10 +256,10 @@ int pkcs7_extract_cert(void *context, size_t hdrlen,
if (IS_ERR(x509))
return PTR_ERR(x509);

pr_debug("Got cert for %s\n", x509->subject);
pr_debug("- fingerprint %s\n", x509->fingerprint);

x509->index = ++ctx->x509_index;
pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);

*ctx->ppcerts = x509;
ctx->ppcerts = &x509->next;
return 0;
Expand Down Expand Up @@ -343,8 +348,8 @@ int pkcs7_sig_note_serial(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;
ctx->sinfo->raw_serial = value;
ctx->sinfo->raw_serial_size = vlen;
ctx->raw_serial = value;
ctx->raw_serial_size = vlen;
return 0;
}

Expand All @@ -356,8 +361,8 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;
ctx->sinfo->raw_issuer = value;
ctx->sinfo->raw_issuer_size = vlen;
ctx->raw_issuer = value;
ctx->raw_issuer_size = vlen;
return 0;
}

Expand Down Expand Up @@ -390,10 +395,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;

ctx->sinfo->index = ++ctx->sinfo_index;
*ctx->ppsinfo = ctx->sinfo;
ctx->ppsinfo = &ctx->sinfo->next;
struct pkcs7_signed_info *sinfo = ctx->sinfo;
struct asymmetric_key_id *kid;

/* Generate cert issuer + serial number key ID */
kid = asymmetric_key_generate_id(ctx->raw_serial,
ctx->raw_serial_size,
ctx->raw_issuer,
ctx->raw_issuer_size);
if (IS_ERR(kid))
return PTR_ERR(kid);

sinfo->signing_cert_id = kid;
sinfo->index = ++ctx->sinfo_index;
*ctx->ppsinfo = sinfo;
ctx->ppsinfo = &sinfo->next;
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
return -ENOMEM;
Expand Down
5 changes: 1 addition & 4 deletions crypto/asymmetric_keys/pkcs7_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ struct pkcs7_signed_info {
const void *authattrs;

/* Issuing cert serial number and issuer's name */
const void *raw_serial;
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer;
struct asymmetric_key_id *signing_cert_id;

/* Message signature.
*
Expand Down
6 changes: 2 additions & 4 deletions crypto/asymmetric_keys/pkcs7_trust.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
/* Look to see if this certificate is present in the trusted
* keys.
*/
key = x509_request_asymmetric_key(trust_keyring, x509->subject,
x509->fingerprint);
key = x509_request_asymmetric_key(trust_keyring, x509->id);
if (!IS_ERR(key))
/* One of the X.509 certificates in the PKCS#7 message
* is apparently the same as one we already trust.
Expand Down Expand Up @@ -82,8 +81,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
return -ENOKEY;
}

key = x509_request_asymmetric_key(trust_keyring, last->issuer,
last->authority);
key = x509_request_asymmetric_key(trust_keyring, last->authority);
if (IS_ERR(key))
return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
x509 = last;
Expand Down
Loading

0 comments on commit 46963b7

Please sign in to comment.