1/* Asymmetric public-key cryptography key type 2 * 3 * See Documentation/security/asymmetric-keys.txt 4 * 5 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 6 * Written by David Howells (dhowells@redhat.com) 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public Licence 10 * as published by the Free Software Foundation; either version 11 * 2 of the Licence, or (at your option) any later version. 12 */ 13#include <keys/asymmetric-subtype.h> 14#include <keys/asymmetric-parser.h> 15#include <linux/seq_file.h> 16#include <linux/module.h> 17#include <linux/slab.h> 18#include <linux/ctype.h> 19#include "asymmetric_keys.h" 20 21MODULE_LICENSE("GPL"); 22 23static LIST_HEAD(asymmetric_key_parsers); 24static DECLARE_RWSEM(asymmetric_key_parsers_sem); 25 26/** 27 * asymmetric_key_generate_id: Construct an asymmetric key ID 28 * @val_1: First binary blob 29 * @len_1: Length of first binary blob 30 * @val_2: Second binary blob 31 * @len_2: Length of second binary blob 32 * 33 * Construct an asymmetric key ID from a pair of binary blobs. 34 */ 35struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, 36 size_t len_1, 37 const void *val_2, 38 size_t len_2) 39{ 40 struct asymmetric_key_id *kid; 41 42 kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2, 43 GFP_KERNEL); 44 if (!kid) 45 return ERR_PTR(-ENOMEM); 46 kid->len = len_1 + len_2; 47 memcpy(kid->data, val_1, len_1); 48 memcpy(kid->data + len_1, val_2, len_2); 49 return kid; 50} 51EXPORT_SYMBOL_GPL(asymmetric_key_generate_id); 52 53/** 54 * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same. 55 * @kid_1, @kid_2: The key IDs to compare 56 */ 57bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1, 58 const struct asymmetric_key_id *kid2) 59{ 60 if (!kid1 || !kid2) 61 return false; 62 if (kid1->len != kid2->len) 63 return false; 64 return memcmp(kid1->data, kid2->data, kid1->len) == 0; 65} 66EXPORT_SYMBOL_GPL(asymmetric_key_id_same); 67 68/** 69 * asymmetric_key_id_partial - Return true if two asymmetric keys IDs 70 * partially match 71 * @kid_1, @kid_2: The key IDs to compare 72 */ 73bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1, 74 const struct asymmetric_key_id *kid2) 75{ 76 if (!kid1 || !kid2) 77 return false; 78 if (kid1->len < kid2->len) 79 return false; 80 return memcmp(kid1->data + (kid1->len - kid2->len), 81 kid2->data, kid2->len) == 0; 82} 83EXPORT_SYMBOL_GPL(asymmetric_key_id_partial); 84 85/** 86 * asymmetric_match_key_ids - Search asymmetric key IDs 87 * @kids: The list of key IDs to check 88 * @match_id: The key ID we're looking for 89 * @match: The match function to use 90 */ 91static bool asymmetric_match_key_ids( 92 const struct asymmetric_key_ids *kids, 93 const struct asymmetric_key_id *match_id, 94 bool (*match)(const struct asymmetric_key_id *kid1, 95 const struct asymmetric_key_id *kid2)) 96{ 97 int i; 98 99 if (!kids || !match_id) 100 return false; 101 for (i = 0; i < ARRAY_SIZE(kids->id); i++) 102 if (match(kids->id[i], match_id)) 103 return true; 104 return false; 105} 106 107/* helper function can be called directly with pre-allocated memory */ 108inline int __asymmetric_key_hex_to_key_id(const char *id, 109 struct asymmetric_key_id *match_id, 110 size_t hexlen) 111{ 112 match_id->len = hexlen; 113 return hex2bin(match_id->data, id, hexlen); 114} 115 116/** 117 * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID. 118 * @id: The ID as a hex string. 119 */ 120struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id) 121{ 122 struct asymmetric_key_id *match_id; 123 size_t asciihexlen; 124 int ret; 125 126 if (!*id) 127 return ERR_PTR(-EINVAL); 128 asciihexlen = strlen(id); 129 if (asciihexlen & 1) 130 return ERR_PTR(-EINVAL); 131 132 match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2, 133 GFP_KERNEL); 134 if (!match_id) 135 return ERR_PTR(-ENOMEM); 136 ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2); 137 if (ret < 0) { 138 kfree(match_id); 139 return ERR_PTR(-EINVAL); 140 } 141 return match_id; 142} 143 144/* 145 * Match asymmetric keys by an exact match on an ID. 146 */ 147static bool asymmetric_key_cmp(const struct key *key, 148 const struct key_match_data *match_data) 149{ 150 const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); 151 const struct asymmetric_key_id *match_id = match_data->preparsed; 152 153 return asymmetric_match_key_ids(kids, match_id, 154 asymmetric_key_id_same); 155} 156 157/* 158 * Match asymmetric keys by a partial match on an IDs. 159 */ 160static bool asymmetric_key_cmp_partial(const struct key *key, 161 const struct key_match_data *match_data) 162{ 163 const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); 164 const struct asymmetric_key_id *match_id = match_data->preparsed; 165 166 return asymmetric_match_key_ids(kids, match_id, 167 asymmetric_key_id_partial); 168} 169 170/* 171 * Preparse the match criterion. If we don't set lookup_type and cmp, 172 * the default will be an exact match on the key description. 173 * 174 * There are some specifiers for matching key IDs rather than by the key 175 * description: 176 * 177 * "id:<id>" - find a key by partial match on any available ID 178 * "ex:<id>" - find a key by exact match on any available ID 179 * 180 * These have to be searched by iteration rather than by direct lookup because 181 * the key is hashed according to its description. 182 */ 183static int asymmetric_key_match_preparse(struct key_match_data *match_data) 184{ 185 struct asymmetric_key_id *match_id; 186 const char *spec = match_data->raw_data; 187 const char *id; 188 bool (*cmp)(const struct key *, const struct key_match_data *) = 189 asymmetric_key_cmp; 190 191 if (!spec || !*spec) 192 return -EINVAL; 193 if (spec[0] == 'i' && 194 spec[1] == 'd' && 195 spec[2] == ':') { 196 id = spec + 3; 197 cmp = asymmetric_key_cmp_partial; 198 } else if (spec[0] == 'e' && 199 spec[1] == 'x' && 200 spec[2] == ':') { 201 id = spec + 3; 202 } else { 203 goto default_match; 204 } 205 206 match_id = asymmetric_key_hex_to_key_id(id); 207 if (IS_ERR(match_id)) 208 return PTR_ERR(match_id); 209 210 match_data->preparsed = match_id; 211 match_data->cmp = cmp; 212 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; 213 return 0; 214 215default_match: 216 return 0; 217} 218 219/* 220 * Free the preparsed the match criterion. 221 */ 222static void asymmetric_key_match_free(struct key_match_data *match_data) 223{ 224 kfree(match_data->preparsed); 225} 226 227/* 228 * Describe the asymmetric key 229 */ 230static void asymmetric_key_describe(const struct key *key, struct seq_file *m) 231{ 232 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); 233 const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); 234 const struct asymmetric_key_id *kid; 235 const unsigned char *p; 236 int n; 237 238 seq_puts(m, key->description); 239 240 if (subtype) { 241 seq_puts(m, ": "); 242 subtype->describe(key, m); 243 244 if (kids && kids->id[1]) { 245 kid = kids->id[1]; 246 seq_putc(m, ' '); 247 n = kid->len; 248 p = kid->data; 249 if (n > 4) { 250 p += n - 4; 251 n = 4; 252 } 253 seq_printf(m, "%*phN", n, p); 254 } 255 256 seq_puts(m, " ["); 257 /* put something here to indicate the key's capabilities */ 258 seq_putc(m, ']'); 259 } 260} 261 262/* 263 * Preparse a asymmetric payload to get format the contents appropriately for the 264 * internal payload to cut down on the number of scans of the data performed. 265 * 266 * We also generate a proposed description from the contents of the key that 267 * can be used to name the key if the user doesn't want to provide one. 268 */ 269static int asymmetric_key_preparse(struct key_preparsed_payload *prep) 270{ 271 struct asymmetric_key_parser *parser; 272 int ret; 273 274 pr_devel("==>%s()\n", __func__); 275 276 if (prep->datalen == 0) 277 return -EINVAL; 278 279 down_read(&asymmetric_key_parsers_sem); 280 281 ret = -EBADMSG; 282 list_for_each_entry(parser, &asymmetric_key_parsers, link) { 283 pr_debug("Trying parser '%s'\n", parser->name); 284 285 ret = parser->parse(prep); 286 if (ret != -EBADMSG) { 287 pr_debug("Parser recognised the format (ret %d)\n", 288 ret); 289 break; 290 } 291 } 292 293 up_read(&asymmetric_key_parsers_sem); 294 pr_devel("<==%s() = %d\n", __func__, ret); 295 return ret; 296} 297 298/* 299 * Clean up the preparse data 300 */ 301static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) 302{ 303 struct asymmetric_key_subtype *subtype = prep->type_data[0]; 304 struct asymmetric_key_ids *kids = prep->type_data[1]; 305 int i; 306 307 pr_devel("==>%s()\n", __func__); 308 309 if (subtype) { 310 subtype->destroy(prep->payload[0]); 311 module_put(subtype->owner); 312 } 313 if (kids) { 314 for (i = 0; i < ARRAY_SIZE(kids->id); i++) 315 kfree(kids->id[i]); 316 kfree(kids); 317 } 318 kfree(prep->description); 319} 320 321/* 322 * dispose of the data dangling from the corpse of a asymmetric key 323 */ 324static void asymmetric_key_destroy(struct key *key) 325{ 326 struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); 327 struct asymmetric_key_ids *kids = key->type_data.p[1]; 328 329 if (subtype) { 330 subtype->destroy(key->payload.data); 331 module_put(subtype->owner); 332 key->type_data.p[0] = NULL; 333 } 334 335 if (kids) { 336 kfree(kids->id[0]); 337 kfree(kids->id[1]); 338 kfree(kids); 339 key->type_data.p[1] = NULL; 340 } 341} 342 343struct key_type key_type_asymmetric = { 344 .name = "asymmetric", 345 .preparse = asymmetric_key_preparse, 346 .free_preparse = asymmetric_key_free_preparse, 347 .instantiate = generic_key_instantiate, 348 .match_preparse = asymmetric_key_match_preparse, 349 .match_free = asymmetric_key_match_free, 350 .destroy = asymmetric_key_destroy, 351 .describe = asymmetric_key_describe, 352}; 353EXPORT_SYMBOL_GPL(key_type_asymmetric); 354 355/** 356 * register_asymmetric_key_parser - Register a asymmetric key blob parser 357 * @parser: The parser to register 358 */ 359int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) 360{ 361 struct asymmetric_key_parser *cursor; 362 int ret; 363 364 down_write(&asymmetric_key_parsers_sem); 365 366 list_for_each_entry(cursor, &asymmetric_key_parsers, link) { 367 if (strcmp(cursor->name, parser->name) == 0) { 368 pr_err("Asymmetric key parser '%s' already registered\n", 369 parser->name); 370 ret = -EEXIST; 371 goto out; 372 } 373 } 374 375 list_add_tail(&parser->link, &asymmetric_key_parsers); 376 377 pr_notice("Asymmetric key parser '%s' registered\n", parser->name); 378 ret = 0; 379 380out: 381 up_write(&asymmetric_key_parsers_sem); 382 return ret; 383} 384EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); 385 386/** 387 * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser 388 * @parser: The parser to unregister 389 */ 390void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) 391{ 392 down_write(&asymmetric_key_parsers_sem); 393 list_del(&parser->link); 394 up_write(&asymmetric_key_parsers_sem); 395 396 pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); 397} 398EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); 399 400/* 401 * Module stuff 402 */ 403static int __init asymmetric_key_init(void) 404{ 405 return register_key_type(&key_type_asymmetric); 406} 407 408static void __exit asymmetric_key_cleanup(void) 409{ 410 unregister_key_type(&key_type_asymmetric); 411} 412 413module_init(asymmetric_key_init); 414module_exit(asymmetric_key_cleanup); 415