|
@@ -58,6 +58,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
58
|
58
|
#define EINFO_EACCES_STALE \
|
59
|
59
|
__einfo_uniqify ( EINFO_EACCES, 0x04, \
|
60
|
60
|
"Stale (or premature) OCSP repsonse" )
|
|
61
|
+#define EACCES_NO_RESPONDER \
|
|
62
|
+ __einfo_error ( EINFO_EACCES_NO_RESPONDER )
|
|
63
|
+#define EINFO_EACCES_NO_RESPONDER \
|
|
64
|
+ __einfo_uniqify ( EINFO_EACCES, 0x05, \
|
|
65
|
+ "Missing OCSP responder certificate" )
|
|
66
|
+#define ENOTSUP_RESPONSE_TYPE \
|
|
67
|
+ __einfo_error ( EINFO_ENOTSUP_RESPONSE_TYPE )
|
|
68
|
+#define EINFO_ENOTSUP_RESPONSE_TYPE \
|
|
69
|
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
|
|
70
|
+ "Unsupported OCSP response type" )
|
|
71
|
+#define ENOTSUP_RESPONDER_ID \
|
|
72
|
+ __einfo_error ( EINFO_ENOTSUP_RESPONDER_ID )
|
|
73
|
+#define EINFO_ENOTSUP_RESPONDER_ID \
|
|
74
|
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x02, \
|
|
75
|
+ "Unsupported OCSP responder ID" )
|
61
|
76
|
#define EPROTO_MALFORMED_REQUEST \
|
62
|
77
|
__einfo_error ( EINFO_EPROTO_MALFORMED_REQUEST )
|
63
|
78
|
#define EINFO_EPROTO_MALFORMED_REQUEST \
|
|
@@ -355,12 +370,94 @@ static int ocsp_parse_response_type ( struct ocsp_check *ocsp,
|
355
|
370
|
DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n",
|
356
|
371
|
ocsp, ocsp->cert->subject.name );
|
357
|
372
|
DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
|
358
|
|
- return -ENOTSUP;
|
|
373
|
+ return -ENOTSUP_RESPONSE_TYPE;
|
359
|
374
|
}
|
360
|
375
|
|
361
|
376
|
return 0;
|
362
|
377
|
}
|
363
|
378
|
|
|
379
|
+/**
|
|
380
|
+ * Compare responder's certificate name
|
|
381
|
+ *
|
|
382
|
+ * @v ocsp OCSP check
|
|
383
|
+ * @v cert Certificate
|
|
384
|
+ * @ret difference Difference as returned by memcmp()
|
|
385
|
+ */
|
|
386
|
+static int ocsp_compare_responder_name ( struct ocsp_check *ocsp,
|
|
387
|
+ struct x509_certificate *cert ) {
|
|
388
|
+ struct ocsp_responder *responder = &ocsp->response.responder;
|
|
389
|
+
|
|
390
|
+ /* Compare responder ID with certificate's subject */
|
|
391
|
+ return asn1_compare ( &responder->id, &cert->subject.raw );
|
|
392
|
+}
|
|
393
|
+
|
|
394
|
+/**
|
|
395
|
+ * Compare responder's certificate public key hash
|
|
396
|
+ *
|
|
397
|
+ * @v ocsp OCSP check
|
|
398
|
+ * @v cert Certificate
|
|
399
|
+ * @ret difference Difference as returned by memcmp()
|
|
400
|
+ */
|
|
401
|
+static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp,
|
|
402
|
+ struct x509_certificate *cert ) {
|
|
403
|
+ struct ocsp_responder *responder = &ocsp->response.responder;
|
|
404
|
+ uint8_t ctx[SHA1_CTX_SIZE];
|
|
405
|
+ uint8_t digest[SHA1_DIGEST_SIZE];
|
|
406
|
+ int difference;
|
|
407
|
+
|
|
408
|
+ /* Sanity check */
|
|
409
|
+ difference = ( sizeof ( digest ) - responder->id.len );
|
|
410
|
+ if ( difference )
|
|
411
|
+ return difference;
|
|
412
|
+
|
|
413
|
+ /* Generate SHA1 hash of certificate's public key */
|
|
414
|
+ digest_init ( &sha1_algorithm, ctx );
|
|
415
|
+ digest_update ( &sha1_algorithm, ctx,
|
|
416
|
+ cert->subject.public_key.raw_bits.data,
|
|
417
|
+ cert->subject.public_key.raw_bits.len );
|
|
418
|
+ digest_final ( &sha1_algorithm, ctx, digest );
|
|
419
|
+
|
|
420
|
+ /* Compare responder ID with SHA1 hash of certificate's public key */
|
|
421
|
+ return memcmp ( digest, responder->id.data, sizeof ( digest ) );
|
|
422
|
+}
|
|
423
|
+
|
|
424
|
+/**
|
|
425
|
+ * Parse OCSP responder ID
|
|
426
|
+ *
|
|
427
|
+ * @v ocsp OCSP check
|
|
428
|
+ * @v raw ASN.1 cursor
|
|
429
|
+ * @ret rc Return status code
|
|
430
|
+ */
|
|
431
|
+static int ocsp_parse_responder_id ( struct ocsp_check *ocsp,
|
|
432
|
+ const struct asn1_cursor *raw ) {
|
|
433
|
+ struct ocsp_responder *responder = &ocsp->response.responder;
|
|
434
|
+ struct asn1_cursor *responder_id = &responder->id;
|
|
435
|
+ unsigned int type;
|
|
436
|
+
|
|
437
|
+ /* Enter responder ID */
|
|
438
|
+ memcpy ( responder_id, raw, sizeof ( *responder_id ) );
|
|
439
|
+ type = asn1_type ( responder_id );
|
|
440
|
+ asn1_enter_any ( responder_id );
|
|
441
|
+
|
|
442
|
+ /* Identify responder ID type */
|
|
443
|
+ switch ( type ) {
|
|
444
|
+ case ASN1_EXPLICIT_TAG ( 1 ) :
|
|
445
|
+ DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by name\n",
|
|
446
|
+ ocsp, ocsp->cert->subject.name );
|
|
447
|
+ responder->compare = ocsp_compare_responder_name;
|
|
448
|
+ return 0;
|
|
449
|
+ case ASN1_EXPLICIT_TAG ( 2 ) :
|
|
450
|
+ DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by key "
|
|
451
|
+ "hash\n", ocsp, ocsp->cert->subject.name );
|
|
452
|
+ responder->compare = ocsp_compare_responder_key_hash;
|
|
453
|
+ return 0;
|
|
454
|
+ default:
|
|
455
|
+ DBGC ( ocsp, "OCSP %p \"%s\" unsupported responder ID type "
|
|
456
|
+ "%d\n", ocsp, ocsp->cert->subject.name, type );
|
|
457
|
+ return -ENOTSUP_RESPONDER_ID;
|
|
458
|
+ }
|
|
459
|
+}
|
|
460
|
+
|
364
|
461
|
/**
|
365
|
462
|
* Parse OCSP certificate ID
|
366
|
463
|
*
|
|
@@ -484,7 +581,9 @@ static int ocsp_parse_tbs_response_data ( struct ocsp_check *ocsp,
|
484
|
581
|
/* Skip version, if present */
|
485
|
582
|
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
|
486
|
583
|
|
487
|
|
- /* Skip responderID */
|
|
584
|
+ /* Parse responderID */
|
|
585
|
+ if ( ( rc = ocsp_parse_responder_id ( ocsp, &cursor ) ) != 0 )
|
|
586
|
+ return rc;
|
488
|
587
|
asn1_skip_any ( &cursor );
|
489
|
588
|
|
490
|
589
|
/* Skip producedAt */
|
|
@@ -508,6 +607,7 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp,
|
508
|
607
|
const struct asn1_cursor *raw ) {
|
509
|
608
|
struct ocsp_response *response = &ocsp->response;
|
510
|
609
|
struct asn1_cursor cursor;
|
|
610
|
+ struct x509_certificate *cert;
|
511
|
611
|
int rc;
|
512
|
612
|
|
513
|
613
|
/* Enter certs */
|
|
@@ -519,20 +619,39 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp,
|
519
|
619
|
* multiple certificates, but the protocol requires that the
|
520
|
620
|
* OCSP signing certificate must either be the issuer itself,
|
521
|
621
|
* or must be directly issued by the issuer (see RFC2560
|
522
|
|
- * section 4.2.2.2 "Authorized Responders").
|
|
622
|
+ * section 4.2.2.2 "Authorized Responders"). We therefore
|
|
623
|
+ * need to identify only the single certificate matching the
|
|
624
|
+ * Responder ID.
|
523
|
625
|
*/
|
524
|
|
- if ( ( cursor.len != 0 ) &&
|
525
|
|
- ( ( rc = x509_certificate ( cursor.data, cursor.len,
|
526
|
|
- &response->signer ) ) != 0 ) ) {
|
527
|
|
- DBGC ( ocsp, "OCSP %p \"%s\" could not parse certificate: "
|
528
|
|
- "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
|
529
|
|
- DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
|
530
|
|
- return rc;
|
|
626
|
+ while ( cursor.len ) {
|
|
627
|
+
|
|
628
|
+ /* Parse certificate */
|
|
629
|
+ if ( ( rc = x509_certificate ( cursor.data, cursor.len,
|
|
630
|
+ &cert ) ) != 0 ) {
|
|
631
|
+ DBGC ( ocsp, "OCSP %p \"%s\" could not parse "
|
|
632
|
+ "certificate: %s\n", ocsp,
|
|
633
|
+ ocsp->cert->subject.name, strerror ( rc ) );
|
|
634
|
+ DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
|
|
635
|
+ return rc;
|
|
636
|
+ }
|
|
637
|
+
|
|
638
|
+ /* Use if this certificate matches the responder ID */
|
|
639
|
+ if ( response->responder.compare ( ocsp, cert ) == 0 ) {
|
|
640
|
+ response->signer = cert;
|
|
641
|
+ DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by "
|
|
642
|
+ "\"%s\"\n", ocsp, ocsp->cert->subject.name,
|
|
643
|
+ response->signer->subject.name );
|
|
644
|
+ return 0;
|
|
645
|
+ }
|
|
646
|
+
|
|
647
|
+ /* Otherwise, discard this certificate */
|
|
648
|
+ x509_put ( cert );
|
|
649
|
+ asn1_skip_any ( &cursor );
|
531
|
650
|
}
|
532
|
|
- DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by \"%s\"\n", ocsp,
|
533
|
|
- ocsp->cert->subject.name, response->signer->subject.name );
|
534
|
651
|
|
535
|
|
- return 0;
|
|
652
|
+ DBGC ( ocsp, "OCSP %p \"%s\" missing responder certificate\n",
|
|
653
|
+ ocsp, ocsp->cert->subject.name );
|
|
654
|
+ return -EACCES_NO_RESPONDER;
|
536
|
655
|
}
|
537
|
656
|
|
538
|
657
|
/**
|