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