aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/x509/boring_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/x509/boring_test.go')
-rw-r--r--src/crypto/x509/boring_test.go138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/crypto/x509/boring_test.go b/src/crypto/x509/boring_test.go
new file mode 100644
index 0000000000..7010f44b32
--- /dev/null
+++ b/src/crypto/x509/boring_test.go
@@ -0,0 +1,138 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package x509
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/internal/boring/fipstls"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509/pkix"
+ "fmt"
+ "math/big"
+ "strings"
+ "testing"
+ "time"
+)
+
+const (
+ boringCertCA = iota
+ boringCertLeaf
+ boringCertFIPSOK = 0x80
+)
+
+func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
+ k, err := rsa.GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
+ k, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+type boringCertificate struct {
+ name string
+ org string
+ parentOrg string
+ der []byte
+ cert *Certificate
+ key interface{}
+ fipsOK bool
+}
+
+func TestBoringAllowCert(t *testing.T) {
+ R1 := testBoringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
+ R2 := testBoringCert(t, "R2", boringRSAKey(t, 4096), nil, boringCertCA)
+
+ M1_R1 := testBoringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
+ M2_R1 := testBoringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
+
+ I_R1 := testBoringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
+
+ testBoringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
+ testBoringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
+}
+
+func testBoringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
+ org := name
+ parentOrg := ""
+ if i := strings.Index(org, "_"); i >= 0 {
+ org = org[:i]
+ parentOrg = name[i+1:]
+ }
+ tmpl := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ Organization: []string{org},
+ },
+ NotBefore: time.Unix(0, 0),
+ NotAfter: time.Unix(0, 0),
+
+ KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
+ BasicConstraintsValid: true,
+ }
+ if mode&^boringCertFIPSOK == boringCertLeaf {
+ tmpl.DNSNames = []string{"example.com"}
+ } else {
+ tmpl.IsCA = true
+ tmpl.KeyUsage |= KeyUsageCertSign
+ }
+
+ var pcert *Certificate
+ var pkey interface{}
+ if parent != nil {
+ pcert = parent.cert
+ pkey = parent.key
+ } else {
+ pcert = tmpl
+ pkey = key
+ }
+
+ var pub interface{}
+ var desc string
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ pub = &k.PublicKey
+ desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
+ case *ecdsa.PrivateKey:
+ pub = &k.PublicKey
+ desc = "ECDSA-" + k.Curve.Params().Name
+ default:
+ t.Fatalf("invalid key %T", key)
+ }
+
+ der, err := CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := ParseCertificate(der)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Tell isBoringCertificate to enforce FIPS restrictions for this check.
+ fipstls.Force()
+ defer fipstls.Abandon()
+
+ fipsOK := mode&boringCertFIPSOK != 0
+ if boringAllowCert(cert) != fipsOK {
+ t.Errorf("boringAllowCert(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
+ }
+ return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
+}