Skip to content

Commit d0c06e8

Browse files
authored
Sign support (#251)
Add verification tests for the Sign command
1 parent 1b68c8a commit d0c06e8

File tree

4 files changed

+289
-27
lines changed

4 files changed

+289
-27
lines changed

verification/certifyKey.go

Lines changed: 105 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ package verification
44

55
import (
66
"bytes"
7+
"crypto/ecdsa"
8+
"crypto/elliptic"
79
"crypto/x509"
810
"encoding/asn1"
911
"encoding/binary"
1012
"encoding/pem"
1113
"fmt"
14+
"math/big"
1215
"reflect"
1316
"testing"
1417
"time"
@@ -117,18 +120,23 @@ const (
117120

118121
type TcgMultiTcbInfo = []DiceTcbInfo
119122

123+
type CertifyKeyParams struct {
124+
Label []byte
125+
Flags CertifyKeyFlags
126+
}
127+
120128
func TestCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T) {
121129
testCertifyKey(d, c, t, false)
122130
}
123131

124-
func TestCertifyKey_SimulationMode(d TestDPEInstance, c DPEClient, t *testing.T) {
132+
func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) {
125133
testCertifyKey(d, c, t, true)
126134
}
127135

128136
// Ignores critical extensions that are unknown to x509 package
129137
// but atleast defined in DPE certificate profile specification.
130138
// UnhandledCriticalExtensions may have only custom extensions mentioned in spec
131-
// unknownExtnMap collects extensions unknown to both x59 and the DICE certificate profiles spec.
139+
// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec.
132140
// positive case expects the unknownExtnMap to be empty.
133141
func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) {
134142
t.Helper()
@@ -158,6 +166,11 @@ func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) {
158166
}
159167
}
160168

169+
// Ignores extended key usages that are unknown to x509 package
170+
// but atleast defined in DPE certificate profile specification.
171+
// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec
172+
// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec.
173+
// positive case expects the unknownKeyUsagesMap to be empty.
161174
func removeTcgDiceExtendedKeyUsages(t *testing.T, certs []*x509.Certificate) {
162175
t.Helper()
163176
unknownKeyUsagesMap := map[string][]string{}
@@ -218,7 +231,7 @@ func checkCertifyKeyTcgUeidExtension(t *testing.T, c *x509.Certificate, label []
218231
}
219232
}
220233

221-
// Check whether certificate extended key usage is as per spec
234+
// Checks whether certificate extended key usage is as per spec
222235
// OID for ExtendedKeyUsage Extension: 2.5.29.37
223236
// The ExtendedKeyUsage extension SHOULD be marked as critical
224237
// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca
@@ -274,7 +287,7 @@ func checkCertifyKeyExtendedKeyUsages(t *testing.T, c *x509.Certificate) (*TcgMu
274287
return multiTcbInfo, err
275288
}
276289

277-
// Check for KeyUsage Extension as per spec
290+
// Checks for KeyUsage Extension as per spec
278291
// If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign
279292
// If IsCA = false, KeyUsage extension MUST contain only DigitalSignature
280293
func checkCertifyKeyExtensions(t *testing.T, c *x509.Certificate) {
@@ -296,25 +309,25 @@ func checkCertifyKeyExtensions(t *testing.T, c *x509.Certificate) {
296309

297310
}
298311

299-
// Validate basic constraints in certificate returned by CertifyKey command
312+
// Validates basic constraints in certificate returned by CertifyKey command
300313
// against the flag set for input parameter.
301314
// The BasicConstraints extension MUST be included
302315
// If CertifyKey AddIsCA is set, IsCA MUST be set to true.
303316
// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false
304-
func checkCertifyKeyBasicConstraints(t *testing.T, c *x509.Certificate, flags uint32) {
317+
func checkCertifyKeyBasicConstraints(t *testing.T, c *x509.Certificate, flags CertifyKeyFlags) {
305318
t.Helper()
306319

307320
flagsBuf := &bytes.Buffer{}
308321
binary.Write(flagsBuf, binary.LittleEndian, flags)
309322

310-
flagIsCA := uint32(CertifyAddIsCA)&flags != 0
323+
flagIsCA := CertifyAddIsCA&flags != 0
311324
if flagIsCA != c.IsCA {
312325
t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, c.IsCA)
313326
}
314327
}
315328

316-
// Validate X509 fields in certificate returned by CertifyKey command.
317-
func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags uint32, label []byte) {
329+
// Validates X509 fields in certificate returned by CertifyKey command.
330+
func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags CertifyKeyFlags, label []byte) {
318331
t.Helper()
319332

320333
// Check for basic constraints extension
@@ -337,6 +350,7 @@ func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags uint32, lab
337350
}
338351
}
339352

353+
// Parses X509 certificate
340354
func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate {
341355
t.Helper()
342356
failed := false
@@ -411,44 +425,48 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate
411425
return x509Cert
412426
}
413427

414-
func testCertifyKey(d TestDPEInstance, client DPEClient, t *testing.T, simulation bool) {
415-
ctx := getInitialContextHandle(d, client, t, simulation)
428+
func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) {
429+
handle := getInitialContextHandle(d, c, t, simulation)
416430
defer func() {
417431
if simulation {
418-
client.DestroyContext(ctx, DestroyDescendants)
432+
c.DestroyContext(handle, DestroyDescendants)
419433
}
420434
}()
421435

422-
type Params struct {
423-
Label []byte
424-
Flags CertifyKeyFlags
425-
}
426-
427436
profile, err := GetTransportProfile(d)
428437
if err != nil {
429438
t.Fatalf("Could not get profile: %v", err)
430439
}
431440
digestLen := profile.GetDigestSize()
432441

442+
var hashAlg asn1.ObjectIdentifier
443+
if digestLen == 32 {
444+
hashAlg = OidSHA256
445+
} else if digestLen == 48 {
446+
hashAlg = OidSHA384
447+
} else {
448+
t.Fatal("Unknown Hash Algorithm")
449+
}
450+
433451
seqLabel := make([]byte, digestLen)
434452
for i := range seqLabel {
435453
seqLabel[i] = byte(i)
436454
}
437455

438-
certifyKeyParams := []Params{
456+
certifyKeyParams := []CertifyKeyParams{
439457
{Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)},
440458
{Label: seqLabel, Flags: CertifyKeyFlags(0)},
441459
}
442460

443461
for _, params := range certifyKeyParams {
444462
// Get DPE leaf certificate from CertifyKey
445-
certifyKeyResp, err := client.CertifyKey(ctx, params.Label, CertifyKeyX509, params.Flags)
463+
certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags)
446464
if err != nil {
447465
t.Fatalf("[FATAL]: Could not certify key: %v", err)
448466
}
449467

450468
// Get root and intermediate certificates to validate certificate chain of leaf cert
451-
certChainBytes, err := client.GetCertificateChain()
469+
certChainBytes, err := c.GetCertificateChain()
452470
if err != nil {
453471
t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err)
454472
}
@@ -459,8 +477,14 @@ func testCertifyKey(d TestDPEInstance, client DPEClient, t *testing.T, simulatio
459477
leafCert := checkCertificateStructure(t, leafCertBytes)
460478
certChain := checkCertificateChain(t, certChainBytes)
461479

480+
// Check default context handle is unchanged
481+
checkCertifyKeyRespHandle(*certifyKeyResp, t, handle)
482+
483+
// Check key returned in command response against certificate
484+
checkCertifyKeyResponse(t, leafCert, *certifyKeyResp, hashAlg)
485+
462486
// Validate that all X.509 fields conform with the format defined in the DPE iRoT profile
463-
validateCertifyKeyCert(t, leafCert, uint32(params.Flags), params.Label)
487+
validateCertifyKeyCert(t, leafCert, params.Flags, params.Label)
464488

465489
// Ensure full certificate chain has valid signatures
466490
// This also checks certificate lifetime, signatures as part of cert chain validation
@@ -469,13 +493,12 @@ func testCertifyKey(d TestDPEInstance, client DPEClient, t *testing.T, simulatio
469493
// Reassign handle for simulation mode.
470494
// However, this does not impact in default mode because
471495
// same default context handle is returned in default mode.
472-
ctx = &certifyKeyResp.Handle
473-
474-
// TODO: When DeriveChild is implemented, call it here to add more TCIs and call CertifyKey again.
496+
handle = &certifyKeyResp.Handle
475497
}
498+
// TODO: When DeriveChild is implemented, call it here to add more TCIs and call CertifyKey again.
476499
}
477500

478-
// Build certificate chain and calls to validateSignature on each chain.
501+
// Builds and verifies certificate chain.
479502
func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) {
480503
t.Helper()
481504
certsToProcess := []*x509.Certificate{leafCert}
@@ -502,6 +525,7 @@ func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert
502525
}
503526
}
504527

528+
// Builds Certificate chain verifier parameters.
505529
func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.VerifyOptions {
506530
roots := x509.NewCertPool()
507531
intermediates := x509.NewCertPool()
@@ -526,6 +550,7 @@ func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.Verify
526550
return opts
527551
}
528552

553+
// Gets KeyUsage bitmap and returns as list of KeyUsage name strings.
529554
func getKeyUsageNames(keyUsage x509.KeyUsage) []string {
530555
keyUsageNames := []string{}
531556

@@ -567,3 +592,58 @@ func getKeyUsageNames(keyUsage x509.KeyUsage) []string {
567592

568593
return keyUsageNames
569594
}
595+
596+
// Checks CertifyKey command response against public key extracted from certificate returned in response
597+
func checkCertifyKeyResponse(t *testing.T, x509Cert *x509.Certificate, response CertifiedKey, hashAlg asn1.ObjectIdentifier) {
598+
var err error
599+
600+
publicKeyDer, err := x509.MarshalPKIXPublicKey(x509Cert.PublicKey)
601+
if err != nil {
602+
t.Fatalf("[FATAL]: Could not marshal pub key: %v", err)
603+
}
604+
605+
// Parse the DER-encoded public key
606+
pubKeyInCert, err := x509.ParsePKIXPublicKey(publicKeyDer)
607+
if err != nil {
608+
t.Fatalf("[FATAL]: Failed to parse DER-encoded public key: %v", err)
609+
}
610+
611+
if _, ok := pubKeyInCert.(*ecdsa.PublicKey); !ok {
612+
t.Fatal("[FATAL]: Public key is not a ecdsa key")
613+
}
614+
615+
var pubKeyInResponse ecdsa.PublicKey
616+
617+
if hashAlg.Equal(OidSHA384) {
618+
pubKeyInResponse = ecdsa.PublicKey{
619+
Curve: elliptic.P384(),
620+
X: new(big.Int).SetBytes(response.Pub.X),
621+
Y: new(big.Int).SetBytes(response.Pub.Y),
622+
}
623+
} else if hashAlg.Equal(OidSHA256) {
624+
pubKeyInResponse = ecdsa.PublicKey{
625+
Curve: elliptic.P256(),
626+
X: new(big.Int).SetBytes(response.Pub.X),
627+
Y: new(big.Int).SetBytes(response.Pub.Y),
628+
}
629+
} else {
630+
t.Errorf("[ERROR]: Unsupported hash algorithm.")
631+
return
632+
}
633+
634+
if !(pubKeyInResponse.Equal(pubKeyInCert)) {
635+
t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the certificate.")
636+
}
637+
}
638+
639+
// Checks whether the context handle is unchanged after certifyKey command when default context handle is used.
640+
func checkCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHandle) {
641+
if *handle != DefaultContextHandle {
642+
t.Logf("[LOG]: Handle is not default context, skipping check...")
643+
return
644+
}
645+
646+
if res.Handle != *handle {
647+
t.Errorf("[ERROR]: Handle must be unchanged by CertifyKey, want original handle %v but got %v", handle, res.Handle)
648+
}
649+
}

0 commit comments

Comments
 (0)