Browse Source

[crypto] Add support for Cryptographic Message Syntax (PKCS #7)

The Cryptographic Message Syntax (PKCS#7) provides a format for
encapsulating digital signatures of arbitrary binary blobs.  A
signature can be generated using

  openssl cms -sign -in <file to sign> -binary -noattr \
  	  -signer <signer>.crt -inkey <signer>.key -certfile <CA>.crt \
	  -outform DER -out <signature>

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
bdb69d587e
4 changed files with 639 additions and 0 deletions
  1. 582
    0
      src/crypto/cms.c
  2. 6
    0
      src/include/ipxe/asn1.h
  3. 50
    0
      src/include/ipxe/cms.h
  4. 1
    0
      src/include/ipxe/errfile.h

+ 582
- 0
src/crypto/cms.c View File

@@ -0,0 +1,582 @@
1
+/*
2
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+/** @file
22
+ *
23
+ * Cryptographic Message Syntax (PKCS #7)
24
+ *
25
+ * The format of CMS messages is defined in RFC 5652.
26
+ *
27
+ */
28
+
29
+#include <stdint.h>
30
+#include <string.h>
31
+#include <time.h>
32
+#include <errno.h>
33
+#include <ipxe/asn1.h>
34
+#include <ipxe/x509.h>
35
+#include <ipxe/uaccess.h>
36
+#include <ipxe/cms.h>
37
+
38
+/* Disambiguate the various error causes */
39
+#define EACCES_NON_SIGNING \
40
+	__einfo_error ( EINFO_EACCES_NON_SIGNING )
41
+#define EINFO_EACCES_NON_SIGNING \
42
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "Not a signing certificate" )
43
+#define EACCES_NON_CODE_SIGNING \
44
+	__einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
45
+#define EINFO_EACCES_NON_CODE_SIGNING \
46
+	__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
47
+#define EACCES_INCOMPLETE \
48
+	__einfo_error ( EINFO_EACCES_INCOMPLETE )
49
+#define EINFO_EACCES_INCOMPLETE \
50
+	__einfo_uniqify ( EINFO_EACCES, 0x03, "Incomplete certificate chain" )
51
+#define EACCES_WRONG_NAME \
52
+	__einfo_error ( EINFO_EACCES_WRONG_NAME )
53
+#define EINFO_EACCES_WRONG_NAME \
54
+	__einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
55
+
56
+/** "pkcs7-signedData" object identifier */
57
+static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA };
58
+
59
+/** "pkcs7-signedData" object identifier cursor */
60
+static struct asn1_cursor oid_signeddata_cursor =
61
+	ASN1_OID_CURSOR ( oid_signeddata );
62
+
63
+/**
64
+ * Parse CMS signature content type
65
+ *
66
+ * @v sig		CMS signature
67
+ * @v raw		ASN.1 cursor
68
+ * @ret rc		Return status code
69
+ */
70
+static int cms_parse_content_type ( struct cms_signature *sig,
71
+				    const struct asn1_cursor *raw ) {
72
+	struct asn1_cursor cursor;
73
+
74
+	/* Enter contentType */
75
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
76
+	asn1_enter ( &cursor, ASN1_OID );
77
+
78
+	/* Check OID is pkcs7-signedData */
79
+	if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) {
80
+		DBGC ( sig, "CMS %p does not contain signedData:\n", sig );
81
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
82
+		return -ENOTSUP;
83
+	}
84
+
85
+	DBGC ( sig, "CMS %p contains signedData\n", sig );
86
+	return 0;
87
+}
88
+
89
+/**
90
+ * Parse CMS signature signer identifier
91
+ *
92
+ * @v sig		CMS signature
93
+ * @v info		Signer information to fill in
94
+ * @v raw		ASN.1 cursor
95
+ * @ret rc		Return status code
96
+ */
97
+static int cms_parse_signer_identifier ( struct cms_signature *sig,
98
+					 struct cms_signer_info *info,
99
+					 const struct asn1_cursor *raw ) {
100
+	struct asn1_cursor cursor;
101
+	int rc;
102
+
103
+	/* Enter issuerAndSerialNumber */
104
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
105
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
106
+
107
+	/* Record issuer */
108
+	memcpy ( &info->issuer, &cursor, sizeof ( info->issuer ) );
109
+	if ( ( rc = asn1_shrink ( &info->issuer, ASN1_SEQUENCE ) ) != 0 ) {
110
+		DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
111
+		       sig, info, strerror ( rc ) );
112
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
113
+		return rc;
114
+	}
115
+	DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
116
+	DBGC_HDA ( sig, 0, info->issuer.data, info->issuer.len );
117
+	asn1_skip_any ( &cursor );
118
+
119
+	/* Record serialNumber */
120
+	memcpy ( &info->serial, &cursor, sizeof ( info->serial ) );
121
+	if ( ( rc = asn1_shrink ( &info->serial, ASN1_INTEGER ) ) != 0 ) {
122
+		DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
123
+		       sig, info, strerror ( rc ) );
124
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
125
+		return rc;
126
+	}
127
+	DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
128
+	DBGC_HDA ( sig, 0, info->serial.data, info->serial.len );
129
+
130
+	return 0;
131
+}
132
+
133
+/**
134
+ * Parse CMS signature digest algorithm
135
+ *
136
+ * @v sig		CMS signature
137
+ * @v info		Signer information to fill in
138
+ * @v raw		ASN.1 cursor
139
+ * @ret rc		Return status code
140
+ */
141
+static int cms_parse_digest_algorithm ( struct cms_signature *sig,
142
+					struct cms_signer_info *info,
143
+					const struct asn1_cursor *raw ) {
144
+	struct asn1_algorithm *algorithm;
145
+
146
+	/* Identify algorithm */
147
+	algorithm = asn1_algorithm ( raw );
148
+	if ( ! algorithm ) {
149
+		DBGC ( sig, "CMS %p/%p could not identify digest algorithm:\n",
150
+		       sig, info );
151
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
152
+		return -ENOTSUP;
153
+	}
154
+
155
+	/* Check algorithm is a digest algorithm */
156
+	if ( ! algorithm->digest ) {
157
+		DBGC ( sig, "CMS %p/%p algorithm %s is not a digest "
158
+		       "algorithm\n", sig, info, algorithm->name );
159
+		return -EINVAL;
160
+	}
161
+
162
+	/* Record digest algorithm */
163
+	info->digest = algorithm->digest;
164
+	DBGC ( sig, "CMS %p/%p digest algorithm is %s\n",
165
+	       sig, info, algorithm->name );
166
+
167
+	return 0;
168
+}
169
+
170
+/**
171
+ * Parse CMS signature algorithm
172
+ *
173
+ * @v sig		CMS signature
174
+ * @v info		Signer information to fill in
175
+ * @v raw		ASN.1 cursor
176
+ * @ret rc		Return status code
177
+ */
178
+static int cms_parse_signature_algorithm ( struct cms_signature *sig,
179
+					   struct cms_signer_info *info,
180
+					   const struct asn1_cursor *raw ) {
181
+	struct asn1_algorithm *algorithm;
182
+
183
+	/* Identify algorithm */
184
+	algorithm = asn1_algorithm ( raw );
185
+	if ( ! algorithm ) {
186
+		DBGC ( sig, "CMS %p/%p could not identify public-key "
187
+		       "algorithm:\n", sig, info );
188
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
189
+		return -ENOTSUP;
190
+	}
191
+
192
+	/* Check algorithm is a signature algorithm */
193
+	if ( ! algorithm->pubkey ) {
194
+		DBGC ( sig, "CMS %p/%p algorithm %s is not a public-key "
195
+		       "algorithm\n", sig, info, algorithm->name );
196
+		return -EINVAL;
197
+	}
198
+
199
+	/* Record signature algorithm */
200
+	info->pubkey = algorithm->pubkey;
201
+	DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n",
202
+	       sig, info, algorithm->name );
203
+
204
+	return 0;
205
+}
206
+
207
+/**
208
+ * Parse CMS signature value
209
+ *
210
+ * @v sig		CMS signature
211
+ * @v info		Signer information to fill in
212
+ * @v raw		ASN.1 cursor
213
+ * @ret rc		Return status code
214
+ */
215
+static int cms_parse_signature_value ( struct cms_signature *sig,
216
+				       struct cms_signer_info *info,
217
+				       const struct asn1_cursor *raw ) {
218
+	struct asn1_cursor cursor;
219
+	int rc;
220
+
221
+	/* Enter signature */
222
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
223
+	if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
224
+		DBGC ( sig, "CMS %p/%p could not locate signature:\n",
225
+		       sig, info );
226
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
227
+		return rc;
228
+	}
229
+
230
+	/* Record signature */
231
+	info->signature = cursor.data;
232
+	info->signature_len = cursor.len;
233
+	DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
234
+	DBGC_HDA ( sig, 0, info->signature, info->signature_len );
235
+
236
+	return 0;
237
+}
238
+
239
+/**
240
+ * Parse CMS signature signer information
241
+ *
242
+ * @v sig		CMS signature
243
+ * @v info		Signer information to fill in
244
+ * @v raw		ASN.1 cursor
245
+ * @ret rc		Return status code
246
+ */
247
+static int cms_parse_signer_info ( struct cms_signature *sig,
248
+				   struct cms_signer_info *info,
249
+				   const struct asn1_cursor *raw ) {
250
+	struct asn1_cursor cursor;
251
+	int rc;
252
+
253
+	/* Enter signerInfo */
254
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
255
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
256
+
257
+	/* Skip version */
258
+	asn1_skip ( &cursor, ASN1_INTEGER );
259
+
260
+	/* Parse sid */
261
+	if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 )
262
+		return rc;
263
+	asn1_skip_any ( &cursor );
264
+
265
+	/* Parse digestAlgorithm */
266
+	if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 )
267
+		return rc;
268
+	asn1_skip_any ( &cursor );
269
+
270
+	/* Skip signedAttrs, if present */
271
+	asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
272
+
273
+	/* Parse signatureAlgorithm */
274
+	if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0)
275
+		return rc;
276
+	asn1_skip_any ( &cursor );
277
+
278
+	/* Parse signature */
279
+	if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 )
280
+		return rc;
281
+
282
+	return 0;
283
+}
284
+
285
+/**
286
+ * Parse CMS signature from ASN.1 data
287
+ *
288
+ * @v sig		CMS signature
289
+ * @v data		Raw signature data
290
+ * @v len		Length of raw data
291
+ * @ret rc		Return status code
292
+ */
293
+int cms_parse ( struct cms_signature *sig, const void *data, size_t len ) {
294
+	struct asn1_cursor cursor;
295
+	int rc;
296
+
297
+	/* Initialise signature */
298
+	memset ( sig, 0, sizeof ( *sig ) );
299
+	cursor.data = data;
300
+	cursor.len = len;
301
+
302
+	/* Enter contentInfo */
303
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
304
+
305
+	/* Parse contentType */
306
+	if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
307
+		return rc;
308
+	asn1_skip_any ( &cursor );
309
+
310
+	/* Enter content */
311
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
312
+
313
+	/* Enter signedData */
314
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
315
+
316
+	/* Skip version */
317
+	asn1_skip ( &cursor, ASN1_INTEGER );
318
+
319
+	/* Skip digestAlgorithms */
320
+	asn1_skip ( &cursor, ASN1_SET );
321
+
322
+	/* Skip encapContentInfo */
323
+	asn1_skip ( &cursor, ASN1_SEQUENCE );
324
+
325
+	/* Record certificates */
326
+	memcpy ( &sig->certificates, &cursor, sizeof ( sig->certificates ) );
327
+	if ( ( rc = asn1_enter ( &sig->certificates,
328
+				 ASN1_EXPLICIT_TAG ( 0 ) ) ) != 0 ) {
329
+		DBGC ( sig, "CMS %p could not locate certificates:\n", sig );
330
+		DBGC_HDA ( sig, 0, data, len );
331
+		return rc;
332
+	}
333
+	asn1_skip_any ( &cursor );
334
+
335
+	/* Skip crls, if present */
336
+	asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
337
+
338
+	/* Enter signerInfos */
339
+	asn1_enter ( &cursor, ASN1_SET );
340
+
341
+	/* Parse first signerInfo */
342
+	if ( ( rc = cms_parse_signer_info ( sig, &sig->info, &cursor ) ) != 0 )
343
+		return rc;
344
+
345
+	return 0;
346
+}
347
+
348
+/** CMS certificate chain context */
349
+struct cms_chain_context {
350
+	/** Signature */
351
+	struct cms_signature *sig;
352
+	/** Signer information */
353
+	struct cms_signer_info *info;
354
+};
355
+
356
+/**
357
+ * Parse next certificate in chain
358
+ *
359
+ * @v cert		X.509 certificate to parse
360
+ * @v previous		Previous X.509 certificate, or NULL
361
+ * @v ctx		Chain context
362
+ * @ret rc		Return status code
363
+ */
364
+static int cms_parse_next ( struct x509_certificate *cert,
365
+			    const struct x509_certificate *previous,
366
+			    void *ctx ) {
367
+	struct cms_chain_context *context = ctx;
368
+	struct cms_signature *sig = context->sig;
369
+	struct cms_signer_info *info = context->info;
370
+	struct asn1_cursor cursor;
371
+	int rc;
372
+
373
+	/* Search for relevant certificate */
374
+	memcpy ( &cursor, &sig->certificates, sizeof ( cursor ) );
375
+	while ( cursor.len ) {
376
+
377
+		/* Parse certificate */
378
+		if ( ( rc = x509_parse ( cert, cursor.data,
379
+					 cursor.len ) ) != 0 ) {
380
+			DBGC ( sig, "CMS %p/%p could not parse certificate:\n",
381
+			       sig, info );
382
+			DBGC_HDA ( sig, 0, cursor.data, cursor.len );
383
+			return rc;
384
+		}
385
+
386
+		if ( previous == NULL ) {
387
+			/* First certificate: check issuer and serial
388
+			 * number against signer info
389
+			 */
390
+			if ( ( asn1_compare ( &info->issuer,
391
+					      &cert->issuer.raw ) == 0 ) &&
392
+			     ( asn1_compare ( &info->serial,
393
+					      &cert->serial.raw ) == 0 ) ) {
394
+				return 0;
395
+			}
396
+		} else {
397
+			/* Subsequent certificates: check subject
398
+			 * against previous certificate's issuer.
399
+			 */
400
+			if ( asn1_compare ( &previous->issuer.raw,
401
+					    &cert->subject.raw ) == 0 ) {
402
+				return 0;
403
+			}
404
+		}
405
+
406
+		/* Move to next certificate */
407
+		asn1_skip_any ( &cursor );
408
+	}
409
+
410
+	DBGC ( sig, "CMS %p/%p reached end of certificate chain\n", sig, info );
411
+	return -EACCES_INCOMPLETE;
412
+}
413
+
414
+/**
415
+ * Calculate digest of CMS-signed data
416
+ *
417
+ * @v sig		CMS signature
418
+ * @v info		Signer information
419
+ * @v data		Signed data
420
+ * @v len		Length of signed data
421
+ * @v out		Digest output
422
+ */
423
+static void cms_digest ( struct cms_signature *sig,
424
+			 struct cms_signer_info *info,
425
+			 userptr_t data, size_t len, void *out ) {
426
+	struct digest_algorithm *digest = info->digest;
427
+	uint8_t ctx[ digest->ctxsize ];
428
+	uint8_t block[ digest->blocksize ];
429
+	size_t offset = 0;
430
+	size_t frag_len;
431
+
432
+	/* Initialise digest */
433
+	digest_init ( digest, ctx );
434
+
435
+	/* Process data one block at a time */
436
+	while ( len ) {
437
+		frag_len = len;
438
+		if ( frag_len > sizeof ( block ) )
439
+			frag_len = sizeof ( block );
440
+		copy_from_user ( block, data, offset, frag_len );
441
+		digest_update ( digest, ctx, block, frag_len );
442
+		offset += frag_len;
443
+		len -= frag_len;
444
+	}
445
+
446
+	/* Finalise digest */
447
+	digest_final ( digest, ctx, out );
448
+
449
+	DBGC ( sig, "CMS %p/%p digest value:\n", sig, info );
450
+	DBGC_HDA ( sig, 0, out, digest->digestsize );
451
+}
452
+
453
+/**
454
+ * Verify digest of CMS-signed data
455
+ *
456
+ * @v sig		CMS signature
457
+ * @v info		Signer information
458
+ * @v cert		Corresponding certificate
459
+ * @v data		Signed data
460
+ * @v len		Length of signed data
461
+ * @ret rc		Return status code
462
+ */
463
+static int cms_verify_digest ( struct cms_signature *sig,
464
+			       struct cms_signer_info *info,
465
+			       struct x509_certificate *cert,
466
+			       userptr_t data, size_t len ) {
467
+	struct digest_algorithm *digest = info->digest;
468
+	struct pubkey_algorithm *pubkey = info->pubkey;
469
+	struct x509_public_key *public_key = &cert->subject.public_key;
470
+	uint8_t digest_out[ digest->digestsize ];
471
+	uint8_t ctx[ pubkey->ctxsize ];
472
+	int rc;
473
+
474
+	/* Generate digest */
475
+	cms_digest ( sig, info, data, len, digest_out );
476
+
477
+	/* Initialise public-key algorithm */
478
+	if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
479
+				  public_key->raw.len ) ) != 0 ) {
480
+		DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n",
481
+		       sig, info, strerror ( rc ) );
482
+		goto err_init;
483
+	}
484
+
485
+	/* Verify digest */
486
+	if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
487
+				    info->signature,
488
+				    info->signature_len ) ) != 0 ) {
489
+		DBGC ( sig, "CMS %p/%p signature verification failed: %s\n",
490
+		       sig, info, strerror ( rc ) );
491
+		return rc;
492
+	}
493
+
494
+	pubkey_final ( pubkey, ctx );
495
+ err_init:
496
+	return rc;
497
+}
498
+
499
+/**
500
+ * Verify CMS signature signer information
501
+ *
502
+ * @v sig		CMS signature
503
+ * @v info		Signer information
504
+ * @v data		Signed data
505
+ * @v len		Length of signed data
506
+ * @v name		Required common name, or NULL to allow any name
507
+ * @v time		Time at which to validate certificates
508
+ * @v root		Root certificate store, or NULL to use default
509
+ * @ret rc		Return status code
510
+ */
511
+static int cms_verify_signer_info ( struct cms_signature *sig,
512
+				    struct cms_signer_info *info,
513
+				    userptr_t data, size_t len,
514
+				    const char *name, time_t time,
515
+				    struct x509_root *root ) {
516
+	struct cms_chain_context context;
517
+	struct x509_certificate cert;
518
+	int rc;
519
+
520
+	/* Validate certificate chain */
521
+	context.sig = sig;
522
+	context.info = info;
523
+	if ( ( rc = x509_validate_chain ( cms_parse_next, &context, time, root,
524
+					  &cert ) ) != 0 ) {
525
+		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
526
+		       sig, info, strerror ( rc ) );
527
+		return rc;
528
+	}
529
+
530
+	/* Check that certificate can create digital signatures */
531
+	if ( ! ( cert.extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
532
+		DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
533
+		       sig, info );
534
+		return -EACCES_NON_SIGNING;
535
+	}
536
+
537
+	/* Check that certificate can sign code */
538
+	if ( ! ( cert.extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
539
+		DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
540
+		       sig, info );
541
+		return -EACCES_NON_CODE_SIGNING;
542
+	}
543
+
544
+	/* Check certificate name, if applicable */
545
+	if ( ( name != NULL ) &&
546
+	     ( ( cert.subject.name.len != strlen ( name ) ) ||
547
+	       ( memcmp ( cert.subject.name.data, name,
548
+			  cert.subject.name.len ) != 0 ) ) ) {
549
+		DBGC ( sig, "CMS %p/%p certificate name incorrect\n",
550
+		       sig, info );
551
+		return -EACCES_WRONG_NAME;
552
+	}
553
+
554
+	/* Verify digest */
555
+	if ( ( rc = cms_verify_digest ( sig, info, &cert, data, len ) ) != 0 )
556
+		return rc;
557
+
558
+	return 0;
559
+}
560
+
561
+/**
562
+ * Verify CMS signature
563
+ *
564
+ * @v sig		CMS signature
565
+ * @v data		Signed data
566
+ * @v len		Length of signed data
567
+ * @v name		Required common name, or NULL to allow any name
568
+ * @v time		Time at which to validate certificates
569
+ * @v root		Root certificate store, or NULL to use default
570
+ * @ret rc		Return status code
571
+ */
572
+int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
573
+		 const char *name, time_t time, struct x509_root *root ) {
574
+	int rc;
575
+
576
+	/* Verify using first signerInfo */
577
+	if ( ( rc = cms_verify_signer_info ( sig, &sig->info, data, len,
578
+					     name, time, root ) ) != 0 )
579
+		return rc;
580
+
581
+	return 0;
582
+}

+ 6
- 0
src/include/ipxe/asn1.h View File

@@ -152,6 +152,12 @@ struct asn1_cursor {
152 152
 	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
153 153
 	ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 )
154 154
 
155
+/** ASN.1 OID for pkcs-signedData (1.2.840.113549.1.7.2) */
156
+#define ASN1_OID_SIGNEDDATA					\
157
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
158
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ),	\
159
+	ASN1_OID_SINGLE ( 7 ), ASN1_OID_SINGLE ( 2 )
160
+
155 161
 /** Define an ASN.1 cursor containing an OID */
156 162
 #define ASN1_OID_CURSOR( oid_value ) {				\
157 163
 		.data = oid_value,				\

+ 50
- 0
src/include/ipxe/cms.h View File

@@ -0,0 +1,50 @@
1
+#ifndef _IPXE_CMS_H
2
+#define _IPXE_CMS_H
3
+
4
+/** @file
5
+ *
6
+ * Cryptographic Message Syntax (PKCS #7)
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <time.h>
13
+#include <ipxe/asn1.h>
14
+#include <ipxe/crypto.h>
15
+#include <ipxe/x509.h>
16
+#include <ipxe/uaccess.h>
17
+
18
+/** CMS signer information */
19
+struct cms_signer_info {
20
+	/** Issuer name */
21
+	struct asn1_cursor issuer;
22
+	/** Serial number */
23
+	struct asn1_cursor serial;
24
+	/** Digest algorithm */
25
+	struct digest_algorithm *digest;
26
+	/** Public-key algorithm */
27
+	struct pubkey_algorithm *pubkey;
28
+	/** Signature */
29
+	const void *signature;
30
+	/** Length of signature */
31
+	size_t signature_len;
32
+};
33
+
34
+/** A CMS signature */
35
+struct cms_signature {
36
+	/** Raw certificate list */
37
+	struct asn1_cursor certificates;
38
+	/** Signer information
39
+	 *
40
+	 * We currently use only the first signer information block.
41
+	 */
42
+	struct cms_signer_info info;
43
+};
44
+
45
+extern int cms_parse ( struct cms_signature *sig, const void *data,
46
+		       size_t len );
47
+extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
48
+			const char *name, time_t time, struct x509_root *root );
49
+
50
+#endif /* _IPXE_CMS_H */

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -249,6 +249,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
249 249
 #define ERRFILE_rsa		      ( ERRFILE_OTHER | 0x00270000 )
250 250
 #define ERRFILE_linux_entropy	      ( ERRFILE_OTHER | 0x00280000 )
251 251
 #define ERRFILE_x509_test	      ( ERRFILE_OTHER | 0x00290000 )
252
+#define ERRFILE_cms		      ( ERRFILE_OTHER | 0x002a0000 )
252 253
 
253 254
 /** @} */
254 255
 

Loading…
Cancel
Save