@@ -19,7 +19,7 @@ use crate::{
19
19
} ;
20
20
21
21
pub ( crate ) struct ChainOptions < ' a > {
22
- pub ( crate ) eku : ExtendedKeyUsage ,
22
+ pub ( crate ) eku : KeyUsage ,
23
23
pub ( crate ) supported_sig_algs : & ' a [ & ' a SignatureAlgorithm ] ,
24
24
pub ( crate ) trust_anchors : & ' a [ TrustAnchor < ' a > ] ,
25
25
pub ( crate ) intermediate_certs : & ' a [ & ' a [ u8 ] ] ,
@@ -38,7 +38,7 @@ fn build_chain_inner(
38
38
) -> Result < ( ) , Error > {
39
39
let used_as_ca = used_as_ca ( & cert. ee_or_ca ) ;
40
40
41
- check_issuer_independent_properties ( cert, time, used_as_ca, sub_ca_count, opts. eku ) ?;
41
+ check_issuer_independent_properties ( cert, time, used_as_ca, sub_ca_count, opts. eku . inner ) ?;
42
42
43
43
// TODO: HPKP checks.
44
44
@@ -59,7 +59,10 @@ fn build_chain_inner(
59
59
// for the purpose of name constraints checking, only end-entity server certificates
60
60
// could plausibly have a DNS name as a subject commonName that could contribute to
61
61
// path validity
62
- let subject_common_name_contents = if opts. eku . key_purpose_id_equals ( EKU_SERVER_AUTH . oid_value )
62
+ let subject_common_name_contents = if opts
63
+ . eku
64
+ . inner
65
+ . key_purpose_id_equals ( EKU_SERVER_AUTH . oid_value )
63
66
&& used_as_ca == UsedAsCa :: No
64
67
{
65
68
subject_name:: SubjectCommonNameContents :: DnsName
@@ -334,9 +337,49 @@ fn check_basic_constraints(
334
337
}
335
338
}
336
339
340
+ /// The expected key usage of a certificate.
341
+ ///
342
+ /// This type represents the expected key usage of an end entity certificate. Although for most
343
+ /// kinds of certificates the extended key usage extension is optional (and so certificates
344
+ /// not carrying a particular value in the EKU extension are acceptable). If the extension
345
+ /// is present, the certificate MUST only be used for one of the purposes indicated.
346
+ ///
347
+ /// <https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12>
348
+ #[ derive( Clone , Copy ) ]
349
+ pub struct KeyUsage {
350
+ inner : ExtendedKeyUsage ,
351
+ }
352
+
353
+ impl KeyUsage {
354
+ /// Construct a new [`KeyUsage`] as appropriate for server certificate authentication.
355
+ ///
356
+ /// As specified in <https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.12>, this does not require the certificate to specify the eKU extension.
357
+ pub const fn server_auth ( ) -> Self {
358
+ Self {
359
+ inner : ExtendedKeyUsage :: RequiredIfPresent ( EKU_SERVER_AUTH ) ,
360
+ }
361
+ }
362
+
363
+ /// Construct a new [`KeyUsage`] as appropriate for client certificate authentication.
364
+ ///
365
+ /// As specified in <>, this does not require the certificate to specify the eKU extension.
366
+ pub const fn client_auth ( ) -> Self {
367
+ Self {
368
+ inner : ExtendedKeyUsage :: RequiredIfPresent ( EKU_CLIENT_AUTH ) ,
369
+ }
370
+ }
371
+
372
+ /// Construct a new [`KeyUsage`] requiring a certificate to support the specified OID.
373
+ pub const fn required ( oid : & ' static [ u8 ] ) -> Self {
374
+ Self {
375
+ inner : ExtendedKeyUsage :: Required ( KeyPurposeId :: new ( oid) ) ,
376
+ }
377
+ }
378
+ }
379
+
337
380
/// Extended Key Usage (EKU) of a certificate.
338
381
#[ derive( Clone , Copy ) ]
339
- pub enum ExtendedKeyUsage {
382
+ enum ExtendedKeyUsage {
340
383
/// The certificate must contain the specified [`KeyPurposeId`] as EKU.
341
384
Required ( KeyPurposeId ) ,
342
385
@@ -347,40 +390,25 @@ pub enum ExtendedKeyUsage {
347
390
impl ExtendedKeyUsage {
348
391
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
349
392
fn check ( & self , input : Option < & mut untrusted:: Reader > ) -> Result < ( ) , Error > {
350
- match input {
351
- Some ( input) => {
352
- loop {
353
- let value = der:: expect_tag_and_get_value ( input, der:: Tag :: OID ) ?;
354
- if self . key_purpose_id_equals ( value) {
355
- input. skip_to_end ( ) ;
356
- break ;
357
- }
358
- if input. at_end ( ) {
359
- return Err ( Error :: RequiredEkuNotFound ) ;
360
- }
361
- }
362
- Ok ( ( ) )
393
+ let input = match ( input, self ) {
394
+ ( Some ( input) , _) => input,
395
+ ( None , Self :: RequiredIfPresent ( _) ) => return Ok ( ( ) ) ,
396
+ ( None , Self :: Required ( _) ) => return Err ( Error :: RequiredEkuNotFound ) ,
397
+ } ;
398
+
399
+ loop {
400
+ let value = der:: expect_tag_and_get_value ( input, der:: Tag :: OID ) ?;
401
+ if self . key_purpose_id_equals ( value) {
402
+ input. skip_to_end ( ) ;
403
+ break ;
363
404
}
364
- None => {
365
- if matches ! ( self , Self :: Required ( _) ) {
366
- return Err ( Error :: RequiredEkuNotFound ) ;
367
- }
368
- // http://tools.ietf.org/html/rfc6960#section-4.2.2.2:
369
- // "OCSP signing delegation SHALL be designated by the inclusion of
370
- // id-kp-OCSPSigning in an extended key usage certificate extension
371
- // included in the OCSP response signer's certificate."
372
- //
373
- // A missing EKU extension generally means "any EKU", but it is
374
- // important that id-kp-OCSPSigning is explicit so that a normal
375
- // end-entity certificate isn't able to sign trusted OCSP responses
376
- // for itself or for other certificates issued by its issuing CA.
377
- if self . key_purpose_id_equals ( EKU_OCSP_SIGNING . oid_value ) {
378
- return Err ( Error :: RequiredEkuNotFound ) ;
379
- }
380
405
381
- Ok ( ( ) )
406
+ if input. at_end ( ) {
407
+ return Err ( Error :: RequiredEkuNotFound ) ;
382
408
}
383
409
}
410
+
411
+ Ok ( ( ) )
384
412
}
385
413
386
414
fn key_purpose_id_equals ( & self , value : untrusted:: Input < ' _ > ) -> bool {
@@ -395,15 +423,15 @@ impl ExtendedKeyUsage {
395
423
396
424
/// An OID value indicating an Extended Key Usage (EKU) key purpose.
397
425
#[ derive( Clone , Copy , PartialEq , Eq ) ]
398
- pub struct KeyPurposeId {
426
+ struct KeyPurposeId {
399
427
oid_value : untrusted:: Input < ' static > ,
400
428
}
401
429
402
430
impl KeyPurposeId {
403
431
/// Construct a new [`KeyPurposeId`].
404
432
///
405
433
/// `oid` is the OBJECT IDENTIFIER in bytes.
406
- pub const fn new ( oid : & ' static [ u8 ] ) -> Self {
434
+ const fn new ( oid : & ' static [ u8 ] ) -> Self {
407
435
Self {
408
436
oid_value : untrusted:: Input :: from ( oid) ,
409
437
}
@@ -415,18 +443,11 @@ impl KeyPurposeId {
415
443
416
444
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
417
445
#[ allow( clippy:: identity_op) ] // TODO: Make this clearer
418
- pub ( crate ) static EKU_SERVER_AUTH : KeyPurposeId =
419
- KeyPurposeId :: new ( & [ ( 40 * 1 ) + 3 , 6 , 1 , 5 , 5 , 7 , 3 , 1 ] ) ;
446
+ const EKU_SERVER_AUTH : KeyPurposeId = KeyPurposeId :: new ( & [ ( 40 * 1 ) + 3 , 6 , 1 , 5 , 5 , 7 , 3 , 1 ] ) ;
420
447
421
448
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
422
449
#[ allow( clippy:: identity_op) ] // TODO: Make this clearer
423
- pub ( crate ) static EKU_CLIENT_AUTH : KeyPurposeId =
424
- KeyPurposeId :: new ( & [ ( 40 * 1 ) + 3 , 6 , 1 , 5 , 5 , 7 , 3 , 2 ] ) ;
425
-
426
- // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
427
- #[ allow( clippy:: identity_op) ] // TODO: Make this clearer
428
- pub ( crate ) static EKU_OCSP_SIGNING : KeyPurposeId =
429
- KeyPurposeId :: new ( & [ ( 40 * 1 ) + 3 , 6 , 1 , 5 , 5 , 7 , 3 , 9 ] ) ;
450
+ const EKU_CLIENT_AUTH : KeyPurposeId = KeyPurposeId :: new ( & [ ( 40 * 1 ) + 3 , 6 , 1 , 5 , 5 , 7 , 3 , 2 ] ) ;
430
451
431
452
// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3
432
453
#[ repr( u8 ) ]
@@ -483,7 +504,7 @@ where
483
504
484
505
#[ cfg( test) ]
485
506
mod tests {
486
- use crate :: { verify_cert :: EKU_SERVER_AUTH , ExtendedKeyUsage } ;
507
+ use super :: * ;
487
508
488
509
#[ test]
489
510
fn eku_key_purpose_id ( ) {
0 commit comments