@@ -73,22 +73,21 @@ type AMDRootCerts struct {
73
73
// ArkX509 is an X.509 certificate for the AMD root key (ARK).
74
74
ArkX509 * x509.Certificate
75
75
// AskSev is the AMD certificate representation of the AMD signing key that certifies
76
- // versioned chip endoresement keys.
76
+ // versioned chip endoresement keys. If present, the information must match AskX509.
77
77
AskSev * abi.AskCert
78
78
// ArkSev is the AMD certificate representation of the self-signed AMD root key that
79
- // certifies the AMD signing key.
79
+ // certifies the AMD signing key. If present, the information must match ArkX509.
80
80
ArkSev * abi.AskCert
81
81
// Protects concurrent updates to CRL.
82
82
mu sync.Mutex
83
83
// CRL is the certificate revocation list for this AMD platform. Populated once, only when a
84
84
// revocation is checked.
85
- CRL * x509.RevocationList
86
- noCrossCheckTestOnly bool
85
+ CRL * x509.RevocationList
87
86
}
88
87
89
88
// DefaultRootCerts holds AMD's SEV API certificate format for ASK and ARK keys as published here
90
89
// https://developer.amd.com/wp-content/resources/ask_ark_milan.cert
91
- var DefaultRootCerts AMDRootCerts
90
+ var DefaultRootCerts map [ string ] * AMDRootCerts
92
91
93
92
// Unmarshal populates ASK and ARK certificates from AMD SEV format certificates in data.
94
93
func (r * AMDRootCerts ) Unmarshal (data []byte ) error {
@@ -161,7 +160,11 @@ func (r *AMDRootCerts) X509Options() *x509.VerifyOptions {
161
160
162
161
// Parse ASK, ARK certificates from the embedded AMD certificate file.
163
162
func init () {
164
- DefaultRootCerts .Unmarshal (askArkMilanBytes )
163
+ milanCerts := new (AMDRootCerts )
164
+ milanCerts .Unmarshal (askArkMilanBytes )
165
+ DefaultRootCerts = map [string ]* AMDRootCerts {
166
+ "Milan" : milanCerts ,
167
+ }
165
168
}
166
169
167
170
func askVerifiedBy (signee , signer * abi.AskCert , signeeName , signerName string ) error {
@@ -276,7 +279,7 @@ func (r *AMDRootCerts) validateRootX509(x *x509.Certificate, version int, role,
276
279
// cryptographic signatures.
277
280
func (r * AMDRootCerts ) ValidateAskX509 () error {
278
281
if r == nil {
279
- r = & DefaultRootCerts
282
+ r = DefaultRootCerts [ "Milan" ]
280
283
}
281
284
var cn string
282
285
if r .Platform != "" {
@@ -285,21 +288,17 @@ func (r *AMDRootCerts) ValidateAskX509() error {
285
288
if err := r .validateRootX509 (r .AskX509 , askX509Version , "ASK" , cn ); err != nil {
286
289
return err
287
290
}
288
- askSev := r .AskSev
289
- if askSev == nil {
290
- askSev = DefaultRootCerts .AskSev
291
- }
292
- if r .noCrossCheckTestOnly {
293
- return nil
291
+ if r .AskSev != nil {
292
+ return crossCheckSevX509 (r .AskSev , r .AskX509 )
294
293
}
295
- return crossCheckSevX509 ( askSev , r . AskX509 )
294
+ return nil
296
295
}
297
296
298
297
// ValidateArkX509 checks expected metadata about the ARK X.509 certificate. It does not verify the
299
298
// cryptographic signatures.
300
299
func (r * AMDRootCerts ) ValidateArkX509 () error {
301
300
if r == nil {
302
- r = & DefaultRootCerts
301
+ r = DefaultRootCerts [ "Milan" ]
303
302
}
304
303
var cn string
305
304
if r .Platform != "" {
@@ -308,14 +307,10 @@ func (r *AMDRootCerts) ValidateArkX509() error {
308
307
if err := r .validateRootX509 (r .ArkX509 , arkX509Version , "ARK" , cn ); err != nil {
309
308
return err
310
309
}
311
- arkSev := r .ArkSev
312
- if arkSev == nil {
313
- arkSev = DefaultRootCerts .ArkSev
314
- }
315
- if r .noCrossCheckTestOnly {
316
- return nil
310
+ if r .ArkSev != nil {
311
+ return crossCheckSevX509 (r .ArkSev , r .ArkX509 )
317
312
}
318
- return crossCheckSevX509 ( arkSev , r . ArkX509 )
313
+ return nil
319
314
}
320
315
321
316
// Checks some steps of AMD SEV API Appendix B.3
@@ -335,7 +330,7 @@ func validateRootSev(subject, issuer *abi.AskCert, version, keyUsage uint32, sub
335
330
// This covers steps 1, 2, and 5
336
331
func (r * AMDRootCerts ) ValidateAskSev () error {
337
332
if r == nil {
338
- r = & DefaultRootCerts
333
+ r = DefaultRootCerts [ "Milan" ]
339
334
}
340
335
return validateRootSev (r .AskSev , r .ArkSev , askVersion , askKeyUsage , "ASK" , "ARK" )
341
336
}
@@ -344,19 +339,19 @@ func (r *AMDRootCerts) ValidateAskSev() error {
344
339
// This covers steps 5, 6, 9, and 11.
345
340
func (r * AMDRootCerts ) ValidateArkSev () error {
346
341
if r == nil {
347
- r = & DefaultRootCerts
342
+ r = DefaultRootCerts [ "Milan" ]
348
343
}
349
344
return validateRootSev (r .ArkSev , r .ArkSev , arkVersion , arkKeyUsage , "ARK" , "ARK" )
350
345
}
351
346
352
347
// ValidateX509 will validate the x509 certificates of the ASK and ARK.
353
348
func (r * AMDRootCerts ) ValidateX509 () error {
354
- if err := r .ValidateAskX509 (); err != nil {
355
- return fmt .Errorf ("ASK validation error: %v" , err )
356
- }
357
349
if err := r .ValidateArkX509 (); err != nil {
358
350
return fmt .Errorf ("ARK validation error: %v" , err )
359
351
}
352
+ if err := r .ValidateAskX509 (); err != nil {
353
+ return fmt .Errorf ("ASK validation error: %v" , err )
354
+ }
360
355
return nil
361
356
}
362
357
@@ -448,7 +443,7 @@ func (r *AMDRootCerts) validateVcekCertificatePlatformSpecifics(cert *x509.Certi
448
443
// VcekDER checks that the VCEK certificate matches expected fields
449
444
// from the KDS specification and also that its certificate chain matches
450
445
// hardcoded trusted root certificates from AMD.
451
- func VcekDER (vcek []byte , ask []byte , ark []byte ) (* x509.Certificate , * AMDRootCerts , error ) {
446
+ func VcekDER (vcek []byte , ask []byte , ark []byte , options * Options ) (* x509.Certificate , * AMDRootCerts , error ) {
452
447
vcekCert , err := x509 .ParseCertificate (vcek )
453
448
if err != nil {
454
449
return nil , nil , fmt .Errorf ("could not interpret VCEK DER bytes: %v" , err )
@@ -457,21 +452,34 @@ func VcekDER(vcek []byte, ask []byte, ark []byte) (*x509.Certificate, *AMDRootCe
457
452
if err != nil {
458
453
return nil , nil , err
459
454
}
460
- root := & AMDRootCerts {
461
- Platform : vcekProductMap [exts .ProductName ],
462
- // Allow tests to disable crosscheck on test-only certificates.
463
- noCrossCheckTestOnly : DefaultRootCerts .noCrossCheckTestOnly ,
464
- }
465
- if err := root .FromDER (ask , ark ); err != nil {
466
- return nil , nil , err
467
- }
468
- if err := root .ValidateX509 (); err != nil {
469
- return nil , nil , err
455
+ roots := options .TrustedRoots
456
+ platform := vcekProductMap [exts .ProductName ]
457
+ if roots == nil {
458
+ root := & AMDRootCerts {
459
+ Platform : platform ,
460
+ // Require that the root matches embedded root certs.
461
+ AskSev : DefaultRootCerts [platform ].AskSev ,
462
+ ArkSev : DefaultRootCerts [platform ].ArkSev ,
463
+ }
464
+ if err := root .FromDER (ask , ark ); err != nil {
465
+ return nil , nil , err
466
+ }
467
+ if err := root .ValidateX509 (); err != nil {
468
+ return nil , nil , err
469
+ }
470
+ roots = map [string ][]* AMDRootCerts {
471
+ platform : []* AMDRootCerts {root },
472
+ }
470
473
}
471
- if err := root .validateVcekCertificatePlatformSpecifics (vcekCert ); err != nil {
472
- return nil , nil , err
474
+ var lastErr error
475
+ for _ , platformRoot := range roots [platform ] {
476
+ if err := platformRoot .validateVcekCertificatePlatformSpecifics (vcekCert ); err != nil {
477
+ lastErr = err
478
+ continue
479
+ }
480
+ return vcekCert , platformRoot , nil
473
481
}
474
- return vcekCert , root , nil
482
+ return nil , nil , fmt . Errorf ( "VCEK could not be verified by any trusted roots. Last error: %v" , lastErr )
475
483
}
476
484
477
485
// SnpReportSignature verifies the attestation report's signature based on the report's
@@ -509,13 +517,17 @@ type Options struct {
509
517
// Getter takes a URL and returns the body of its contents. By default uses http.Get and returns
510
518
// the body.
511
519
Getter HTTPSGetter
520
+ // TrustedRoots specifies the ARK and ASK certificates to trust when checking the VCEK. If nil,
521
+ // then verification will fall back on embedded AMD-published root certificates.
522
+ // Maps the platform name to an array of allowed roots.
523
+ TrustedRoots map [string ][]* AMDRootCerts
512
524
}
513
525
514
526
// SnpAttestation verifies the protobuf representation of an attestation report's signature based
515
527
// on the report's SignatureAlgo, provided the certificate chain is valid.
516
528
func SnpAttestation (attestation * spb.Attestation , options * Options ) error {
517
529
chain := attestation .GetCertificateChain ()
518
- vcek , root , err := VcekDER (chain .GetVcekCert (), chain .GetAskCert (), chain .GetArkCert ())
530
+ vcek , root , err := VcekDER (chain .GetVcekCert (), chain .GetAskCert (), chain .GetArkCert (), options )
519
531
if err != nil {
520
532
return err
521
533
}
0 commit comments