Source file src/crypto/x509/boring_test.go

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build boringcrypto
     6  
     7  package x509
     8  
     9  import (
    10  	"crypto/ecdsa"
    11  	"crypto/elliptic"
    12  	"crypto/internal/boring/fipstls"
    13  	"crypto/rand"
    14  	"crypto/rsa"
    15  	"crypto/x509/pkix"
    16  	"fmt"
    17  	"math/big"
    18  	"strings"
    19  	"testing"
    20  	"time"
    21  )
    22  
    23  const (
    24  	boringCertCA = iota
    25  	boringCertLeaf
    26  	boringCertFIPSOK = 0x80
    27  )
    28  
    29  func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
    30  	t.Helper()
    31  	k, err := rsa.GenerateKey(rand.Reader, size)
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	return k
    36  }
    37  
    38  func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
    39  	t.Helper()
    40  	k, err := ecdsa.GenerateKey(curve, rand.Reader)
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  	return k
    45  }
    46  
    47  type boringCertificate struct {
    48  	name      string
    49  	org       string
    50  	parentOrg string
    51  	der       []byte
    52  	cert      *Certificate
    53  	key       interface{}
    54  	fipsOK    bool
    55  }
    56  
    57  func TestBoringAllowCert(t *testing.T) {
    58  	R1 := testBoringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
    59  	R2 := testBoringCert(t, "R2", boringRSAKey(t, 512), nil, boringCertCA)
    60  	R3 := testBoringCert(t, "R3", boringRSAKey(t, 4096), nil, boringCertCA|boringCertFIPSOK)
    61  
    62  	M1_R1 := testBoringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
    63  	M2_R1 := testBoringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
    64  
    65  	I_R1 := testBoringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
    66  	testBoringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
    67  	testBoringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
    68  	testBoringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
    69  
    70  	I_R3 := testBoringCert(t, "I_R3", boringRSAKey(t, 3072), R3, boringCertCA|boringCertFIPSOK)
    71  	testBoringCert(t, "I_R3", I_R3.key, R3, boringCertCA|boringCertFIPSOK)
    72  
    73  	testBoringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
    74  	testBoringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
    75  }
    76  
    77  func testBoringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
    78  	org := name
    79  	parentOrg := ""
    80  	if i := strings.Index(org, "_"); i >= 0 {
    81  		org = org[:i]
    82  		parentOrg = name[i+1:]
    83  	}
    84  	tmpl := &Certificate{
    85  		SerialNumber: big.NewInt(1),
    86  		Subject: pkix.Name{
    87  			Organization: []string{org},
    88  		},
    89  		NotBefore: time.Unix(0, 0),
    90  		NotAfter:  time.Unix(0, 0),
    91  
    92  		KeyUsage:              KeyUsageKeyEncipherment | KeyUsageDigitalSignature,
    93  		ExtKeyUsage:           []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
    94  		BasicConstraintsValid: true,
    95  	}
    96  	if mode&^boringCertFIPSOK == boringCertLeaf {
    97  		tmpl.DNSNames = []string{"example.com"}
    98  	} else {
    99  		tmpl.IsCA = true
   100  		tmpl.KeyUsage |= KeyUsageCertSign
   101  	}
   102  
   103  	var pcert *Certificate
   104  	var pkey interface{}
   105  	if parent != nil {
   106  		pcert = parent.cert
   107  		pkey = parent.key
   108  	} else {
   109  		pcert = tmpl
   110  		pkey = key
   111  	}
   112  
   113  	var pub interface{}
   114  	var desc string
   115  	switch k := key.(type) {
   116  	case *rsa.PrivateKey:
   117  		pub = &k.PublicKey
   118  		desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
   119  	case *ecdsa.PrivateKey:
   120  		pub = &k.PublicKey
   121  		desc = "ECDSA-" + k.Curve.Params().Name
   122  	default:
   123  		t.Fatalf("invalid key %T", key)
   124  	}
   125  
   126  	der, err := CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	cert, err := ParseCertificate(der)
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  
   135  	// Tell isBoringCertificate to enforce FIPS restrictions for this check.
   136  	fipstls.Force()
   137  	defer fipstls.Abandon()
   138  
   139  	fipsOK := mode&boringCertFIPSOK != 0
   140  	if boringAllowCert(cert) != fipsOK {
   141  		t.Errorf("boringAllowCert(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
   142  	}
   143  	return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
   144  }
   145  

View as plain text