Skip to content
Open
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
41 changes: 23 additions & 18 deletions coordinator/internal/attestation/mda.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,26 +202,31 @@ func VerifyMDACertChain(certChainPEM []byte, appleRootCA *x509.Certificate) (*MD

result := &MDAResult{}

// When a root CA is provided, verify the certificate chain.
// When nil, skip chain verification and just parse OIDs.
if appleRootCA != nil {
roots := x509.NewCertPool()
roots.AddCert(appleRootCA)

intPool := x509.NewCertPool()
for _, ic := range intermediatesCerts {
intPool.AddCert(ic)
}
// A nil root means no trust anchor is available — return a parsed-only
// result with Valid=false so callers cannot accidentally treat unverified
// chains as trusted.
if appleRootCA == nil {
result.Error = "no root CA provided; chain verification skipped"
result.DeviceSerial = leaf.Subject.SerialNumber
return result, nil
}

opts := x509.VerifyOptions{
Roots: roots,
Intermediates: intPool,
}
roots := x509.NewCertPool()
roots.AddCert(appleRootCA)

if _, err := leaf.Verify(opts); err != nil {
result.Error = fmt.Sprintf("certificate chain verification failed: %v", err)
return result, nil
}
intPool := x509.NewCertPool()
for _, ic := range intermediatesCerts {
intPool.AddCert(ic)
}

opts := x509.VerifyOptions{
Roots: roots,
Intermediates: intPool,
}

if _, err := leaf.Verify(opts); err != nil {
result.Error = fmt.Sprintf("certificate chain verification failed: %v", err)
return result, nil
}

result.Valid = true
Expand Down
18 changes: 6 additions & 12 deletions coordinator/internal/attestation/mda_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,26 +221,20 @@ func TestVerifyMDACertChainWrongRoot(t *testing.T) {
}

func TestVerifyMDACertChainNilRoot(t *testing.T) {
// Without a root CA, the function should still parse OIDs but skip chain verification.
// Without a root CA no trust anchor is available; the result must be
// invalid so callers cannot treat an unverified chain as trusted.
certPEM, _ := createTestMDACert(t, false, true, true)

result, err := VerifyMDACertChain(certPEM, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

if !result.Valid {
t.Fatalf("expected valid result without root CA, got error: %s", result.Error)
}

if result.SIPEnabled {
t.Error("expected SIPEnabled = false")
}
if !result.SecureBootEnabled {
t.Error("expected SecureBootEnabled = true")
if result.Valid {
t.Fatal("expected Valid=false when no root CA is provided")
}
if !result.ThirdPartyKexts {
t.Error("expected ThirdPartyKexts = true")
if result.Error == "" {
t.Error("expected a non-empty Error explaining why validation was skipped")
}
}

Expand Down
Loading