3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
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"
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 */
32 const void *raw_serial
;
33 unsigned raw_serial_size
;
34 unsigned raw_issuer_size
;
35 const void *raw_issuer
;
39 * Free a signed information block.
41 static void pkcs7_free_signed_info(struct pkcs7_signed_info
*sinfo
)
44 mpi_free(sinfo
->sig
.mpi
[0]);
45 kfree(sinfo
->sig
.digest
);
46 kfree(sinfo
->signing_cert_id
);
52 * pkcs7_free_message - Free a PKCS#7 message
53 * @pkcs7: The PKCS#7 message to free
55 void pkcs7_free_message(struct pkcs7_message
*pkcs7
)
57 struct x509_certificate
*cert
;
58 struct pkcs7_signed_info
*sinfo
;
61 while (pkcs7
->certs
) {
63 pkcs7
->certs
= cert
->next
;
64 x509_free_certificate(cert
);
68 pkcs7
->crl
= cert
->next
;
69 x509_free_certificate(cert
);
71 while (pkcs7
->signed_infos
) {
72 sinfo
= pkcs7
->signed_infos
;
73 pkcs7
->signed_infos
= sinfo
->next
;
74 pkcs7_free_signed_info(sinfo
);
79 EXPORT_SYMBOL_GPL(pkcs7_free_message
);
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
86 struct pkcs7_message
*pkcs7_parse_message(const void *data
, size_t datalen
)
88 struct pkcs7_parse_context
*ctx
;
89 struct pkcs7_message
*msg
= ERR_PTR(-ENOMEM
);
92 ctx
= kzalloc(sizeof(struct pkcs7_parse_context
), GFP_KERNEL
);
95 ctx
->msg
= kzalloc(sizeof(struct pkcs7_message
), GFP_KERNEL
);
98 ctx
->sinfo
= kzalloc(sizeof(struct pkcs7_signed_info
), GFP_KERNEL
);
102 ctx
->data
= (unsigned long)data
;
103 ctx
->ppcerts
= &ctx
->certs
;
104 ctx
->ppsinfo
= &ctx
->msg
->signed_infos
;
106 /* Attempt to decode the signature */
107 ret
= asn1_ber_decoder(&pkcs7_decoder
, ctx
, data
, datalen
);
118 struct x509_certificate
*cert
= ctx
->certs
;
119 ctx
->certs
= cert
->next
;
120 x509_free_certificate(cert
);
122 pkcs7_free_signed_info(ctx
->sinfo
);
124 pkcs7_free_message(ctx
->msg
);
130 EXPORT_SYMBOL_GPL(pkcs7_parse_message
);
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
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.
143 int pkcs7_get_content_data(const struct pkcs7_message
*pkcs7
,
144 const void **_data
, size_t *_data_len
,
152 wrapper
= want_wrapper
? pkcs7
->data_hdrlen
: 0;
153 *_data
= pkcs7
->data
- wrapper
;
154 *_data_len
= pkcs7
->data_len
+ wrapper
;
157 EXPORT_SYMBOL_GPL(pkcs7_get_content_data
);
160 * Note an OID when we find one for later processing when we know how
163 int pkcs7_note_OID(void *context
, size_t hdrlen
,
165 const void *value
, size_t vlen
)
167 struct pkcs7_parse_context
*ctx
= context
;
169 ctx
->last_oid
= look_up_OID(value
, vlen
);
170 if (ctx
->last_oid
== OID__NR
) {
172 sprint_oid(value
, vlen
, buffer
, sizeof(buffer
));
173 printk("PKCS7: Unknown OID: [%lu] %s\n",
174 (unsigned long)value
- ctx
->data
, buffer
);
180 * Note the digest algorithm for the signature.
182 int pkcs7_sig_note_digest_algo(void *context
, size_t hdrlen
,
184 const void *value
, size_t vlen
)
186 struct pkcs7_parse_context
*ctx
= context
;
188 switch (ctx
->last_oid
) {
190 ctx
->sinfo
->sig
.pkey_hash_algo
= HASH_ALGO_MD4
;
193 ctx
->sinfo
->sig
.pkey_hash_algo
= HASH_ALGO_MD5
;
196 ctx
->sinfo
->sig
.pkey_hash_algo
= HASH_ALGO_SHA1
;
199 ctx
->sinfo
->sig
.pkey_hash_algo
= HASH_ALGO_SHA256
;
202 printk("Unsupported digest algo: %u\n", ctx
->last_oid
);
209 * Note the public key algorithm for the signature.
211 int pkcs7_sig_note_pkey_algo(void *context
, size_t hdrlen
,
213 const void *value
, size_t vlen
)
215 struct pkcs7_parse_context
*ctx
= context
;
217 switch (ctx
->last_oid
) {
218 case OID_rsaEncryption
:
219 ctx
->sinfo
->sig
.pkey_algo
= PKEY_ALGO_RSA
;
222 printk("Unsupported pkey algo: %u\n", ctx
->last_oid
);
229 * Extract a certificate and store it in the context.
231 int pkcs7_extract_cert(void *context
, size_t hdrlen
,
233 const void *value
, size_t vlen
)
235 struct pkcs7_parse_context
*ctx
= context
;
236 struct x509_certificate
*x509
;
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
);
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
252 if (((u8
*)value
)[1] == 0x80)
253 vlen
+= 2; /* Indefinite length - there should be an EOC */
255 x509
= x509_cert_parse(value
, vlen
);
257 return PTR_ERR(x509
);
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
);
263 *ctx
->ppcerts
= x509
;
264 ctx
->ppcerts
= &x509
->next
;
269 * Save the certificate list
271 int pkcs7_note_certificate_list(void *context
, size_t hdrlen
,
273 const void *value
, size_t vlen
)
275 struct pkcs7_parse_context
*ctx
= context
;
277 pr_devel("Got cert list (%02x)\n", tag
);
279 *ctx
->ppcerts
= ctx
->msg
->certs
;
280 ctx
->msg
->certs
= ctx
->certs
;
282 ctx
->ppcerts
= &ctx
->certs
;
287 * Extract the data from the message and store that and its content type OID in
290 int pkcs7_note_data(void *context
, size_t hdrlen
,
292 const void *value
, size_t vlen
)
294 struct pkcs7_parse_context
*ctx
= context
;
296 pr_debug("Got data\n");
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
;
306 * Parse authenticated attributes
308 int pkcs7_sig_note_authenticated_attr(void *context
, size_t hdrlen
,
310 const void *value
, size_t vlen
)
312 struct pkcs7_parse_context
*ctx
= context
;
314 pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag
, vlen
, (unsigned)vlen
, value
);
316 switch (ctx
->last_oid
) {
317 case OID_messageDigest
:
320 ctx
->sinfo
->msgdigest
= value
;
321 ctx
->sinfo
->msgdigest_len
= vlen
;
329 * Note the set of auth attributes for digestion purposes [RFC2315 9.3]
331 int pkcs7_sig_note_set_of_authattrs(void *context
, size_t hdrlen
,
333 const void *value
, size_t vlen
)
335 struct pkcs7_parse_context
*ctx
= context
;
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);
344 * Note the issuing certificate serial number
346 int pkcs7_sig_note_serial(void *context
, size_t hdrlen
,
348 const void *value
, size_t vlen
)
350 struct pkcs7_parse_context
*ctx
= context
;
351 ctx
->raw_serial
= value
;
352 ctx
->raw_serial_size
= vlen
;
357 * Note the issuer's name
359 int pkcs7_sig_note_issuer(void *context
, size_t hdrlen
,
361 const void *value
, size_t vlen
)
363 struct pkcs7_parse_context
*ctx
= context
;
364 ctx
->raw_issuer
= value
;
365 ctx
->raw_issuer_size
= vlen
;
370 * Note the signature data
372 int pkcs7_sig_note_signature(void *context
, size_t hdrlen
,
374 const void *value
, size_t vlen
)
376 struct pkcs7_parse_context
*ctx
= context
;
379 BUG_ON(ctx
->sinfo
->sig
.pkey_algo
!= PKEY_ALGO_RSA
);
381 mpi
= mpi_read_raw_data(value
, vlen
);
385 ctx
->sinfo
->sig
.mpi
[0] = mpi
;
386 ctx
->sinfo
->sig
.nr_mpi
= 1;
391 * Note a signature information block
393 int pkcs7_note_signed_info(void *context
, size_t hdrlen
,
395 const void *value
, size_t vlen
)
397 struct pkcs7_parse_context
*ctx
= context
;
398 struct pkcs7_signed_info
*sinfo
= ctx
->sinfo
;
399 struct asymmetric_key_id
*kid
;
401 /* Generate cert issuer + serial number key ID */
402 kid
= asymmetric_key_generate_id(ctx
->raw_serial
,
403 ctx
->raw_serial_size
,
405 ctx
->raw_issuer_size
);
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
);