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