1 /* PKCS#7 parser 2 * 3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #define pr_fmt(fmt) "PKCS7: "fmt 13 #include <linux/kernel.h> 14 #include <linux/export.h> 15 #include <linux/slab.h> 16 #include <linux/err.h> 17 #include <linux/oid_registry.h> 18 #include "public_key.h" 19 #include "pkcs7_parser.h" 20 #include "pkcs7-asn1.h" 21 22 struct pkcs7_parse_context { 23 struct pkcs7_message *msg; /* Message being constructed */ 24 struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */ 25 struct pkcs7_signed_info **ppsinfo; 26 struct x509_certificate *certs; /* Certificate cache */ 27 struct x509_certificate **ppcerts; 28 unsigned long data; /* Start of data */ 29 enum OID last_oid; /* Last OID encountered */ 30 unsigned x509_index; 31 unsigned sinfo_index; 32 const void *raw_serial; 33 unsigned raw_serial_size; 34 unsigned raw_issuer_size; 35 const void *raw_issuer; 36 }; 37 38 /* 39 * Free a signed information block. 40 */ 41 static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) 42 { 43 if (sinfo) { 44 mpi_free(sinfo->sig.mpi[0]); 45 kfree(sinfo->sig.digest); 46 kfree(sinfo->signing_cert_id); 47 kfree(sinfo); 48 } 49 } 50 51 /** 52 * pkcs7_free_message - Free a PKCS#7 message 53 * @pkcs7: The PKCS#7 message to free 54 */ 55 void pkcs7_free_message(struct pkcs7_message *pkcs7) 56 { 57 struct x509_certificate *cert; 58 struct pkcs7_signed_info *sinfo; 59 60 if (pkcs7) { 61 while (pkcs7->certs) { 62 cert = pkcs7->certs; 63 pkcs7->certs = cert->next; 64 x509_free_certificate(cert); 65 } 66 while (pkcs7->crl) { 67 cert = pkcs7->crl; 68 pkcs7->crl = cert->next; 69 x509_free_certificate(cert); 70 } 71 while (pkcs7->signed_infos) { 72 sinfo = pkcs7->signed_infos; 73 pkcs7->signed_infos = sinfo->next; 74 pkcs7_free_signed_info(sinfo); 75 } 76 kfree(pkcs7); 77 } 78 } 79 EXPORT_SYMBOL_GPL(pkcs7_free_message); 80 81 /** 82 * pkcs7_parse_message - Parse a PKCS#7 message 83 * @data: The raw binary ASN.1 encoded message to be parsed 84 * @datalen: The size of the encoded message 85 */ 86 struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) 87 { 88 struct pkcs7_parse_context *ctx; 89 struct pkcs7_message *msg = ERR_PTR(-ENOMEM); 90 int ret; 91 92 ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL); 93 if (!ctx) 94 goto out_no_ctx; 95 ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); 96 if (!ctx->msg) 97 goto out_no_msg; 98 ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); 99 if (!ctx->sinfo) 100 goto out_no_sinfo; 101 102 ctx->data = (unsigned long)data; 103 ctx->ppcerts = &ctx->certs; 104 ctx->ppsinfo = &ctx->msg->signed_infos; 105 106 /* Attempt to decode the signature */ 107 ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen); 108 if (ret < 0) { 109 msg = ERR_PTR(ret); 110 goto out; 111 } 112 113 msg = ctx->msg; 114 ctx->msg = NULL; 115 116 out: 117 while (ctx->certs) { 118 struct x509_certificate *cert = ctx->certs; 119 ctx->certs = cert->next; 120 x509_free_certificate(cert); 121 } 122 pkcs7_free_signed_info(ctx->sinfo); 123 out_no_sinfo: 124 pkcs7_free_message(ctx->msg); 125 out_no_msg: 126 kfree(ctx); 127 out_no_ctx: 128 return msg; 129 } 130 EXPORT_SYMBOL_GPL(pkcs7_parse_message); 131 132 /** 133 * pkcs7_get_content_data - Get access to the PKCS#7 content 134 * @pkcs7: The preparsed PKCS#7 message to access 135 * @_data: Place to return a pointer to the data 136 * @_data_len: Place to return the data length 137 * @want_wrapper: True if the ASN.1 object header should be included in the data 138 * 139 * Get access to the data content of the PKCS#7 message, including, optionally, 140 * the header of the ASN.1 object that contains it. Returns -ENODATA if the 141 * data object was missing from the message. 142 */ 143 int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, 144 const void **_data, size_t *_data_len, 145 bool want_wrapper) 146 { 147 size_t wrapper; 148 149 if (!pkcs7->data) 150 return -ENODATA; 151 152 wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; 153 *_data = pkcs7->data - wrapper; 154 *_data_len = pkcs7->data_len + wrapper; 155 return 0; 156 } 157 EXPORT_SYMBOL_GPL(pkcs7_get_content_data); 158 159 /* 160 * Note an OID when we find one for later processing when we know how 161 * to interpret it. 162 */ 163 int pkcs7_note_OID(void *context, size_t hdrlen, 164 unsigned char tag, 165 const void *value, size_t vlen) 166 { 167 struct pkcs7_parse_context *ctx = context; 168 169 ctx->last_oid = look_up_OID(value, vlen); 170 if (ctx->last_oid == OID__NR) { 171 char buffer[50]; 172 sprint_oid(value, vlen, buffer, sizeof(buffer)); 173 printk("PKCS7: Unknown OID: [%lu] %s\n", 174 (unsigned long)value - ctx->data, buffer); 175 } 176 return 0; 177 } 178 179 /* 180 * Note the digest algorithm for the signature. 181 */ 182 int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, 183 unsigned char tag, 184 const void *value, size_t vlen) 185 { 186 struct pkcs7_parse_context *ctx = context; 187 188 switch (ctx->last_oid) { 189 case OID_md4: 190 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4; 191 break; 192 case OID_md5: 193 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5; 194 break; 195 case OID_sha1: 196 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1; 197 break; 198 case OID_sha256: 199 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; 200 break; 201 default: 202 printk("Unsupported digest algo: %u\n", ctx->last_oid); 203 return -ENOPKG; 204 } 205 return 0; 206 } 207 208 /* 209 * Note the public key algorithm for the signature. 210 */ 211 int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, 212 unsigned char tag, 213 const void *value, size_t vlen) 214 { 215 struct pkcs7_parse_context *ctx = context; 216 217 switch (ctx->last_oid) { 218 case OID_rsaEncryption: 219 ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA; 220 break; 221 default: 222 printk("Unsupported pkey algo: %u\n", ctx->last_oid); 223 return -ENOPKG; 224 } 225 return 0; 226 } 227 228 /* 229 * Extract a certificate and store it in the context. 230 */ 231 int pkcs7_extract_cert(void *context, size_t hdrlen, 232 unsigned char tag, 233 const void *value, size_t vlen) 234 { 235 struct pkcs7_parse_context *ctx = context; 236 struct x509_certificate *x509; 237 238 if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) { 239 pr_debug("Cert began with tag %02x at %lu\n", 240 tag, (unsigned long)ctx - ctx->data); 241 return -EBADMSG; 242 } 243 244 /* We have to correct for the header so that the X.509 parser can start 245 * from the beginning. Note that since X.509 stipulates DER, there 246 * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which 247 * stipulates BER). 248 */ 249 value -= hdrlen; 250 vlen += hdrlen; 251 252 if (((u8*)value)[1] == 0x80) 253 vlen += 2; /* Indefinite length - there should be an EOC */ 254 255 x509 = x509_cert_parse(value, vlen); 256 if (IS_ERR(x509)) 257 return PTR_ERR(x509); 258 259 x509->index = ++ctx->x509_index; 260 pr_debug("Got cert %u for %s\n", x509->index, x509->subject); 261 pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data); 262 263 *ctx->ppcerts = x509; 264 ctx->ppcerts = &x509->next; 265 return 0; 266 } 267 268 /* 269 * Save the certificate list 270 */ 271 int pkcs7_note_certificate_list(void *context, size_t hdrlen, 272 unsigned char tag, 273 const void *value, size_t vlen) 274 { 275 struct pkcs7_parse_context *ctx = context; 276 277 pr_devel("Got cert list (%02x)\n", tag); 278 279 *ctx->ppcerts = ctx->msg->certs; 280 ctx->msg->certs = ctx->certs; 281 ctx->certs = NULL; 282 ctx->ppcerts = &ctx->certs; 283 return 0; 284 } 285 286 /* 287 * Extract the data from the message and store that and its content type OID in 288 * the context. 289 */ 290 int pkcs7_note_data(void *context, size_t hdrlen, 291 unsigned char tag, 292 const void *value, size_t vlen) 293 { 294 struct pkcs7_parse_context *ctx = context; 295 296 pr_debug("Got data\n"); 297 298 ctx->msg->data = value; 299 ctx->msg->data_len = vlen; 300 ctx->msg->data_hdrlen = hdrlen; 301 ctx->msg->data_type = ctx->last_oid; 302 return 0; 303 } 304 305 /* 306 * Parse authenticated attributes 307 */ 308 int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, 309 unsigned char tag, 310 const void *value, size_t vlen) 311 { 312 struct pkcs7_parse_context *ctx = context; 313 314 pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); 315 316 switch (ctx->last_oid) { 317 case OID_messageDigest: 318 if (tag != ASN1_OTS) 319 return -EBADMSG; 320 ctx->sinfo->msgdigest = value; 321 ctx->sinfo->msgdigest_len = vlen; 322 return 0; 323 default: 324 return 0; 325 } 326 } 327 328 /* 329 * Note the set of auth attributes for digestion purposes [RFC2315 9.3] 330 */ 331 int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, 332 unsigned char tag, 333 const void *value, size_t vlen) 334 { 335 struct pkcs7_parse_context *ctx = context; 336 337 /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ 338 ctx->sinfo->authattrs = value - (hdrlen - 1); 339 ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); 340 return 0; 341 } 342 343 /* 344 * Note the issuing certificate serial number 345 */ 346 int pkcs7_sig_note_serial(void *context, size_t hdrlen, 347 unsigned char tag, 348 const void *value, size_t vlen) 349 { 350 struct pkcs7_parse_context *ctx = context; 351 ctx->raw_serial = value; 352 ctx->raw_serial_size = vlen; 353 return 0; 354 } 355 356 /* 357 * Note the issuer's name 358 */ 359 int pkcs7_sig_note_issuer(void *context, size_t hdrlen, 360 unsigned char tag, 361 const void *value, size_t vlen) 362 { 363 struct pkcs7_parse_context *ctx = context; 364 ctx->raw_issuer = value; 365 ctx->raw_issuer_size = vlen; 366 return 0; 367 } 368 369 /* 370 * Note the signature data 371 */ 372 int pkcs7_sig_note_signature(void *context, size_t hdrlen, 373 unsigned char tag, 374 const void *value, size_t vlen) 375 { 376 struct pkcs7_parse_context *ctx = context; 377 MPI mpi; 378 379 BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA); 380 381 mpi = mpi_read_raw_data(value, vlen); 382 if (!mpi) 383 return -ENOMEM; 384 385 ctx->sinfo->sig.mpi[0] = mpi; 386 ctx->sinfo->sig.nr_mpi = 1; 387 return 0; 388 } 389 390 /* 391 * Note a signature information block 392 */ 393 int pkcs7_note_signed_info(void *context, size_t hdrlen, 394 unsigned char tag, 395 const void *value, size_t vlen) 396 { 397 struct pkcs7_parse_context *ctx = context; 398 struct pkcs7_signed_info *sinfo = ctx->sinfo; 399 struct asymmetric_key_id *kid; 400 401 /* Generate cert issuer + serial number key ID */ 402 kid = asymmetric_key_generate_id(ctx->raw_serial, 403 ctx->raw_serial_size, 404 ctx->raw_issuer, 405 ctx->raw_issuer_size); 406 if (IS_ERR(kid)) 407 return PTR_ERR(kid); 408 409 sinfo->signing_cert_id = kid; 410 sinfo->index = ++ctx->sinfo_index; 411 *ctx->ppsinfo = sinfo; 412 ctx->ppsinfo = &sinfo->next; 413 ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); 414 if (!ctx->sinfo) 415 return -ENOMEM; 416 return 0; 417 } 418