3
3
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
5
5
use const_oid:: { AssociatedOid , ObjectIdentifier } ;
6
- use digest:: Digest ;
6
+ use der:: Sequence ;
7
+ use digest:: { typenum:: Unsigned , Digest , OutputSizeUser } ;
7
8
use flagset:: FlagSet ;
8
- use miette:: { IntoDiagnostic , Result } ;
9
+ use miette:: { IntoDiagnostic , Result , WrapErr } ;
9
10
use sha1:: Sha1 ;
11
+ use sha2:: { Sha256 , Sha384 , Sha512 } ;
10
12
use x509_cert:: {
11
13
attr:: AttributeTypeAndValue ,
12
14
der:: {
13
- asn1:: { PrintableStringRef , SetOfVec , Utf8StringRef } ,
15
+ self ,
16
+ asn1:: { OctetString , PrintableStringRef , SetOfVec , Utf8StringRef } ,
14
17
Decode as _, Encode as _,
15
18
} ,
16
19
ext:: pkix:: { certpolicy:: PolicyInformation , BasicConstraints , KeyUsage } ,
@@ -26,6 +29,7 @@ pub mod ed25519;
26
29
pub mod p384;
27
30
pub mod rsa;
28
31
32
+ use crate :: config:: DigestAlgorithm ;
29
33
use crate :: p384:: P384KeyPair ;
30
34
use crate :: rsa:: RsaKeyPair ;
31
35
use ed25519:: Ed25519KeyPair ;
@@ -176,6 +180,9 @@ impl dyn Extension {
176
180
config:: X509Extensions :: CertificatePolicies ( x) => {
177
181
Ok ( Box :: new ( CertificatePoliciesExtension :: from_config ( x) ?) )
178
182
}
183
+ config:: X509Extensions :: DiceTcbInfo ( c) => {
184
+ Ok ( Box :: new ( DiceTcbInfoExtension :: from_config ( c) ?) )
185
+ }
179
186
}
180
187
}
181
188
}
@@ -501,3 +508,113 @@ impl CertificatePoliciesExtension {
501
508
} )
502
509
}
503
510
}
511
+
512
+ // DICE Attestation Architecture §6.1.1:
513
+ // FWID ::== SEQUENCE {
514
+ #[ derive( Debug , Sequence ) ]
515
+ pub struct Fwid {
516
+ // hashAlg OBJECT IDENTIFIER,
517
+ hash_algorithm : ObjectIdentifier ,
518
+ // digest OCTET STRING
519
+ digest : OctetString ,
520
+ }
521
+
522
+ impl Fwid {
523
+ fn from_config ( config : & config:: Fwid ) -> Result < Self > {
524
+ let ( hash_algorithm, length) = match config. digest_algorithm {
525
+ DigestAlgorithm :: Sha_256 => {
526
+ ( Sha256 :: OID , <Sha256 as OutputSizeUser >:: OutputSize :: USIZE )
527
+ }
528
+ DigestAlgorithm :: Sha_384 => {
529
+ ( Sha384 :: OID , <Sha384 as OutputSizeUser >:: OutputSize :: USIZE )
530
+ }
531
+ DigestAlgorithm :: Sha_512 => {
532
+ ( Sha512 :: OID , <Sha512 as OutputSizeUser >:: OutputSize :: USIZE )
533
+ }
534
+ } ;
535
+
536
+ let digest = hex:: decode ( & config. digest )
537
+ . into_diagnostic ( )
538
+ . wrap_err ( "Decode FWID digest" ) ?;
539
+
540
+ if digest. len ( ) != length {
541
+ return Err ( miette:: miette!(
542
+ "Unexpected digest length: expected {}, got {}" ,
543
+ length,
544
+ digest. len( ) ,
545
+ ) ) ;
546
+ }
547
+
548
+ let digest = OctetString :: new ( digest)
549
+ . into_diagnostic ( )
550
+ . wrap_err ( "digest to OctetString" ) ?;
551
+
552
+ Ok ( Fwid {
553
+ digest,
554
+ hash_algorithm,
555
+ } )
556
+ }
557
+ }
558
+
559
+ // NOTE: All fields in this structure is optional and we only implement support
560
+ // for the ones that we currently need. Additional fields should be added as
561
+ // needed.
562
+ //
563
+ // DICE Attestation Architecture §6.1.1:
564
+ // DiceTcbInfo ::== SEQUENCE {
565
+ #[ derive( Debug , Sequence ) ]
566
+ pub struct DiceTcbInfo {
567
+ // fwids[6] IMPLICIT FWIDLIST OPTIONAL,
568
+ // where FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID
569
+ #[ asn1( context_specific = "6" , tag_mode = "IMPLICIT" , optional = "true" ) ]
570
+ fwids : Option < Vec < Fwid > > ,
571
+ }
572
+
573
+ #[ derive( Debug ) ]
574
+ pub struct DiceTcbInfoExtension {
575
+ der : Vec < u8 > ,
576
+ is_critical : bool ,
577
+ }
578
+
579
+ impl Extension for DiceTcbInfoExtension {
580
+ fn oid ( & self ) -> ObjectIdentifier {
581
+ Self :: OID
582
+ }
583
+
584
+ fn is_critical ( & self ) -> bool {
585
+ self . is_critical
586
+ }
587
+
588
+ fn as_der ( & self ) -> & [ u8 ] {
589
+ & self . der
590
+ }
591
+ }
592
+
593
+ impl DiceTcbInfoExtension {
594
+ // tcg-dice-TcbInfo from ASN.1 in DICE Attestation Architecture §6.1.1
595
+ const OID : ObjectIdentifier = ObjectIdentifier :: new_unwrap ( "2.23.133.5.4.1" ) ;
596
+
597
+ pub fn from_config ( config : & config:: DiceTcbInfoExtension ) -> Result < Self > {
598
+ let mut fwids: Vec < Fwid > = Vec :: new ( ) ;
599
+
600
+ for fwid in & config. fwid_list {
601
+ let fwid = Fwid :: from_config ( fwid) . wrap_err ( "Fwid from config" ) ?;
602
+
603
+ fwids. push ( fwid) ;
604
+ }
605
+
606
+ let fwids = if !fwids. is_empty ( ) { Some ( fwids) } else { None } ;
607
+
608
+ let tcb_info = DiceTcbInfo { fwids } ;
609
+
610
+ let der = tcb_info
611
+ . to_der ( )
612
+ . into_diagnostic ( )
613
+ . wrap_err ( "fwid list to DER" ) ?;
614
+
615
+ Ok ( DiceTcbInfoExtension {
616
+ der,
617
+ is_critical : config. critical ,
618
+ } )
619
+ }
620
+ }
0 commit comments