Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/spm/sku_sival_pqc.yml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
sku: "sival_pqc"
slotId: 0
numSessions: 3
certCountX509: 4
certCountX509: 5
certCountCWT: 0
symmetricKeys:
- name: eg-kdf-hisec-v0
Expand Down Expand Up @@ -46,3 +46,4 @@ x509CertHashOrder:
- UDS
- CDI_0
- CDI_1
- PQ_UDS_44
2 changes: 0 additions & 2 deletions src/ate/ate_dll.cc
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,6 @@ DLLEXPORT int GetCaCerts(ate_client_ptr client, const char* sku, size_t count,
cert_label_name = "OSAT_ICA_DICE_MLDSA";
} else if (label == "ext") {
cert_label_name = "OSAT_ICA_EXT";
} else if (label == "ext_mldsa") {
cert_label_name = "OSAT_ICA_EXT_MLDSA";
} else {
LOG(ERROR) << "Unknown CA certificate label: " << label;
return static_cast<int>(absl::StatusCode::kInvalidArgument);
Expand Down
16 changes: 12 additions & 4 deletions src/ate/test_programs/ft.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ int main(int argc, char** argv) {
};
if (absl::GetFlag(FLAGS_enable_mldsa_dice)) {
ica_cert_labels.push_back("PQ_UDS_44");
ica_cert_labels.push_back("EXT_MLDSA");
ica_cert_labels.push_back("PQ_UDS_87");
}

std::vector<ca_subject_key_t> key_ids(ica_cert_labels.size());
Expand Down Expand Up @@ -405,14 +405,22 @@ int main(int argc, char** argv) {
ca_certs = dice_ca_certs;
}

// Send the endorsed certs back to the device.
// Send the endorsed certs back to the device (excluding PQ_UDS_87, which is
// endorsed and sent to the registry, but not written to DUT flash).
std::vector<endorse_cert_response_t> certs_for_dut;
for (size_t i = 0; i < num_tbs_certs; ++i) {
if (std::string_view(pa_endorsed_certs[i].key_label,
pa_endorsed_certs[i].key_label_size) != "PQ_UDS_87") {
certs_for_dut.push_back(pa_endorsed_certs[i]);
}
}
perso_blob_t perso_blob_from_ate = {0};
constexpr size_t kNumPersoBlobMaxNumSpiFrames = 1200;
std::unique_ptr<dut_spi_frame_t[]> perso_blob_from_ate_spi_frames(
new dut_spi_frame_t[kNumPersoBlobMaxNumSpiFrames]);
size_t num_perso_blob_spi_frames = kNumPersoBlobMaxNumSpiFrames;
if (PackPersoBlob(num_tbs_certs, pa_endorsed_certs, num_ca_certs, ca_certs,
&perso_blob_from_ate) != 0) {
if (PackPersoBlob(certs_for_dut.size(), certs_for_dut.data(), num_ca_certs,
ca_certs, &perso_blob_from_ate) != 0) {
LOG(ERROR) << "Failed to repack the perso blob.";
return -1;
}
Expand Down
12 changes: 2 additions & 10 deletions src/ate/testutils/dututils.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,17 +243,14 @@ func (d *Dut) ExpectedExtCerts(mldsa bool) (int, error) {

consumed := numDiceCerts
if mldsa && skuSupportsMldsa {
consumed += 1 // UDS_MLDSA
consumed += 2 // PQ_UDS_44 and PQ_UDS_87
}

if d.skuConfig.CertCountX509 < consumed {
return 0, fmt.Errorf("expected at least %d X.509 certificates, got %d", consumed, d.skuConfig.CertCountX509)
}

remaining := d.skuConfig.CertCountX509 - consumed
if mldsa && skuSupportsMldsa {
return remaining / 2, nil
}
return remaining, nil
}
return 0, nil
Expand All @@ -266,7 +263,7 @@ func (d *Dut) BuildTbsCerts(mldsa bool) error {
// Generate TBS certificates for the DUT. This requires accessing the HSM.
certLabels := []string{"UDS"}
if mldsa && skuSupportsMldsa {
certLabels = append(certLabels, "UDS_MLDSA")
certLabels = append(certLabels, "PQ_UDS_44", "PQ_UDS_87")
}

numExtCerts, err := d.ExpectedExtCerts(mldsa)
Expand All @@ -277,11 +274,6 @@ func (d *Dut) BuildTbsCerts(mldsa bool) error {
for i := 0; i < numExtCerts; i++ {
certLabels = append(certLabels, fmt.Sprintf("EXT_%d", i))
}
if mldsa && skuSupportsMldsa {
for i := 0; i < numExtCerts; i++ {
certLabels = append(certLabels, fmt.Sprintf("EXT_MLDSA_%d", i))
}
}

tbsCerts, privKeys, err := tbsgen.BuildTestTBSCerts(d.skuMgr, d.skuName, certLabels)
if err != nil {
Expand Down
13 changes: 8 additions & 5 deletions src/pa/loadtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ func buildCaSubjectKeysJSON(keys [][]byte) ([]byte, error) {
for i, b := range keys[1] {
caKeys.ExtAuthKeyKeyId[i] = uint32(b)
}
if len(keys) >= 3 {
caKeys.DiceMldsaAuthKeyKeyId = make([]uint32, 20)
for i, b := range keys[2] {
caKeys.DiceMldsaAuthKeyKeyId[i] = uint32(b)
}
}
return json.Marshal(caKeys)
}

Expand Down Expand Up @@ -256,7 +262,7 @@ func processDut(ctx context.Context, c *clientTask, skuName string, dut *dututil
// Retrieve CA subject key IDs.
subjectKeyLabels := []string{"UDS", "EXT"}
if *enableMLDSADice && dut.SupportsMLDSA() {
subjectKeyLabels = append(subjectKeyLabels, "UDS_MLDSA", "EXT_MLDSA")
subjectKeyLabels = append(subjectKeyLabels, "PQ_UDS_44", "PQ_UDS_87")
}
caKeysReq := &pbp.GetCaSubjectKeysRequest{
Sku: skuName,
Expand Down Expand Up @@ -300,7 +306,7 @@ func processDut(ctx context.Context, c *clientTask, skuName string, dut *dututil
Bundles: []*pbp.EndorseCertBundle{},
}
for _, tbsCert := range persoBlob.X509TbsCerts {
if strings.Contains(tbsCert.KeyLabel, "MLDSA") {
if tbsCert.KeyLabel == "PQ_UDS_44" || tbsCert.KeyLabel == "PQ_UDS_87" {
// Sign with MLDSA
endorseReq.Bundles = append(endorseReq.Bundles, &pbp.EndorseCertBundle{
KeyParams: &pbc.SigningKeyParams{
Expand Down Expand Up @@ -352,9 +358,6 @@ func processDut(ctx context.Context, c *clientTask, skuName string, dut *dututil
if *enableMLDSADice && dut.SupportsMLDSA() {
caCertLabels = append(caCertLabels, "root_mldsa")
caCertLabels = append(caCertLabels, "dice_mldsa")
if skuName != "sival_pqc" {
caCertLabels = append(caCertLabels, "ext_mldsa")
}
}
caCertsReq := &pbp.GetCaCertsRequest{
Sku: skuName,
Expand Down
37 changes: 6 additions & 31 deletions src/spm/services/spm.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,12 +401,12 @@ func (s *server) GetCaSubjectKeys(ctx context.Context, request *pbp.GetCaSubject
var kl string
if label == "UDS" {
kl = "SigningKey/Dice/v0"
} else if label == "UDS_MLDSA" {
} else if label == "PQ_UDS_44" || label == "PQ_UDS_87" {
kl = "SigningKey/Dice/Mldsa/v0"
} else if label == "EXT" {
kl = "SigningKey/Ext/v0"
} else {
kl = "SigningKey/Ext/Mldsa/v0"
return nil, status.Errorf(codes.InvalidArgument, "unsupported certificate label %q", label)
}

cert, ok := sku.Certs[kl]
Expand Down Expand Up @@ -442,8 +442,6 @@ func (s *server) GetCaCerts(ctx context.Context, request *pbp.GetCaCertsRequest)
kl = "SigningKey/Dice/Mldsa/v0"
} else if label == "ext" {
kl = "SigningKey/Ext/v0"
} else if label == "ext_mldsa" {
kl = "SigningKey/Ext/Mldsa/v0"
} else if label == "root" {
kl = "RootCA"
} else if label == "root_mldsa" {
Expand Down Expand Up @@ -529,16 +527,10 @@ func (s *server) EndorseCerts(ctx context.Context, request *pbp.EndorseCertsRequ

var kl string
if bundle.KeyParams.KeyLabel == "UDS" {
switch bundle.KeyParams.Key.(type) {
case *pbc.SigningKeyParams_MldsaParams:
kl = "SigningKey/Dice/Mldsa/v0"
default:
kl = "SigningKey/Dice/v0"
}
} else if bundle.KeyParams.KeyLabel == "UDS_MLDSA" {
kl = "SigningKey/Dice/v0"
} else if bundle.KeyParams.KeyLabel == "PQ_UDS_44" ||
bundle.KeyParams.KeyLabel == "PQ_UDS_87" {
kl = "SigningKey/Dice/Mldsa/v0"
} else if strings.HasPrefix(bundle.KeyParams.KeyLabel, "EXT_MLDSA") {
kl = "SigningKey/Ext/Mldsa/v0"
} else {
kl = "SigningKey/Ext/v0"
}
Expand Down Expand Up @@ -725,9 +717,6 @@ func (s *server) VerifyDeviceData(ctx context.Context, request *pbs.VerifyDevice
if ok {
extIntermediates.AddCert(extICA)
}
if extMldsaICA, ok := sku.Certs["SigningKey/Ext/Mldsa/v0"]; ok {
extIntermediates.AddCert(extMldsaICA)
}

certChainDiceLeaf, err := sku.Config.GetUnsafeAttribute(skucfg.AttrNameCertChainDiceLeaf)
if err != nil {
Expand Down Expand Up @@ -772,7 +761,7 @@ func (s *server) VerifyDeviceData(ctx context.Context, request *pbs.VerifyDevice
} else {
diceIntermediates.AddCert(certObj)
}
case "UDS_MLDSA":
case "PQ_UDS_44", "PQ_UDS_87":
diceCerts = append(diceCerts, certObj)
case "CDI_0":
if certChainDiceLeaf == "CDI_0" {
Expand All @@ -798,20 +787,6 @@ func (s *server) VerifyDeviceData(ctx context.Context, request *pbs.VerifyDevice
// Verify the EXT certificate chains.
if len(extCerts) > 0 {
for i, ext := range extCerts {
// Only verify if the signature algorithm is supported by Go's x509 library.
// MLDSA certificates will have an UnknownSignatureAlgorithm.
if ext.SignatureAlgorithm == x509.UnknownSignatureAlgorithm {
// For MLDSA, we verify the signature using the HSM.
// We assume the issuer is the MLDSA EXT CA.
keyLabel, err := sku.Config.GetUnsafeAttribute("SigningKey/Ext/Mldsa/v0")
if err != nil {
return nil, status.Errorf(codes.Internal, "could not get HSM label for SigningKey/Ext/Mldsa/v0: %v", err)
}
if err := sku.SeHandle.VerifyMLDSASignature(keyLabel, ext.RawTBSCertificate, ext.Signature); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%q MLDSA certificate verification failed: %v", extNames[i], err)
}
continue
}
_, err := ext.Verify(x509.VerifyOptions{
Roots: roots,
Intermediates: extIntermediates,
Expand Down
79 changes: 48 additions & 31 deletions src/spm/services/testutils/tbsgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package tbsgen
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/mldsa"
"crypto/rand"
"crypto/sha1"
"crypto/x509"
Expand Down Expand Up @@ -47,28 +48,6 @@ type validityStruct struct {
NotBefore, NotAfter asn1.RawValue
}

// PatchTBSAlg patches the TBS certificate bytes to replace the ECDSA-SHA256 OID
// with MLDSA-87 OID.
func PatchTBSAlg(tbs []byte) ([]byte, error) {
// MLDSA-87 OID: 2.16.840.1.101.3.4.3.19
mldsaOID := asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19}

var parsedTBS tbsCertificate
if _, err := asn1.Unmarshal(tbs, &parsedTBS); err != nil {
return nil, fmt.Errorf("failed to unmarshal TBS: %v", err)
}

// Replace SignatureAlgorithm OID
parsedTBS.SignatureAlgorithm.Algorithm = mldsaOID
parsedTBS.SignatureAlgorithm.Parameters = asn1.RawValue{Tag: 0} // NULL or omitted? MLDSA usually omits parameters.
// Actually, let's just set the OID.
parsedTBS.SignatureAlgorithm = pkix.AlgorithmIdentifier{
Algorithm: mldsaOID,
}

parsedTBS.Raw = nil
return asn1.Marshal(parsedTBS)
}

// GenerateTBS generates a To-Be-Signed (TBS) certificate from a CSR.
func GenerateTBS(csr *x509.CertificateRequest, caCert *x509.Certificate, days int, isMldsa bool) ([]byte, error) {
Expand Down Expand Up @@ -203,11 +182,28 @@ func AssembleCertificate(tbsDER []byte, sigBytes []byte) ([]byte, error) {
return asn1.Marshal(cert)
}

type subjectPublicKeyInfo struct {
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}

func generateMLDSASPKI(params mldsa.Parameters, oid asn1.ObjectIdentifier) ([]byte, error) {
priv, err := mldsa.GenerateKey(params)
if err != nil {
return nil, fmt.Errorf("failed to generate ML-DSA key: %w", err)
}
pubBytes := priv.PublicKey().Bytes()
return asn1.Marshal(subjectPublicKeyInfo{
Algorithm: pkix.AlgorithmIdentifier{Algorithm: oid},
PublicKey: asn1.BitString{Bytes: pubBytes, BitLength: len(pubBytes) * 8},
})
}

// buildTestTbsCert creates a To-Be-Signed (TBS) certificate for testing purposes.
// It takes an intermediate CA certificate. It generates a new key pair for the
// subject, creates a certificate, and returns the TBS part of it.
// The private key of the new certificate is also returned.
func buildTestTbsCert(label string, intermediateCACert *x509.Certificate, isMldsa bool) ([]byte, *ecdsa.PrivateKey, error) {
func buildTestTbsCert(certLabel, label string, intermediateCACert *x509.Certificate, isMldsa bool) ([]byte, *ecdsa.PrivateKey, error) {
// Generate a dummy ECDSA key to act as the signer.
// We do this to satisfy x509.CreateCertificate, which doesn't support MLDSA keys.
// The signature generated by this key will be invalid for the real CA, but we only
Expand All @@ -234,7 +230,21 @@ func buildTestTbsCert(label string, intermediateCACert *x509.Certificate, isMlds
}
pubKey := dutKey.PublicKey

spki, err := x509.MarshalPKIXPublicKey(&pubKey)
var spki []byte
if isMldsa {
switch certLabel {
case "PQ_UDS_44":
// ML-DSA-44 OID: 2.16.840.1.101.3.4.3.17
spki, err = generateMLDSASPKI(mldsa.MLDSA44(), asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 17})
case "PQ_UDS_87":
// ML-DSA-87 OID: 2.16.840.1.101.3.4.3.19
spki, err = generateMLDSASPKI(mldsa.MLDSA87(), asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19})
default:
return nil, nil, fmt.Errorf("unsupported ML-DSA certificate label %q", certLabel)
}
} else {
spki, err = x509.MarshalPKIXPublicKey(&pubKey)
}
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -278,9 +288,19 @@ func buildTestTbsCert(label string, intermediateCACert *x509.Certificate, isMlds

tbs := cert.RawTBSCertificate
if isMldsa {
tbs, err = PatchTBSAlg(tbs)
var parsedTBS tbsCertificate
if _, err := asn1.Unmarshal(tbs, &parsedTBS); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal TBS for MLDSA patching: %v", err)
}
parsedTBS.PublicKey = asn1.RawValue{FullBytes: spki}
// Both PQ_UDS_44 and PQ_UDS_87 are signed by the ML-DSA-87 DICE ICA key.
parsedTBS.SignatureAlgorithm = pkix.AlgorithmIdentifier{
Algorithm: asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19},
}
parsedTBS.Raw = nil
tbs, err = asn1.Marshal(parsedTBS)
if err != nil {
return nil, nil, fmt.Errorf("failed to patch TBS for MLDSA: %v", err)
return nil, nil, fmt.Errorf("failed to marshal patched MLDSA TBS: %v", err)
}
}

Expand All @@ -302,12 +322,9 @@ func BuildTestTBSCerts(mgr *skumgr.Manager, skuName string, certLabels []string)
isMldsa := false
if kl == "UDS" {
label = "SigningKey/Dice/v0"
} else if kl == "UDS_MLDSA" {
} else if kl == "PQ_UDS_44" || kl == "PQ_UDS_87" {
label = "SigningKey/Dice/Mldsa/v0"
isMldsa = true
} else if strings.HasPrefix(kl, "EXT_MLDSA_") {
label = "SigningKey/Ext/Mldsa/v0"
isMldsa = true
} else if strings.HasPrefix(kl, "EXT_") {
label = "SigningKey/Ext/v0"
} else {
Expand All @@ -319,7 +336,7 @@ func BuildTestTBSCerts(mgr *skumgr.Manager, skuName string, certLabels []string)
return nil, nil, fmt.Errorf("issuer certificate %q not found for SKU %q", label, skuName)
}

tbs, priv, err := buildTestTbsCert(label, issuerCert, isMldsa)
tbs, priv, err := buildTestTbsCert(kl, label, issuerCert, isMldsa)
if err != nil {
return nil, nil, err
}
Expand Down
Loading