Skip to content

Commit c834adc

Browse files
authored
fix: update key usage error message to make it clear (#169)
Resolves #164 Signed-off-by: Junjie Gao <[email protected]> --------- Signed-off-by: Junjie Gao <[email protected]>
1 parent 3f28a1b commit c834adc

File tree

2 files changed

+106
-16
lines changed

2 files changed

+106
-16
lines changed

x509/cert_validations.go

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,10 @@ import (
2020
"crypto/x509"
2121
"errors"
2222
"fmt"
23+
"strings"
2324
"time"
2425
)
2526

26-
var kuLeafCertBlocked = x509.KeyUsageContentCommitment |
27-
x509.KeyUsageKeyEncipherment |
28-
x509.KeyUsageDataEncipherment |
29-
x509.KeyUsageKeyAgreement |
30-
x509.KeyUsageCertSign |
31-
x509.KeyUsageCRLSign |
32-
x509.KeyUsageEncipherOnly |
33-
x509.KeyUsageDecipherOnly
34-
var kuLeafCertBlockedString = "ContentCommitment, KeyEncipherment, DataEncipherment, KeyAgreement, " +
35-
"CertSign, CRLSign, EncipherOnly, DecipherOnly"
36-
3727
// ValidateCodeSigningCertChain takes an ordered code-signing certificate chain
3828
// and validates issuance from leaf to root
3929
// Validates certificates according to this spec:
@@ -184,10 +174,36 @@ func validateLeafKeyUsage(cert *x509.Certificate) error {
184174
return err
185175
}
186176
if cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
187-
return fmt.Errorf("certificate with subject %q: key usage must have the bit positions for digital signature set", cert.Subject)
177+
return fmt.Errorf("The certificate with subject %q is invalid. The key usage must have the bit positions for \"Digital Signature\" set", cert.Subject)
178+
}
179+
180+
var invalidKeyUsages []string
181+
if cert.KeyUsage&x509.KeyUsageContentCommitment != 0 {
182+
invalidKeyUsages = append(invalidKeyUsages, `"ContentCommitment"`)
183+
}
184+
if cert.KeyUsage&x509.KeyUsageKeyEncipherment != 0 {
185+
invalidKeyUsages = append(invalidKeyUsages, `"KeyEncipherment"`)
186+
}
187+
if cert.KeyUsage&x509.KeyUsageDataEncipherment != 0 {
188+
invalidKeyUsages = append(invalidKeyUsages, `"DataEncipherment"`)
189+
}
190+
if cert.KeyUsage&x509.KeyUsageKeyAgreement != 0 {
191+
invalidKeyUsages = append(invalidKeyUsages, `"KeyAgreement"`)
192+
}
193+
if cert.KeyUsage&x509.KeyUsageCertSign != 0 {
194+
invalidKeyUsages = append(invalidKeyUsages, `"CertSign"`)
195+
}
196+
if cert.KeyUsage&x509.KeyUsageCRLSign != 0 {
197+
invalidKeyUsages = append(invalidKeyUsages, `"CRLSign"`)
198+
}
199+
if cert.KeyUsage&x509.KeyUsageEncipherOnly != 0 {
200+
invalidKeyUsages = append(invalidKeyUsages, `"EncipherOnly"`)
201+
}
202+
if cert.KeyUsage&x509.KeyUsageDecipherOnly != 0 {
203+
invalidKeyUsages = append(invalidKeyUsages, `"DecipherOnly"`)
188204
}
189-
if cert.KeyUsage&kuLeafCertBlocked != 0 {
190-
return fmt.Errorf("certificate with subject %q: key usage must not have the bit positions for %s set", cert.Subject, kuLeafCertBlockedString)
205+
if len(invalidKeyUsages) > 0 {
206+
return fmt.Errorf("The certificate with subject %q is invalid. The key usage must be \"Digital Signature\" only, but found %s", cert.Subject, strings.Join(invalidKeyUsages, ", "))
191207
}
192208
return nil
193209
}

x509/cert_validations_test.go

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ package x509
1515

1616
import (
1717
"crypto/x509"
18+
"crypto/x509/pkix"
1819
_ "embed"
20+
"encoding/asn1"
1921
"testing"
2022
"time"
2123

@@ -510,7 +512,7 @@ var kuNoDigitalSignatureLeaf = parseCertificateFromString(kuNoDigitalSignatureLe
510512

511513
func TestFailKuNoDigitalSignatureLeaf(t *testing.T) {
512514
err := validateLeafCertificate(kuNoDigitalSignatureLeaf, x509.ExtKeyUsageCodeSigning)
513-
assertErrorEqual("certificate with subject \"CN=Hello\": key usage must have the bit positions for digital signature set", err, t)
515+
assertErrorEqual("The certificate with subject \"CN=Hello\" is invalid. The key usage must have the bit positions for \"Digital Signature\" set", err, t)
514516
}
515517

516518
var kuWrongValuesLeafPem = "-----BEGIN CERTIFICATE-----\n" +
@@ -534,7 +536,7 @@ var kuWrongValuesLeaf = parseCertificateFromString(kuWrongValuesLeafPem)
534536

535537
func TestFailKuWrongValuesLeaf(t *testing.T) {
536538
err := validateLeafCertificate(kuWrongValuesLeaf, x509.ExtKeyUsageCodeSigning)
537-
assertErrorEqual("certificate with subject \"CN=Hello\": key usage must not have the bit positions for ContentCommitment, KeyEncipherment, DataEncipherment, KeyAgreement, CertSign, CRLSign, EncipherOnly, DecipherOnly set", err, t)
539+
assertErrorEqual("The certificate with subject \"CN=Hello\" is invalid. The key usage must be \"Digital Signature\" only, but found \"CertSign\", \"CRLSign\"", err, t)
538540
}
539541

540542
var rsaKeyTooSmallLeafPem = "-----BEGIN CERTIFICATE-----\n" +
@@ -699,3 +701,75 @@ func assertErrorEqual(expected string, err error, t *testing.T) {
699701
t.Fatalf("Expected error \"%v\" but was \"%v\"", expected, err)
700702
}
701703
}
704+
705+
func TestValidateLeafKeyUsage(t *testing.T) {
706+
extensions := []pkix.Extension{{
707+
Id: asn1.ObjectIdentifier{2, 5, 29, 15}, // OID for KeyUsage
708+
Critical: true,
709+
}}
710+
711+
tests := []struct {
712+
name string
713+
cert *x509.Certificate
714+
expectedErrMsg string
715+
}{
716+
{
717+
name: "Valid DigitalSignature usage",
718+
cert: &x509.Certificate{
719+
Subject: pkix.Name{CommonName: "Test CN"},
720+
KeyUsage: x509.KeyUsageDigitalSignature,
721+
Extensions: extensions,
722+
},
723+
expectedErrMsg: "",
724+
},
725+
{
726+
name: "Valid ContentCommitment usage",
727+
cert: &x509.Certificate{
728+
Subject: pkix.Name{CommonName: "Test CN"},
729+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageContentCommitment,
730+
Extensions: extensions,
731+
},
732+
expectedErrMsg: "The certificate with subject \"CN=Test CN\" is invalid. The key usage must be \"Digital Signature\" only, but found \"ContentCommitment\"",
733+
},
734+
{
735+
name: "Missing DigitalSignature usage",
736+
cert: &x509.Certificate{
737+
Subject: pkix.Name{CommonName: "Test CN"},
738+
KeyUsage: x509.KeyUsageCertSign,
739+
Extensions: extensions,
740+
},
741+
expectedErrMsg: "The certificate with subject \"CN=Test CN\" is invalid. The key usage must have the bit positions for \"Digital Signature\" set",
742+
},
743+
{
744+
name: "Invalid KeyEncipherment usage",
745+
cert: &x509.Certificate{
746+
Subject: pkix.Name{CommonName: "Test CN"},
747+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
748+
Extensions: extensions,
749+
},
750+
expectedErrMsg: "The certificate with subject \"CN=Test CN\" is invalid. The key usage must be \"Digital Signature\" only, but found \"KeyEncipherment\"",
751+
},
752+
{
753+
name: "Multiple Invalid usages",
754+
cert: &x509.Certificate{
755+
Subject: pkix.Name{CommonName: "Test CN"},
756+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageEncipherOnly | x509.KeyUsageDecipherOnly | x509.KeyUsageEncipherOnly | x509.KeyUsageDecipherOnly,
757+
Extensions: extensions,
758+
},
759+
expectedErrMsg: "The certificate with subject \"CN=Test CN\" is invalid. The key usage must be \"Digital Signature\" only, but found \"KeyEncipherment\", \"DataEncipherment\", \"KeyAgreement\", \"CertSign\", \"CRLSign\", \"EncipherOnly\", \"DecipherOnly\"",
760+
},
761+
}
762+
763+
for _, tt := range tests {
764+
t.Run(tt.name, func(t *testing.T) {
765+
err := validateLeafKeyUsage(tt.cert)
766+
if err != nil && tt.expectedErrMsg == "" {
767+
t.Fatalf("expected no error, but got: %s", err)
768+
} else if err == nil && tt.expectedErrMsg != "" {
769+
t.Fatalf("expected error %q, but got none", tt.expectedErrMsg)
770+
} else if err != nil && err.Error() != tt.expectedErrMsg {
771+
t.Fatalf("expected error %q, but got: %s", tt.expectedErrMsg, err)
772+
}
773+
})
774+
}
775+
}

0 commit comments

Comments
 (0)