diff --git a/testing/certutil/certutil.go b/testing/certutil/certutil.go index 030a5be..b2495dd 100644 --- a/testing/certutil/certutil.go +++ b/testing/certutil/certutil.go @@ -24,6 +24,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" + "crypto/sha256" "crypto/tls" "crypto/x509" "crypto/x509/pkix" @@ -349,6 +350,7 @@ func newRootCert(priv crypto.PrivateKey, pub crypto.PublicKey, opts ...Option) ( KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, IsCA: true, + SubjectKeyId: generateSubjectKeyID(pub), } rootCertRawBytes, err := x509.CreateCertificate( @@ -406,6 +408,23 @@ func getCgf(opts []Option) configs { return cfg } +func generateSubjectKeyID(pub crypto.PublicKey) []byte { + // SubjectKeyId generated using method 1 in RFC 7093, Section 2: + // 1) The keyIdentifier is composed of the leftmost 160-bits of the + // SHA-256 hash of the value of the BIT STRING subjectPublicKey + // (excluding the tag, length, and number of unused bits). + var publicKeyBytes []byte + switch publicKey := pub.(type) { + case *rsa.PublicKey: + publicKeyBytes = x509.MarshalPKCS1PublicKey(publicKey) + case *ecdsa.PublicKey: + //nolint:staticcheck // no alternative + publicKeyBytes = elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y) + } + h := sha256.Sum256(publicKeyBytes) + return h[:20] +} + // defaultChildCert generates a child certificate for localhost and 127.0.0.1. // It returns the certificate and its key as a Pair and an error if any happens. func defaultChildCert( diff --git a/transport/httpcommon/diag_test.go b/transport/httpcommon/diag_test.go index 767ebe8..a5e07c1 100644 --- a/transport/httpcommon/diag_test.go +++ b/transport/httpcommon/diag_test.go @@ -21,6 +21,7 @@ import ( "context" "crypto/rand" "crypto/rsa" + "crypto/sha256" "crypto/tls" "crypto/x509" "crypto/x509/pkix" @@ -313,6 +314,8 @@ func genCA(t *testing.T) tls.Certificate { caKey, err := rsa.GenerateKey(rand.Reader, 2048) // less secure key for quicker testing. require.NoError(t, err) + ca.SubjectKeyId = generateSubjectKeyID(&caKey.PublicKey) + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caKey.PublicKey, caKey) require.NoError(t, err) @@ -378,6 +381,10 @@ func genSignedCert( certKey, err := rsa.GenerateKey(rand.Reader, 2048) require.NoError(t, err) + if isCA { + cert.SubjectKeyId = generateSubjectKeyID(&certKey.PublicKey) + } + certBytes, err := x509.CreateCertificate( rand.Reader, cert, @@ -401,3 +408,13 @@ func serial() *big.Int { ser = ser + 1 return big.NewInt(ser) } + +func generateSubjectKeyID(publicKey *rsa.PublicKey) []byte { + // SubjectKeyId generated using method 1 in RFC 7093, Section 2: + // 1) The keyIdentifier is composed of the leftmost 160-bits of the + // SHA-256 hash of the value of the BIT STRING subjectPublicKey + // (excluding the tag, length, and number of unused bits). + publicKeyBytes := x509.MarshalPKCS1PublicKey(publicKey) + h := sha256.Sum256(publicKeyBytes) + return h[:20] +} diff --git a/transport/tlscommon/ca_pinning_test.go b/transport/tlscommon/ca_pinning_test.go index cdd63ac..e1f44ef 100644 --- a/transport/tlscommon/ca_pinning_test.go +++ b/transport/tlscommon/ca_pinning_test.go @@ -22,6 +22,7 @@ import ( "context" "crypto/rand" "crypto/rsa" + "crypto/sha256" "crypto/tls" "crypto/x509" "crypto/x509/pkix" @@ -335,6 +336,8 @@ func genCA() (tls.Certificate, error) { return tls.Certificate{}, fmt.Errorf("fail to generate RSA key: %w", err) } + ca.SubjectKeyId = generateSubjectKeyID(&caKey.PublicKey) + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caKey.PublicKey, caKey) if err != nil { return tls.Certificate{}, fmt.Errorf("fail to create certificate: %w", err) @@ -404,6 +407,10 @@ func genSignedCert( return tls.Certificate{}, fmt.Errorf("fail to generate RSA key: %w", err) } + if isCA { + cert.SubjectKeyId = generateSubjectKeyID(&certKey.PublicKey) + } + certBytes, err := x509.CreateCertificate( rand.Reader, cert, @@ -432,3 +439,13 @@ func serial() *big.Int { ser = ser + 1 return big.NewInt(ser) } + +func generateSubjectKeyID(publicKey *rsa.PublicKey) []byte { + // SubjectKeyId generated using method 1 in RFC 7093, Section 2: + // 1) The keyIdentifier is composed of the leftmost 160-bits of the + // SHA-256 hash of the value of the BIT STRING subjectPublicKey + // (excluding the tag, length, and number of unused bits). + publicKeyBytes := x509.MarshalPKCS1PublicKey(publicKey) + h := sha256.Sum256(publicKeyBytes) + return h[:20] +}