aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/x509
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2020-12-14 10:03:05 -0500
committerKatie Hockman <katie@golang.org>2020-12-14 10:06:13 -0500
commit0345ede87ee12698988973884cfc0fd3d499dffd (patch)
tree7123cff141ee5661208d2f5f437b8f5252ac7f6a /src/crypto/x509
parent4651d6b267818b0e0d128a5443289717c4bb8cbc (diff)
parent0a02371b0576964e81c3b40d328db9a3ef3b031b (diff)
downloadgo-0345ede87ee12698988973884cfc0fd3d499dffd.tar.xz
[dev.fuzz] all: merge master into dev.fuzz
Change-Id: I5d8c8329ccc9d747bd81ade6b1cb7cb8ae2e94b2
Diffstat (limited to 'src/crypto/x509')
-rw-r--r--src/crypto/x509/cert_pool.go179
-rw-r--r--src/crypto/x509/internal/macos/corefoundation.go6
-rw-r--r--src/crypto/x509/internal/macos/corefoundation.s2
-rw-r--r--src/crypto/x509/internal/macos/security.go6
-rw-r--r--src/crypto/x509/internal/macos/security.s2
-rw-r--r--src/crypto/x509/name_constraints_test.go15
-rw-r--r--src/crypto/x509/pem_decrypt.go35
-rw-r--r--src/crypto/x509/root.go2
-rw-r--r--src/crypto/x509/root_aix.go6
-rw-r--r--src/crypto/x509/root_bsd.go7
-rw-r--r--src/crypto/x509/root_cgo_darwin_amd64.go322
-rw-r--r--src/crypto/x509/root_darwin.go (renamed from src/crypto/x509/root_darwin_amd64.go)4
-rw-r--r--src/crypto/x509/root_darwin_test.go32
-rw-r--r--src/crypto/x509/root_ios.go (renamed from src/crypto/x509/root_darwin_ios.go)218
-rw-r--r--src/crypto/x509/root_ios_gen.go (renamed from src/crypto/x509/root_darwin_ios_gen.go)23
-rw-r--r--src/crypto/x509/root_js.go4
-rw-r--r--src/crypto/x509/root_linux.go8
-rw-r--r--src/crypto/x509/root_omit.go3
-rw-r--r--src/crypto/x509/root_plan9.go3
-rw-r--r--src/crypto/x509/root_solaris.go6
-rw-r--r--src/crypto/x509/root_unix.go39
-rw-r--r--src/crypto/x509/root_unix_test.go20
-rw-r--r--src/crypto/x509/root_windows.go118
-rw-r--r--src/crypto/x509/verify.go22
-rw-r--r--src/crypto/x509/verify_test.go133
-rw-r--r--src/crypto/x509/x509.go593
-rw-r--r--src/crypto/x509/x509_test.go395
27 files changed, 1182 insertions, 1021 deletions
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index 59ec4b6894..bcc5db3b70 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -5,43 +5,89 @@
package x509
import (
+ "bytes"
+ "crypto/sha256"
"encoding/pem"
"errors"
"runtime"
+ "sync"
)
+type sum224 [sha256.Size224]byte
+
// CertPool is a set of certificates.
type CertPool struct {
- bySubjectKeyId map[string][]int
- byName map[string][]int
- certs []*Certificate
+ byName map[string][]int // cert.RawSubject => index into lazyCerts
+
+ // lazyCerts contains funcs that return a certificate,
+ // lazily parsing/decompressing it as needed.
+ lazyCerts []lazyCert
+
+ // haveSum maps from sum224(cert.Raw) to true. It's used only
+ // for AddCert duplicate detection, to avoid CertPool.contains
+ // calls in the AddCert path (because the contains method can
+ // call getCert and otherwise negate savings from lazy getCert
+ // funcs).
+ haveSum map[sum224]bool
+}
+
+// lazyCert is minimal metadata about a Cert and a func to retrieve it
+// in its normal expanded *Certificate form.
+type lazyCert struct {
+ // rawSubject is the Certificate.RawSubject value.
+ // It's the same as the CertPool.byName key, but in []byte
+ // form to make CertPool.Subjects (as used by crypto/tls) do
+ // fewer allocations.
+ rawSubject []byte
+
+ // getCert returns the certificate.
+ //
+ // It is not meant to do network operations or anything else
+ // where a failure is likely; the func is meant to lazily
+ // parse/decompress data that is already known to be good. The
+ // error in the signature primarily is meant for use in the
+ // case where a cert file existed on local disk when the program
+ // started up is deleted later before it's read.
+ getCert func() (*Certificate, error)
}
// NewCertPool returns a new, empty CertPool.
func NewCertPool() *CertPool {
return &CertPool{
- bySubjectKeyId: make(map[string][]int),
- byName: make(map[string][]int),
+ byName: make(map[string][]int),
+ haveSum: make(map[sum224]bool),
}
}
+// len returns the number of certs in the set.
+// A nil set is a valid empty set.
+func (s *CertPool) len() int {
+ if s == nil {
+ return 0
+ }
+ return len(s.lazyCerts)
+}
+
+// cert returns cert index n in s.
+func (s *CertPool) cert(n int) (*Certificate, error) {
+ return s.lazyCerts[n].getCert()
+}
+
func (s *CertPool) copy() *CertPool {
p := &CertPool{
- bySubjectKeyId: make(map[string][]int, len(s.bySubjectKeyId)),
- byName: make(map[string][]int, len(s.byName)),
- certs: make([]*Certificate, len(s.certs)),
- }
- for k, v := range s.bySubjectKeyId {
- indexes := make([]int, len(v))
- copy(indexes, v)
- p.bySubjectKeyId[k] = indexes
+ byName: make(map[string][]int, len(s.byName)),
+ lazyCerts: make([]lazyCert, len(s.lazyCerts)),
+ haveSum: make(map[sum224]bool, len(s.haveSum)),
}
for k, v := range s.byName {
indexes := make([]int, len(v))
copy(indexes, v)
p.byName[k] = indexes
}
- copy(p.certs, s.certs)
+ for k := range s.haveSum {
+ p.haveSum[k] = true
+ }
+ copy(p.lazyCerts, s.lazyCerts)
return p
}
@@ -70,19 +116,44 @@ func SystemCertPool() (*CertPool, error) {
}
// findPotentialParents returns the indexes of certificates in s which might
-// have signed cert. The caller must not modify the returned slice.
-func (s *CertPool) findPotentialParents(cert *Certificate) []int {
+// have signed cert.
+func (s *CertPool) findPotentialParents(cert *Certificate) []*Certificate {
if s == nil {
return nil
}
- var candidates []int
- if len(cert.AuthorityKeyId) > 0 {
- candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ // consider all candidates where cert.Issuer matches cert.Subject.
+ // when picking possible candidates the list is built in the order
+ // of match plausibility as to save cycles in buildChains:
+ // AKID and SKID match
+ // AKID present, SKID missing / AKID missing, SKID present
+ // AKID and SKID don't match
+ var matchingKeyID, oneKeyID, mismatchKeyID []*Certificate
+ for _, c := range s.byName[string(cert.RawIssuer)] {
+ candidate, err := s.cert(c)
+ if err != nil {
+ continue
+ }
+ kidMatch := bytes.Equal(candidate.SubjectKeyId, cert.AuthorityKeyId)
+ switch {
+ case kidMatch:
+ matchingKeyID = append(matchingKeyID, candidate)
+ case (len(candidate.SubjectKeyId) == 0 && len(cert.AuthorityKeyId) > 0) ||
+ (len(candidate.SubjectKeyId) > 0 && len(cert.AuthorityKeyId) == 0):
+ oneKeyID = append(oneKeyID, candidate)
+ default:
+ mismatchKeyID = append(mismatchKeyID, candidate)
+ }
}
- if len(candidates) == 0 {
- candidates = s.byName[string(cert.RawIssuer)]
+
+ found := len(matchingKeyID) + len(oneKeyID) + len(mismatchKeyID)
+ if found == 0 {
+ return nil
}
+ candidates := make([]*Certificate, 0, found)
+ candidates = append(candidates, matchingKeyID...)
+ candidates = append(candidates, oneKeyID...)
+ candidates = append(candidates, mismatchKeyID...)
return candidates
}
@@ -90,15 +161,7 @@ func (s *CertPool) contains(cert *Certificate) bool {
if s == nil {
return false
}
-
- candidates := s.byName[string(cert.RawSubject)]
- for _, c := range candidates {
- if s.certs[c].Equal(cert) {
- return true
- }
- }
-
- return false
+ return s.haveSum[sha256.Sum224(cert.Raw)]
}
// AddCert adds a certificate to a pool.
@@ -106,21 +169,32 @@ func (s *CertPool) AddCert(cert *Certificate) {
if cert == nil {
panic("adding nil Certificate to CertPool")
}
+ s.addCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), func() (*Certificate, error) {
+ return cert, nil
+ })
+}
+
+// addCertFunc adds metadata about a certificate to a pool, along with
+// a func to fetch that certificate later when needed.
+//
+// The rawSubject is Certificate.RawSubject and must be non-empty.
+// The getCert func may be called 0 or more times.
+func (s *CertPool) addCertFunc(rawSum224 sum224, rawSubject string, getCert func() (*Certificate, error)) {
+ if getCert == nil {
+ panic("getCert can't be nil")
+ }
// Check that the certificate isn't being added twice.
- if s.contains(cert) {
+ if s.haveSum[rawSum224] {
return
}
- n := len(s.certs)
- s.certs = append(s.certs, cert)
-
- if len(cert.SubjectKeyId) > 0 {
- keyId := string(cert.SubjectKeyId)
- s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
- }
- name := string(cert.RawSubject)
- s.byName[name] = append(s.byName[name], n)
+ s.haveSum[rawSum224] = true
+ s.lazyCerts = append(s.lazyCerts, lazyCert{
+ rawSubject: []byte(rawSubject),
+ getCert: getCert,
+ })
+ s.byName[rawSubject] = append(s.byName[rawSubject], len(s.lazyCerts)-1)
}
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
@@ -140,24 +214,35 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
continue
}
- cert, err := ParseCertificate(block.Bytes)
+ certBytes := block.Bytes
+ cert, err := ParseCertificate(certBytes)
if err != nil {
continue
}
-
- s.AddCert(cert)
+ var lazyCert struct {
+ sync.Once
+ v *Certificate
+ }
+ s.addCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), func() (*Certificate, error) {
+ lazyCert.Do(func() {
+ // This can't fail, as the same bytes already parsed above.
+ lazyCert.v, _ = ParseCertificate(certBytes)
+ certBytes = nil
+ })
+ return lazyCert.v, nil
+ })
ok = true
}
- return
+ return ok
}
// Subjects returns a list of the DER-encoded subjects of
// all of the certificates in the pool.
func (s *CertPool) Subjects() [][]byte {
- res := make([][]byte, len(s.certs))
- for i, c := range s.certs {
- res[i] = c.RawSubject
+ res := make([][]byte, s.len())
+ for i, lc := range s.lazyCerts {
+ res[i] = lc.rawSubject
}
return res
}
diff --git a/src/crypto/x509/internal/macos/corefoundation.go b/src/crypto/x509/internal/macos/corefoundation.go
index 359694fabf..9b776d4b85 100644
--- a/src/crypto/x509/internal/macos/corefoundation.go
+++ b/src/crypto/x509/internal/macos/corefoundation.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
// Package macOS provides cgo-less wrappers for Core Foundation and
// Security.framework, similarly to how package syscall provides access to
@@ -16,6 +16,10 @@ import (
"unsafe"
)
+// Core Foundation linker flags for the external linker. See Issue 42459.
+//go:cgo_ldflag "-framework"
+//go:cgo_ldflag "CoreFoundation"
+
// CFRef is an opaque reference to a Core Foundation object. It is a pointer,
// but to memory not owned by Go, so not an unsafe.Pointer.
type CFRef uintptr
diff --git a/src/crypto/x509/internal/macos/corefoundation.s b/src/crypto/x509/internal/macos/corefoundation.s
index 8f6be47e4b..a4495d68dd 100644
--- a/src/crypto/x509/internal/macos/corefoundation.s
+++ b/src/crypto/x509/internal/macos/corefoundation.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
#include "textflag.h"
diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go
index 64fe206390..5e39e93666 100644
--- a/src/crypto/x509/internal/macos/security.go
+++ b/src/crypto/x509/internal/macos/security.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
package macOS
@@ -12,6 +12,10 @@ import (
"unsafe"
)
+// Security.framework linker flags for the external linker. See Issue 42459.
+//go:cgo_ldflag "-framework"
+//go:cgo_ldflag "Security"
+
// Based on https://opensource.apple.com/source/Security/Security-59306.41.2/base/Security.h
type SecTrustSettingsResult int32
diff --git a/src/crypto/x509/internal/macos/security.s b/src/crypto/x509/internal/macos/security.s
index 1630c55bab..bd446dbcbe 100644
--- a/src/crypto/x509/internal/macos/security.s
+++ b/src/crypto/x509/internal/macos/security.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,amd64
+// +build darwin,!ios
#include "textflag.h"
diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go
index 5469e28de2..3826c82c38 100644
--- a/src/crypto/x509/name_constraints_test.go
+++ b/src/crypto/x509/name_constraints_test.go
@@ -14,7 +14,6 @@ import (
"encoding/hex"
"encoding/pem"
"fmt"
- "io/ioutil"
"math/big"
"net"
"net/url"
@@ -1941,7 +1940,7 @@ func TestConstraintCases(t *testing.T) {
// Skip tests with CommonName set because OpenSSL will try to match it
// against name constraints, while we ignore it when it's not hostname-looking.
if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
- output, err := testChainAgainstOpenSSL(leafCert, intermediatePool, rootPool)
+ output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
if err == nil && len(test.expectedError) > 0 {
t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i)
if debugOpenSSLFailure {
@@ -1993,7 +1992,7 @@ func TestConstraintCases(t *testing.T) {
pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
return buf.String()
}
- t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.certs[0]))
+ t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.mustCert(t, 0)))
t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert))
}
@@ -2005,7 +2004,7 @@ func TestConstraintCases(t *testing.T) {
}
func writePEMsToTempFile(certs []*Certificate) *os.File {
- file, err := ioutil.TempFile("", "name_constraints_test")
+ file, err := os.CreateTemp("", "name_constraints_test")
if err != nil {
panic("cannot create tempfile")
}
@@ -2019,10 +2018,10 @@ func writePEMsToTempFile(certs []*Certificate) *os.File {
return file
}
-func testChainAgainstOpenSSL(leaf *Certificate, intermediates, roots *CertPool) (string, error) {
+func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
args := []string{"verify", "-no_check_time"}
- rootsFile := writePEMsToTempFile(roots.certs)
+ rootsFile := writePEMsToTempFile(allCerts(t, roots))
if debugOpenSSLFailure {
println("roots file:", rootsFile.Name())
} else {
@@ -2030,8 +2029,8 @@ func testChainAgainstOpenSSL(leaf *Certificate, intermediates, roots *CertPool)
}
args = append(args, "-CAfile", rootsFile.Name())
- if len(intermediates.certs) > 0 {
- intermediatesFile := writePEMsToTempFile(intermediates.certs)
+ if intermediates.len() > 0 {
+ intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
if debugOpenSSLFailure {
println("intermediates file:", intermediatesFile.Name())
} else {
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
index 93d1e4a922..781cb3de83 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -95,7 +95,12 @@ func (c rfc1423Algo) deriveKey(password, salt []byte) []byte {
return out
}
-// IsEncryptedPEMBlock returns if the PEM block is password encrypted.
+// IsEncryptedPEMBlock returns whether the PEM block is password encrypted
+// according to RFC 1423.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
func IsEncryptedPEMBlock(b *pem.Block) bool {
_, ok := b.Headers["DEK-Info"]
return ok
@@ -104,14 +109,18 @@ func IsEncryptedPEMBlock(b *pem.Block) bool {
// IncorrectPasswordError is returned when an incorrect password is detected.
var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
-// DecryptPEMBlock takes a password encrypted PEM block and the password used to
-// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
-// the DEK-Info header to determine the algorithm used for decryption. If no
-// DEK-Info header is present, an error is returned. If an incorrect password
-// is detected an IncorrectPasswordError is returned. Because of deficiencies
-// in the encrypted-PEM format, it's not always possible to detect an incorrect
-// password. In these cases no error will be returned but the decrypted DER
-// bytes will be random noise.
+// DecryptPEMBlock takes a PEM block encrypted according to RFC 1423 and the
+// password used to encrypt it and returns a slice of decrypted DER encoded
+// bytes. It inspects the DEK-Info header to determine the algorithm used for
+// decryption. If no DEK-Info header is present, an error is returned. If an
+// incorrect password is detected an IncorrectPasswordError is returned. Because
+// of deficiencies in the format, it's not always possible to detect an
+// incorrect password. In these cases no error will be returned but the
+// decrypted DER bytes will be random noise.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
dek, ok := b.Headers["DEK-Info"]
if !ok {
@@ -178,8 +187,12 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
}
// EncryptPEMBlock returns a PEM block of the specified type holding the
-// given DER-encoded data encrypted with the specified algorithm and
-// password.
+// given DER encoded data encrypted with the specified algorithm and
+// password according to RFC 1423.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) {
ciph := cipherByKey(alg)
if ciph == nil {
diff --git a/src/crypto/x509/root.go b/src/crypto/x509/root.go
index da5e91b91c..ac92915128 100644
--- a/src/crypto/x509/root.go
+++ b/src/crypto/x509/root.go
@@ -4,7 +4,7 @@
package x509
-//go:generate go run root_darwin_ios_gen.go -version 55161.80.1
+//go:generate go run root_ios_gen.go -version 55161.140.3
import "sync"
diff --git a/src/crypto/x509/root_aix.go b/src/crypto/x509/root_aix.go
index 6d427739a4..4d50a13473 100644
--- a/src/crypto/x509/root_aix.go
+++ b/src/crypto/x509/root_aix.go
@@ -8,3 +8,9 @@ package x509
var certFiles = []string{
"/var/ssl/certs/ca-bundle.crt",
}
+
+// Possible directories with certificate files; stop after successfully
+// reading at least one file from a directory.
+var certDirectories = []string{
+ "/var/ssl/certs",
+}
diff --git a/src/crypto/x509/root_bsd.go b/src/crypto/x509/root_bsd.go
index 1371933891..f04b6bd0d6 100644
--- a/src/crypto/x509/root_bsd.go
+++ b/src/crypto/x509/root_bsd.go
@@ -13,3 +13,10 @@ var certFiles = []string{
"/usr/local/share/certs/ca-root-nss.crt", // DragonFly
"/etc/openssl/certs/ca-certificates.crt", // NetBSD
}
+
+// Possible directories with certificate files; stop after successfully
+// reading at least one file from a directory.
+var certDirectories = []string{
+ "/usr/local/share/certs", // FreeBSD
+ "/etc/openssl/certs", // NetBSD
+}
diff --git a/src/crypto/x509/root_cgo_darwin_amd64.go b/src/crypto/x509/root_cgo_darwin_amd64.go
deleted file mode 100644
index 15c72cc0c8..0000000000
--- a/src/crypto/x509/root_cgo_darwin_amd64.go
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright 2011 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.
-
-// +build !ios
-
-package x509
-
-// This cgo implementation exists only to support side-by-side testing by
-// TestSystemRoots. It can be removed once we are confident in the no-cgo
-// implementation.
-
-/*
-#cgo CFLAGS: -mmacosx-version-min=10.11
-#cgo LDFLAGS: -framework CoreFoundation -framework Security
-
-#include <errno.h>
-#include <sys/sysctl.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-
-static Boolean isSSLPolicy(SecPolicyRef policyRef) {
- if (!policyRef) {
- return false;
- }
- CFDictionaryRef properties = SecPolicyCopyProperties(policyRef);
- if (properties == NULL) {
- return false;
- }
- Boolean isSSL = false;
- CFTypeRef value = NULL;
- if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid, (const void **)&value)) {
- isSSL = CFEqual(value, kSecPolicyAppleSSL);
- }
- CFRelease(properties);
- return isSSL;
-}
-
-// sslTrustSettingsResult obtains the final kSecTrustSettingsResult value
-// for a certificate in the user or admin domain, combining usage constraints
-// for the SSL SecTrustSettingsPolicy, ignoring SecTrustSettingsKeyUsage and
-// kSecTrustSettingsAllowedError.
-// https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting
-static SInt32 sslTrustSettingsResult(SecCertificateRef cert) {
- CFArrayRef trustSettings = NULL;
- OSStatus err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainUser, &trustSettings);
-
- // According to Apple's SecTrustServer.c, "user trust settings overrule admin trust settings",
- // but the rules of the override are unclear. Let's assume admin trust settings are applicable
- // if and only if user trust settings fail to load or are NULL.
- if (err != errSecSuccess || trustSettings == NULL) {
- if (trustSettings != NULL) CFRelease(trustSettings);
- err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainAdmin, &trustSettings);
- }
-
- // > no trust settings [...] means "this certificate must be verified to a known trusted certificate”
- // (Should this cause a fallback from user to admin domain? It's unclear.)
- if (err != errSecSuccess || trustSettings == NULL) {
- if (trustSettings != NULL) CFRelease(trustSettings);
- return kSecTrustSettingsResultUnspecified;
- }
-
- // > An empty trust settings array means "always trust this certificate” with an
- // > overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot.
- if (CFArrayGetCount(trustSettings) == 0) {
- CFRelease(trustSettings);
- return kSecTrustSettingsResultTrustRoot;
- }
-
- // kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
- // but the Go linker's internal linking mode can't handle CFSTR relocations.
- // Create our own dynamic string instead and release it below.
- CFStringRef _kSecTrustSettingsResult = CFStringCreateWithCString(
- NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
- CFStringRef _kSecTrustSettingsPolicy = CFStringCreateWithCString(
- NULL, "kSecTrustSettingsPolicy", kCFStringEncodingUTF8);
- CFStringRef _kSecTrustSettingsPolicyString = CFStringCreateWithCString(
- NULL, "kSecTrustSettingsPolicyString", kCFStringEncodingUTF8);
-
- CFIndex m; SInt32 result = 0;
- for (m = 0; m < CFArrayGetCount(trustSettings); m++) {
- CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, m);
-
- // First, check if this trust setting is constrained to a non-SSL policy.
- SecPolicyRef policyRef;
- if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsPolicy, (const void**)&policyRef)) {
- if (!isSSLPolicy(policyRef)) {
- continue;
- }
- }
-
- if (CFDictionaryContainsKey(tSetting, _kSecTrustSettingsPolicyString)) {
- // Restricted to a hostname, not a root.
- continue;
- }
-
- CFNumberRef cfNum;
- if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsResult, (const void**)&cfNum)) {
- CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
- } else {
- // > If this key is not present, a default value of
- // > kSecTrustSettingsResultTrustRoot is assumed.
- result = kSecTrustSettingsResultTrustRoot;
- }
-
- // If multiple dictionaries match, we are supposed to "OR" them,
- // the semantics of which are not clear. Since TrustRoot and TrustAsRoot
- // are mutually exclusive, Deny should probably override, and Invalid and
- // Unspecified be overridden, approximate this by stopping at the first
- // TrustRoot, TrustAsRoot or Deny.
- if (result == kSecTrustSettingsResultTrustRoot) {
- break;
- } else if (result == kSecTrustSettingsResultTrustAsRoot) {
- break;
- } else if (result == kSecTrustSettingsResultDeny) {
- break;
- }
- }
-
- // If trust settings are present, but none of them match the policy...
- // the docs don't tell us what to do.
- //
- // "Trust settings for a given use apply if any of the dictionaries in the
- // certificate’s trust settings array satisfies the specified use." suggests
- // that it's as if there were no trust settings at all, so we should probably
- // fallback to the admin trust settings. TODO.
- if (result == 0) {
- result = kSecTrustSettingsResultUnspecified;
- }
-
- CFRelease(_kSecTrustSettingsPolicy);
- CFRelease(_kSecTrustSettingsPolicyString);
- CFRelease(_kSecTrustSettingsResult);
- CFRelease(trustSettings);
-
- return result;
-}
-
-// isRootCertificate reports whether Subject and Issuer match.
-static Boolean isRootCertificate(SecCertificateRef cert, CFErrorRef *errRef) {
- CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, errRef);
- if (*errRef != NULL) {
- return false;
- }
- CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, errRef);
- if (*errRef != NULL) {
- CFRelease(subjectName);
- return false;
- }
- Boolean equal = CFEqual(subjectName, issuerName);
- CFRelease(subjectName);
- CFRelease(issuerName);
- return equal;
-}
-
-// CopyPEMRoots fetches the system's list of trusted X.509 root certificates
-// for the kSecTrustSettingsPolicy SSL.
-//
-// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
-// certificates of the system. On failure, the function returns -1.
-// Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots.
-//
-// Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
-// be released (using CFRelease) after we've consumed its content.
-static int CopyPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots, bool debugDarwinRoots) {
- int i;
-
- if (debugDarwinRoots) {
- fprintf(stderr, "crypto/x509: kSecTrustSettingsResultInvalid = %d\n", kSecTrustSettingsResultInvalid);
- fprintf(stderr, "crypto/x509: kSecTrustSettingsResultTrustRoot = %d\n", kSecTrustSettingsResultTrustRoot);
- fprintf(stderr, "crypto/x509: kSecTrustSettingsResultTrustAsRoot = %d\n", kSecTrustSettingsResultTrustAsRoot);
- fprintf(stderr, "crypto/x509: kSecTrustSettingsResultDeny = %d\n", kSecTrustSettingsResultDeny);
- fprintf(stderr, "crypto/x509: kSecTrustSettingsResultUnspecified = %d\n", kSecTrustSettingsResultUnspecified);
- }
-
- // Get certificates from all domains, not just System, this lets
- // the user add CAs to their "login" keychain, and Admins to add
- // to the "System" keychain
- SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
- kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainUser };
-
- int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
- if (pemRoots == NULL || untrustedPemRoots == NULL) {
- return -1;
- }
-
- CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- for (i = 0; i < numDomains; i++) {
- int j;
- CFArrayRef certs = NULL;
- OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
- if (err != noErr) {
- continue;
- }
-
- CFIndex numCerts = CFArrayGetCount(certs);
- for (j = 0; j < numCerts; j++) {
- SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
- if (cert == NULL) {
- continue;
- }
-
- SInt32 result;
- if (domains[i] == kSecTrustSettingsDomainSystem) {
- // Certs found in the system domain are always trusted. If the user
- // configures "Never Trust" on such a cert, it will also be found in the
- // admin or user domain, causing it to be added to untrustedPemRoots. The
- // Go code will then clean this up.
- result = kSecTrustSettingsResultTrustRoot;
- } else {
- result = sslTrustSettingsResult(cert);
- if (debugDarwinRoots) {
- CFErrorRef errRef = NULL;
- CFStringRef summary = SecCertificateCopyShortDescription(NULL, cert, &errRef);
- if (errRef != NULL) {
- fprintf(stderr, "crypto/x509: SecCertificateCopyShortDescription failed\n");
- CFRelease(errRef);
- continue;
- }
-
- CFIndex length = CFStringGetLength(summary);
- CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
- char *buffer = malloc(maxSize);
- if (CFStringGetCString(summary, buffer, maxSize, kCFStringEncodingUTF8)) {
- fprintf(stderr, "crypto/x509: %s returned %d\n", buffer, (int)result);
- }
- free(buffer);
- CFRelease(summary);
- }
- }
-
- CFMutableDataRef appendTo;
- // > Note the distinction between the results kSecTrustSettingsResultTrustRoot
- // > and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to
- // > root (self-signed) certificates; the latter can only be applied to
- // > non-root certificates.
- if (result == kSecTrustSettingsResultTrustRoot) {
- CFErrorRef errRef = NULL;
- if (!isRootCertificate(cert, &errRef) || errRef != NULL) {
- if (errRef != NULL) CFRelease(errRef);
- continue;
- }
-
- appendTo = combinedData;
- } else if (result == kSecTrustSettingsResultTrustAsRoot) {
- CFErrorRef errRef = NULL;
- if (isRootCertificate(cert, &errRef) || errRef != NULL) {
- if (errRef != NULL) CFRelease(errRef);
- continue;
- }
-
- appendTo = combinedData;
- } else if (result == kSecTrustSettingsResultDeny) {
- appendTo = combinedUntrustedData;
- } else if (result == kSecTrustSettingsResultUnspecified) {
- // Certificates with unspecified trust should probably be added to a pool of
- // intermediates for chain building, or checked for transitive trust and
- // added to the root pool (which is an imprecise approximation because it
- // cuts chains short) but we don't support either at the moment. TODO.
- continue;
- } else {
- continue;
- }
-
- CFDataRef data = NULL;
- err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
- if (err != noErr) {
- continue;
- }
- if (data != NULL) {
- CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
- }
- }
- CFRelease(certs);
- }
- *pemRoots = combinedData;
- *untrustedPemRoots = combinedUntrustedData;
- return 0;
-}
-*/
-import "C"
-import (
- "errors"
- "unsafe"
-)
-
-func init() {
- loadSystemRootsWithCgo = _loadSystemRootsWithCgo
-}
-
-func _loadSystemRootsWithCgo() (*CertPool, error) {
- var data, untrustedData C.CFDataRef
- err := C.CopyPEMRoots(&data, &untrustedData, C.bool(debugDarwinRoots))
- if err == -1 {
- return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
- }
- defer C.CFRelease(C.CFTypeRef(data))
- defer C.CFRelease(C.CFTypeRef(untrustedData))
-
- buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
- roots := NewCertPool()
- roots.AppendCertsFromPEM(buf)
-
- if C.CFDataGetLength(untrustedData) == 0 {
- return roots, nil
- }
-
- buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData)))
- untrustedRoots := NewCertPool()
- untrustedRoots.AppendCertsFromPEM(buf)
-
- trustedRoots := NewCertPool()
- for _, c := range roots.certs {
- if !untrustedRoots.contains(c) {
- trustedRoots.AddCert(c)
- }
- }
- return trustedRoots, nil
-}
diff --git a/src/crypto/x509/root_darwin_amd64.go b/src/crypto/x509/root_darwin.go
index ce88de025e..c9ea7e80f3 100644
--- a/src/crypto/x509/root_darwin_amd64.go
+++ b/src/crypto/x509/root_darwin.go
@@ -20,10 +20,6 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return nil, nil
}
-// loadSystemRootsWithCgo is set in root_cgo_darwin_amd64.go when cgo is
-// available, and is only used for testing.
-var loadSystemRootsWithCgo func() (*CertPool, error)
-
func loadSystemRoots() (*CertPool, error) {
var trustedRoots []*Certificate
untrustedRoots := make(map[string]bool)
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index 2c773b9120..ae2bd02bf8 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -24,40 +24,10 @@ func TestSystemRoots(t *testing.T) {
// There are 174 system roots on Catalina, and 163 on iOS right now, require
// at least 100 to make sure this is not completely broken.
- if want, have := 100, len(sysRoots.certs); have < want {
+ if want, have := 100, sysRoots.len(); have < want {
t.Errorf("want at least %d system roots, have %d", want, have)
}
- if loadSystemRootsWithCgo == nil {
- t.Skip("cgo not available, can't compare pool")
- }
-
- t1 := time.Now()
- cgoRoots, err := loadSystemRootsWithCgo() // cgo roots
- cgoSysRootsDuration := time.Since(t1)
-
- if err != nil {
- t.Fatalf("failed to read cgo roots: %v", err)
- }
-
- t.Logf("loadSystemRootsWithCgo: %v", cgoSysRootsDuration)
-
- // Check that the two cert pools are the same.
- sysPool := make(map[string]*Certificate, len(sysRoots.certs))
- for _, c := range sysRoots.certs {
- sysPool[string(c.Raw)] = c
- }
- for _, c := range cgoRoots.certs {
- if _, ok := sysPool[string(c.Raw)]; ok {
- delete(sysPool, string(c.Raw))
- } else {
- t.Errorf("certificate only present in cgo pool: %v", c.Subject)
- }
- }
- for _, c := range sysPool {
- t.Errorf("certificate only present in real pool: %v", c.Subject)
- }
-
if t.Failed() {
cmd := exec.Command("security", "dump-trust-settings")
cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
diff --git a/src/crypto/x509/root_darwin_ios.go b/src/crypto/x509/root_ios.go
index 5ecc4911b3..cb3529d6d5 100644
--- a/src/crypto/x509/root_darwin_ios.go
+++ b/src/crypto/x509/root_ios.go
@@ -1,7 +1,7 @@
-// Code generated by root_darwin_ios_gen.go -version 55161.80.1; DO NOT EDIT.
+// Code generated by root_ios_gen.go -version 55161.140.3; DO NOT EDIT.
// Update the version in root.go and regenerate with "go generate".
-// +build darwin,arm64 darwin,amd64,ios
+// +build ios
// +build !x509omitbundledroots
package x509
@@ -10,9 +10,6 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return nil, nil
}
-// loadSystemRootsWithCgo is not available on iOS.
-var loadSystemRootsWithCgo func() (*CertPool, error)
-
func loadSystemRoots() (*CertPool, error) {
p := NewCertPool()
p.AppendCertsFromPEM([]byte(systemRootsPEM))
@@ -561,33 +558,6 @@ Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961
kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH
CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj
-----END CERTIFICATE-----
-# "ApplicationCA2 Root"
-# 12 6B F0 1C 10 94 D2 F0 CA 2E 35 23 80 B3 C7 24
-# 29 45 46 CC C6 55 97 BE F7 F1 2D 8A 17 1F 19 84
------BEGIN CERTIFICATE-----
-MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG
-A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT
-BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw
-MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw
-YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj
-YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq
-rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo
-+rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN
-dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk
-KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq
-0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa
-2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g
-by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG
-EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo
-qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB
-MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs
-B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL
-nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0
-HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m
-Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i
-Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf
-SUJiOxMfFui61/0=
------END CERTIFICATE-----
# "Atos TrustedRoot 2011"
# F3 56 BE A2 44 B7 A9 1E B3 5D 53 CA 9A D7 86 4A
# CE 01 8E 2D 35 D5 F8 F9 6D DF 68 A6 F4 1A A4 74
@@ -2032,35 +2002,6 @@ nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
-----END CERTIFICATE-----
# "Entrust.net Certification Authority (2048)"
-# D1 C3 39 EA 27 84 EB 87 0F 93 4F C5 63 4E 4A A9
-# AD 55 05 01 64 01 F2 64 65 D3 7A 57 46 63 35 9F
------BEGIN CERTIFICATE-----
-MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
-RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
-bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
-IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
-MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
-LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
-YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
-A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
-K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
-sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
-MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
-XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
-HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
-4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
-vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
-CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
-WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
-oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
-h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
-f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
-B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
-vUxFnmG6v4SBkgPR0ml8xQ==
------END CERTIFICATE-----
-# "Entrust.net Certification Authority (2048)"
# 6D C4 71 72 E0 1C BC B0 BF 62 58 0D 89 5F E2 B8
# AC 9A D4 F8 73 80 1E 0C 10 B9 C8 37 D2 1E B1 77
-----BEGIN CERTIFICATE-----
@@ -2378,22 +2319,6 @@ Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f
-----END CERTIFICATE-----
# "GlobalSign"
-# BE C9 49 11 C2 95 56 76 DB 6C 0A 55 09 86 D7 6E
-# 3B A0 05 66 7C 44 2C 97 62 B4 FB B7 73 DE 22 8C
------BEGIN CERTIFICATE-----
-MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
-MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
-bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
-DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
-QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
-FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
-uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
-kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
-ewv4n4Q=
------END CERTIFICATE-----
-# "GlobalSign"
# 17 9F BC 14 8A 3D D0 0F D2 4E A1 34 58 CC 43 BF
# A7 F5 9C 81 82 D7 83 A5 13 F6 EB EC 10 0C 89 24
-----BEGIN CERTIFICATE-----
@@ -2410,6 +2335,22 @@ KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
xwy8p2Fp8fc74SrL+SvzZpA3
-----END CERTIFICATE-----
+# "GlobalSign"
+# BE C9 49 11 C2 95 56 76 DB 6C 0A 55 09 86 D7 6E
+# 3B A0 05 66 7C 44 2C 97 62 B4 FB B7 73 DE 22 8C
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
+MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
+bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
+DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
+QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
+FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
+uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
+kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
+ewv4n4Q=
+-----END CERTIFICATE-----
# "GlobalSign Root CA"
# EB D4 10 40 E4 BB 3E C7 42 C9 E3 81 D3 1E F2 A4
# 1A 48 B6 68 5C 96 E7 CE F3 C1 DF 6C D4 33 1C 99
@@ -3095,6 +3036,24 @@ ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf
aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
-----END CERTIFICATE-----
+# "OISTE WISeKey Global Root GC CA"
+# 85 60 F9 1C 36 24 DA BA 95 70 B5 FE A0 DB E3 6F
+# F1 1A 83 23 BE 94 86 85 4F B3 F3 4A 55 71 19 8D
+-----BEGIN CERTIFICATE-----
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
+CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
+bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
+Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ
+BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu
+ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS
+b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni
+eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W
+p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T
+rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
+57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
+Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
+-----END CERTIFICATE-----
# "OpenTrust Root CA G1"
# 56 C7 71 28 D9 8C 18 D9 1B 4C FD FF BC 25 EE 91
# 03 D4 75 8E A2 AB AD 82 6A 90 F3 45 7D 46 0E B4
@@ -4113,41 +4072,6 @@ Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
-----END CERTIFICATE-----
-# "SwissSign Gold Root CA - G3"
-# 7A F6 EA 9F 75 3A 1E 70 9B D6 4D 0B EB 86 7C 11
-# E8 C2 95 A5 6E 24 A6 E0 47 14 59 DC CD AA 15 58
------BEGIN CERTIFICATE-----
-MIIFejCCA2KgAwIBAgIJAN7E8kTzHab8MA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV
-BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNVBAMTG1N3aXNzU2ln
-biBHb2xkIFJvb3QgQ0EgLSBHMzAeFw0wOTA4MDQxMzMxNDdaFw0zNzA4MDQxMzMx
-NDdaMEoxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNV
-BAMTG1N3aXNzU2lnbiBHb2xkIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEB
-BQADggIPADCCAgoCggIBAMPon8hlWp1nG8FFl7S0h0NbYWCAnvJ/XvlnRN1E+qu1
-q3f/KhlMzm/Ej0Gf4OLNcuDR1FJhQQkKvwpw++CDaWEpytsimlul5t0XlbBvhI46
-PmRaQfsbWPz9Kz6ypOasyYK8zvaV+Jd37Sb2WK6eJ+IPg+zFNljIe8/Vh6GphxoT
-Z2EBbaZpnOKQ8StoZfPosHz8gj3erdgKAAlEeROc8P5udXvCvLNZAQt8xdUt8L//
-bVfSSYHrtLNQrFv5CxUVjGn/ozkB7fzc3CeXjnuL1Wqm1uAdX80Bkeb1Ipi6LgkY
-OG8TqIHS+yE35y20YueBkLDGeVm3Z3X+vo87+jbsr63ST3Q2AeVXqyMEzEpel89+
-xu+MzJUjaY3LOMcZ9taKABQeND1v2gwLw7qX/BFLUmE+vzNnUxC/eBsJwke6Hq9Y
-9XWBf71W8etW19lpDAfpNzGwEhwy71bZvnorfL3TPbxqM006PFAQhyfHegpnU9t/
-gJvoniP6+Qg6i6GONFpIM19k05eGBxl9iJTOKnzFat+vvKmfzTqmurtU+X+P388O
-WsStmryzOndzg0yTPJBotXxQlRHIgl6UcdBBGPvJxmXszom2ziKzEVs/4J0+Gxho
-DaoDoWdZv2udvPjyZS+aQTpF2F7QNmxvOx5jtI6YTBPbIQ6fe+3qoKpxw+ujoNIl
-AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
-DgQWBBRclwZGNKvfMMV8xQ1VcWYwtWCPnjAfBgNVHSMEGDAWgBRclwZGNKvfMMV8
-xQ1VcWYwtWCPnjANBgkqhkiG9w0BAQsFAAOCAgEAd0tN3uqFSqssJ9ZFx/FfIMFb
-YO0Hy6Iz3DbPx5TxBsfV2s/NrYQ+/xJIf0HopWZXMMQd5KcaLy1Cwe9Gc7LV9Vr9
-Dnpr0sgxow1IlldlY1UYwPzkisyYhlurDIonN/ojaFlcJtehwcK5Tiz/KV7mlAu+
-zXJPleiP9ve4Pl7Oz54RyawDKUiKqbamNLmsQP/EtnM3scd/qVHbSypHX0AkB4gG
-tySz+3/3sIsz+r8jdaNc/qplGsK+8X2BdwOBsY3XlQ16PEKYt4+pfVDh31IGmqBS
-VHiDB2FSCTdeipynxlHRXGPRhNzC29L6Wxg2fWa81CiXL3WWHIQHrIuOUxG+JCGq
-Z/LBrYic07B4Z3j101gDIApdIPG152XMDiDj1d/mLxkrhWjBBCbPj+0FU6HdBw7r
-QSbHtKksW+NpPWbAYhvAqobAN8MxBIZwOb5rXyFAQaB/5dkPOEtwX0n4hbgrLqof
-k0FD+PuydDwfS1dbt9RRoZJKzr4Qou7YFCJ7uUG9jemIqdGPAxpg/z+HiaCZJyJm
-sD5onnKIUTidEz5FbQXlRrVz7UOGsRQKHrzaDb8eJFxmjw6+of3G62m8Q3nXA3b5
-3IeZuJjEzX9tEPkQvixC/pwpTYNrCr21jsRIiv0hB6aAfR+b6au9gmFECnEnX22b
-kJ6u/zYks2gD1pWMa3M=
------END CERTIFICATE-----
# "SwissSign Platinum CA - G2"
# 3B 22 2E 56 67 11 E9 92 30 0D C0 B1 5A B9 47 3D
# AF DE F8 C8 4D 0C EF 7D 33 17 B4 C1 82 1D 14 36
@@ -4184,41 +4108,6 @@ DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x
kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
-----END CERTIFICATE-----
-# "SwissSign Platinum Root CA - G3"
-# 59 B3 82 9F 1F F4 43 34 49 58 FA E8 BF F6 21 B6
-# 84 C8 48 CF BF 7E AD 6B 63 A6 CA 50 F2 79 4F 89
------BEGIN CERTIFICATE-----
-MIIFgTCCA2mgAwIBAgIIIj+pFyDegZQwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UE
-BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEoMCYGA1UEAxMfU3dpc3NTaWdu
-IFBsYXRpbnVtIFJvb3QgQ0EgLSBHMzAeFw0wOTA4MDQxMzM0MDRaFw0zNzA4MDQx
-MzM0MDRaME4xCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKDAm
-BgNVBAMTH1N3aXNzU2lnbiBQbGF0aW51bSBSb290IENBIC0gRzMwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQCUoO8TG59EIBvNxaoiu9nyUj56Wlh35o2h
-K8ncpPPksxOUAGKbHPJDUEOBfq8wNkmsGIkMGEW4PsdUbePYmllriholqba1Dbd9
-I/BffagHqfc+hi7IAU3c5jbtHeU3B2kSS+OD0QQcJPAfcHHnGe1zSG6VKxW2VuYC
-31bpm/rqpu7gwsO64MzGyHvXbzqVmzqPvlss0qmgOD7WiOGxYhOO3KswZ82oaqZj
-K4Kwy8c9Tu1y9n2rMk5lAusPmXT4HBoojA5FAJMsFJ9txxue9orce3jjtJRHHU0F
-bYR6kFSynot1woDfhzk/n/tIVAeNoCn1+WBfWnLou5ugQuAIADSjFTwT49YaawKy
-lCGjnUG8KmtOMzumlDj8PccrM7MuKwZ0rJsQb8VORfddoVYDLA1fer0e3h13kGva
-pS2KTOnfQfTnS+x9lUKfTKkJD0OIPz2T5yv0ekjaaMTdEoAxGl0kVCamJCGzTK3a
-Fwg2AlfGnIZwyXXJnnxh2HjmuegUafkcECgSXUt1ULo80GdwVVVWS/s9HNjbeU2X
-37ie2xcs1TUHuFCp9473Vv96Z0NPINnKZtY4YEvulDHWDaJIm/80aZTGNfWWiO+q
-ZsyBputMU/8ydKe2nZhXtLomqfEzM2J+OrADEVf/3G8RI60+xgrQzFS3LcKTHeXC
-pozH2O9T9wIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zAdBgNVHQ4EFgQUVio/kFj0F1oUstcIG4VbVGpUGigwHwYDVR0jBBgwFoAUVio/
-kFj0F1oUstcIG4VbVGpUGigwDQYJKoZIhvcNAQELBQADggIBAGztiudDqHknm7jP
-hz5kOBiMEUKShjfgWMMb7gQu94TsgxBoDH94LZzCl442ThbYDuprSK1Pnl0NzA2p
-PhiFfsxomTk11tifhsEy+01lsyIUS8iFZtoX/3GRrJxWV95xLFZCv/jNDvCi0//S
-IhX70HgKfuGwWs6ON9upnueVz2PyLA3S+m/zyNX7ALf3NWcQ03tS7BAy+L/dXsmm
-gqTxsL8dLt0l5L1N8DWpkQFH+BAClFvrPusNutUdYyylLqvn4x6j7kuqX7FmAbSC
-WvlGS8fx+N8svv113ZY4mjc6bqXmMhVus5DAOYp0pZWgvg0uiXnNKVaOw15XUcQF
-bwRVj4HpTL1ZRssqvE3JHfLGTwXkyAQN925P2sM6nNLC9enGJHoUPhxCMKgCRTGp
-/FCp3NyGOA9bkz9/CE5qDSc6EHlWwxW4PgaG9tlwZ691eoviWMzGdU8yVcVsFAko
-O/KV5GreLCgHraB9Byjd1Fqj6aZ8E4yZC1J429nR3z5aQ3Z/RmBTws3ndkd8Vc20
-OWQQW5VLNV1EgyTV4C4kDMGAbmkAgAZ3CmaCEAxRbzeJV9vzTOW4ue4jZpdgt1Ld
-2Zb7uoo7oE3OXvBETJDMIU8bOphrjjGD+YMIUssZwTVr7qEVW4g/bazyNJJTpjAq
-E9fmhqhd2ULSx52peovL3+6iMcLl
------END CERTIFICATE-----
# "SwissSign Silver CA - G2"
# BE 6C 4D A2 BB B9 BA 59 B6 F3 93 97 68 37 42 46
# C3 C0 05 99 3F A9 8F 02 0D 1D ED BE D4 8A 81 D5
@@ -4255,41 +4144,6 @@ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
-----END CERTIFICATE-----
-# "SwissSign Silver Root CA - G3"
-# 1E 49 AC 5D C6 9E 86 D0 56 5D A2 C1 30 5C 41 93
-# 30 B0 B7 81 BF EC 50 E5 4A 1B 35 AF 7F DD D5 01
------BEGIN CERTIFICATE-----
-MIIFfjCCA2agAwIBAgIJAKqIsFoLsXabMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
-BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJjAkBgNVBAMTHVN3aXNzU2ln
-biBTaWx2ZXIgUm9vdCBDQSAtIEczMB4XDTA5MDgwNDEzMTkxNFoXDTM3MDgwNDEz
-MTkxNFowTDELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEmMCQG
-A1UEAxMdU3dpc3NTaWduIFNpbHZlciBSb290IENBIC0gRzMwggIiMA0GCSqGSIb3
-DQEBAQUAA4ICDwAwggIKAoICAQC+h5sF5nF8Um9t7Dep6bPczF9/01DqIZsE8D2/
-vo7JpRQWMhDPmfzscK1INmckDBcy1inlSjmxN+umeAxsbxnKTvdR2hro+iE4bJWc
-L9aLzDsCm78mmxFFtrg0Wh2mVEhSyJ14cc5ISsyneIPcaKtmHncH0zYYCNfUbWD4
-8HnTMzYJkmO3BJr1p5baRa90GvyC46hbDjo/UleYfrycjMHAslrfxH7+DKZUdoN+
-ut3nKvRKNk+HZS6lujmNWWEp89OOJHCMU5sRpUcHsnUFXA2E2UTZzckmRFduAn2V
-AdSrJIbuPXD7V/qwKRTQnfLFl8sJyvHyPefYS5bpiC+eR1GKVGWYSNIS5FR3DAfm
-vluc8d0Dfo2E/L7JYtX8yTroibVfwgVSYfCcPuwuTYxykY7IQ8GiKF71gCTc4i+H
-O1MA5cvwsnyNeRmgiM14+MWKWnflBqzdSt7mcG6+r771sasOCLDboD+Uxb4Subx7
-J3m1MildrsUgI5IDe1Q5sIkiVG0S48N46jpA/aSTrOktiDzbpkdmTN/YF+0W3hrW
-10Fmvx2A8aTgZBEpXgwnBWLr5cQEYtHEnwxqVdZYOJxmD537q1SAmZzsSdaCn9pF
-1j9TBgO3/R/shn104KS06DK2qgcj+O8kQZ5jMHj0VN2O8Fo4jhJ/eMdvAlYhM864
-uK1pVQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
-BgNVHQ4EFgQUoYxFkwoSYwunV18ySn3hIee3PmYwHwYDVR0jBBgwFoAUoYxFkwoS
-YwunV18ySn3hIee3PmYwDQYJKoZIhvcNAQELBQADggIBAIeuYW1IOCrGHNxKLoR4
-ScAjKkW4NU3RBfq5BTPEZL3brVQWKrA+DVoo2qYagHMMxEFvr7g0tnfUW44dC4tG
-kES1s+5JGInBSzSzhzV0op5FZ+1FcWa2uaElc9fCrIj70h2na9rAWubYWWQ0l2Ug
-MTMDT86tCZ6u6cI+GHW0MyUSuwXsULpxQOK93ohGBSGEi6MrHuswMIm/EfVcRPiR
-i0tZRQswDcoMT29jvgT+we3gh/7IzVa/5dyOetTWKU6A26ubP45lByL3RM2WHy3H
-9Qm2mHD/ONxQFRGEO3+p8NgkVMgXjCsTSdaZf0XRD46/aXI3Uwf05q79Wz55uQbN
-uIF4tE2g0DW65K7/00m8Ne1jxrP846thWgW2C+T/qSq+31ROwktcaNqjMqLJTVcY
-UzRZPGaZ1zwCeKdMcdC/2/HEPOcB5gTyRPZIJjAzybEBGesC8cwh+joCMBedyF+A
-P90lrAKb4xfevcqSFNJSgVPm6vwwZzKpYvaTFxUHMV4PG2n19Km3fC2z7YREMkco
-BzuGaUWpxzaWkHJ02BKmcyPRTrm2ejrEKaFQBhG52fQmbmIIEiAW8AFXF9QFNmeX
-61H5/zMkDAUPVr/vPRxSjoreaQ9aH/DVAzFEs5LG6nWorrvHYAOImP/HBIRSkIbh
-tJOpUC/o69I2rDBgp9ADE7UK
------END CERTIFICATE-----
# "Symantec Class 1 Public Primary Certification Authority - G6"
# 9D 19 0B 2E 31 45 66 68 5B E8 A8 89 E2 7A A8 C7
# D7 AE 1D 8A AD DB A3 C1 EC F9 D2 48 63 CD 34 B9
diff --git a/src/crypto/x509/root_darwin_ios_gen.go b/src/crypto/x509/root_ios_gen.go
index 7a42466e5f..8bc6e7d9c4 100644
--- a/src/crypto/x509/root_darwin_ios_gen.go
+++ b/src/crypto/x509/root_ios_gen.go
@@ -4,7 +4,7 @@
// +build ignore
-// Generates root_darwin_ios.go.
+// Generates root_ios.go.
//
// As of iOS 13, there is no API for querying the system trusted X.509 root
// certificates.
@@ -27,9 +27,9 @@ import (
"fmt"
"go/format"
"io"
- "io/ioutil"
"log"
"net/http"
+ "os"
"path"
"sort"
"strings"
@@ -37,7 +37,7 @@ import (
)
func main() {
- var output = flag.String("output", "root_darwin_ios.go", "file name to write")
+ var output = flag.String("output", "root_ios.go", "file name to write")
var version = flag.String("version", "", "security_certificates version")
flag.Parse()
if *version == "" {
@@ -81,7 +81,7 @@ func main() {
continue
}
- der, err := ioutil.ReadAll(tr)
+ der, err := io.ReadAll(tr)
if err != nil {
log.Fatal(err)
}
@@ -124,7 +124,11 @@ func main() {
if strings.ToLower(certName(certs[i])) != strings.ToLower(certName(certs[j])) {
return strings.ToLower(certName(certs[i])) < strings.ToLower(certName(certs[j]))
}
- return certs[i].NotBefore.Before(certs[j].NotBefore)
+ if !certs[i].NotBefore.Equal(certs[j].NotBefore) {
+ return certs[i].NotBefore.Before(certs[j].NotBefore)
+ }
+ fi, fj := sha256.Sum256(certs[i].Raw), sha256.Sum256(certs[j].Raw)
+ return bytes.Compare(fi[:], fj[:]) < 0
})
out := new(bytes.Buffer)
@@ -151,15 +155,15 @@ func main() {
if err != nil {
log.Fatal(err)
}
- if err := ioutil.WriteFile(*output, source, 0644); err != nil {
+ if err := os.WriteFile(*output, source, 0644); err != nil {
log.Fatal(err)
}
}
-const header = `// Code generated by root_darwin_ios_gen.go -version %s; DO NOT EDIT.
+const header = `// Code generated by root_ios_gen.go -version %s; DO NOT EDIT.
// Update the version in root.go and regenerate with "go generate".
-// +build darwin,arm64 darwin,amd64,ios
+// +build ios
// +build !x509omitbundledroots
package x509
@@ -168,9 +172,6 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return nil, nil
}
-// loadSystemRootsWithCgo is not available on iOS.
-var loadSystemRootsWithCgo func() (*CertPool, error)
-
func loadSystemRoots() (*CertPool, error) {
p := NewCertPool()
p.AppendCertsFromPEM([]byte(systemRootsPEM))
diff --git a/src/crypto/x509/root_js.go b/src/crypto/x509/root_js.go
index 70abb73f99..4e537a4fe5 100644
--- a/src/crypto/x509/root_js.go
+++ b/src/crypto/x509/root_js.go
@@ -8,3 +8,7 @@ package x509
// Possible certificate files; stop after finding one.
var certFiles = []string{}
+
+// Possible directories with certificate files; stop after successfully
+// reading at least one file from a directory.
+var certDirectories = []string{}
diff --git a/src/crypto/x509/root_linux.go b/src/crypto/x509/root_linux.go
index 267775dc5f..ad6ce5cae7 100644
--- a/src/crypto/x509/root_linux.go
+++ b/src/crypto/x509/root_linux.go
@@ -13,3 +13,11 @@ var certFiles = []string{
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
"/etc/ssl/cert.pem", // Alpine Linux
}
+
+// Possible directories with certificate files; stop after successfully
+// reading at least one file from a directory.
+var certDirectories = []string{
+ "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
+ "/etc/pki/tls/certs", // Fedora/RHEL
+ "/system/etc/security/cacerts", // Android
+}
diff --git a/src/crypto/x509/root_omit.go b/src/crypto/x509/root_omit.go
index 175d71643b..0055b3b862 100644
--- a/src/crypto/x509/root_omit.go
+++ b/src/crypto/x509/root_omit.go
@@ -24,6 +24,3 @@ func loadSystemRoots() (*CertPool, error) {
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
-
-// loadSystemRootsWithCgo is not available on iOS.
-var loadSystemRootsWithCgo func() (*CertPool, error)
diff --git a/src/crypto/x509/root_plan9.go b/src/crypto/x509/root_plan9.go
index 09f0e23033..2dc4aaf5d7 100644
--- a/src/crypto/x509/root_plan9.go
+++ b/src/crypto/x509/root_plan9.go
@@ -7,7 +7,6 @@
package x509
import (
- "io/ioutil"
"os"
)
@@ -24,7 +23,7 @@ func loadSystemRoots() (*CertPool, error) {
roots := NewCertPool()
var bestErr error
for _, file := range certFiles {
- data, err := ioutil.ReadFile(file)
+ data, err := os.ReadFile(file)
if err == nil {
roots.AppendCertsFromPEM(data)
return roots, nil
diff --git a/src/crypto/x509/root_solaris.go b/src/crypto/x509/root_solaris.go
index e6d4e61399..97c19139e3 100644
--- a/src/crypto/x509/root_solaris.go
+++ b/src/crypto/x509/root_solaris.go
@@ -10,3 +10,9 @@ var certFiles = []string{
"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
"/etc/ssl/cacert.pem", // OmniOS
}
+
+// Possible directories with certificate files; stop after successfully
+// reading at least one file from a directory.
+var certDirectories = []string{
+ "/etc/certs/CA",
+}
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index b48e618a65..262fc079d5 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -7,23 +7,12 @@
package x509
import (
- "io/ioutil"
+ "io/fs"
"os"
"path/filepath"
"strings"
)
-// Possible directories with certificate files; stop after successfully
-// reading at least one file from a directory.
-var certDirectories = []string{
- "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
- "/system/etc/security/cacerts", // Android
- "/usr/local/share/certs", // FreeBSD
- "/etc/pki/tls/certs", // Fedora/RHEL
- "/etc/openssl/certs", // NetBSD
- "/var/ssl/certs", // AIX
-}
-
const (
// certFileEnv is the environment variable which identifies where to locate
// the SSL certificate file. If set this overrides the system default.
@@ -50,7 +39,7 @@ func loadSystemRoots() (*CertPool, error) {
var firstErr error
for _, file := range files {
- data, err := ioutil.ReadFile(file)
+ data, err := os.ReadFile(file)
if err == nil {
roots.AppendCertsFromPEM(data)
break
@@ -78,31 +67,31 @@ func loadSystemRoots() (*CertPool, error) {
continue
}
for _, fi := range fis {
- data, err := ioutil.ReadFile(directory + "/" + fi.Name())
+ data, err := os.ReadFile(directory + "/" + fi.Name())
if err == nil {
roots.AppendCertsFromPEM(data)
}
}
}
- if len(roots.certs) > 0 || firstErr == nil {
+ if roots.len() > 0 || firstErr == nil {
return roots, nil
}
return nil, firstErr
}
-// readUniqueDirectoryEntries is like ioutil.ReadDir but omits
+// readUniqueDirectoryEntries is like os.ReadDir but omits
// symlinks that point within the directory.
-func readUniqueDirectoryEntries(dir string) ([]os.FileInfo, error) {
- fis, err := ioutil.ReadDir(dir)
+func readUniqueDirectoryEntries(dir string) ([]fs.DirEntry, error) {
+ files, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
- uniq := fis[:0]
- for _, fi := range fis {
- if !isSameDirSymlink(fi, dir) {
- uniq = append(uniq, fi)
+ uniq := files[:0]
+ for _, f := range files {
+ if !isSameDirSymlink(f, dir) {
+ uniq = append(uniq, f)
}
}
return uniq, nil
@@ -110,10 +99,10 @@ func readUniqueDirectoryEntries(dir string) ([]os.FileInfo, error) {
// isSameDirSymlink reports whether fi in dir is a symlink with a
// target not containing a slash.
-func isSameDirSymlink(fi os.FileInfo, dir string) bool {
- if fi.Mode()&os.ModeSymlink == 0 {
+func isSameDirSymlink(f fs.DirEntry, dir string) bool {
+ if f.Type()&fs.ModeSymlink == 0 {
return false
}
- target, err := os.Readlink(filepath.Join(dir, fi.Name()))
+ target, err := os.Readlink(filepath.Join(dir, f.Name()))
return err == nil && !strings.Contains(target, "/")
}
diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go
index 5a8015429c..878ed7c2fa 100644
--- a/src/crypto/x509/root_unix_test.go
+++ b/src/crypto/x509/root_unix_test.go
@@ -9,7 +9,6 @@ package x509
import (
"bytes"
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -113,15 +112,15 @@ func TestEnvVars(t *testing.T) {
// Verify that the returned certs match, otherwise report where the mismatch is.
for i, cn := range tc.cns {
- if i >= len(r.certs) {
+ if i >= r.len() {
t.Errorf("missing cert %v @ %v", cn, i)
- } else if r.certs[i].Subject.CommonName != cn {
- fmt.Printf("%#v\n", r.certs[0].Subject)
- t.Errorf("unexpected cert common name %q, want %q", r.certs[i].Subject.CommonName, cn)
+ } else if r.mustCert(t, i).Subject.CommonName != cn {
+ fmt.Printf("%#v\n", r.mustCert(t, 0).Subject)
+ t.Errorf("unexpected cert common name %q, want %q", r.mustCert(t, i).Subject.CommonName, cn)
}
}
- if len(r.certs) > len(tc.cns) {
- t.Errorf("got %v certs, which is more than %v wanted", len(r.certs), len(tc.cns))
+ if r.len() > len(tc.cns) {
+ t.Errorf("got %v certs, which is more than %v wanted", r.len(), len(tc.cns))
}
})
}
@@ -147,7 +146,7 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
os.Setenv(certFileEnv, origFile)
}()
- tmpDir, err := ioutil.TempDir(os.TempDir(), "x509-issue35325")
+ tmpDir, err := os.MkdirTemp(os.TempDir(), "x509-issue35325")
if err != nil {
t.Fatalf("Failed to create temporary directory: %v", err)
}
@@ -166,7 +165,7 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
t.Fatalf("Failed to create certificate dir: %v", err)
}
certOutFile := filepath.Join(certDir, "cert.crt")
- if err := ioutil.WriteFile(certOutFile, []byte(certPEM), 0655); err != nil {
+ if err := os.WriteFile(certOutFile, []byte(certPEM), 0655); err != nil {
t.Fatalf("Failed to write certificate to file: %v", err)
}
certDirs = append(certDirs, certDir)
@@ -197,7 +196,8 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
strCertPool := func(p *CertPool) string {
return string(bytes.Join(p.Subjects(), []byte("\n")))
}
- if !reflect.DeepEqual(gotPool, wantPool) {
+
+ if !certPoolEqual(gotPool, wantPool) {
g, w := strCertPool(gotPool), strCertPool(wantPool)
t.Fatalf("Mismatched certPools\nGot:\n%s\n\nWant:\n%s", g, w)
}
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go
index 1e0f3acb67..1e9be80b7d 100644
--- a/src/crypto/x509/root_windows.go
+++ b/src/crypto/x509/root_windows.go
@@ -38,7 +38,11 @@ func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertCo
}
if opts.Intermediates != nil {
- for _, intermediate := range opts.Intermediates.certs {
+ for i := 0; i < opts.Intermediates.len(); i++ {
+ intermediate, err := opts.Intermediates.cert(i)
+ if err != nil {
+ return nil, err
+ }
ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
if err != nil {
return nil, err
@@ -151,6 +155,44 @@ func init() {
}
}
+func verifyChain(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) (chain []*Certificate, err error) {
+ err = checkChainTrustStatus(c, chainCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if opts != nil && len(opts.DNSName) > 0 {
+ err = checkChainSSLServerPolicy(c, chainCtx, opts)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ chain, err = extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
+ if err != nil {
+ return nil, err
+ }
+ if len(chain) == 0 {
+ return nil, errors.New("x509: internal error: system verifier returned an empty chain")
+ }
+
+ // Mitigate CVE-2020-0601, where the Windows system verifier might be
+ // tricked into using custom curve parameters for a trusted root, by
+ // double-checking all ECDSA signatures. If the system was tricked into
+ // using spoofed parameters, the signature will be invalid for the correct
+ // ones we parsed. (We don't support custom curves ourselves.)
+ for i, parent := range chain[1:] {
+ if parent.PublicKeyAlgorithm != ECDSA {
+ continue
+ }
+ if err := parent.CheckSignature(chain[i].SignatureAlgorithm,
+ chain[i].RawTBSCertificate, chain[i].Signature); err != nil {
+ return nil, err
+ }
+ }
+ return chain, nil
+}
+
// systemVerify is like Verify, except that it uses CryptoAPI calls
// to build certificate chains and verify them.
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
@@ -198,67 +240,41 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
verifyTime = &ft
}
- // CertGetCertificateChain will traverse Windows's root stores
- // in an attempt to build a verified certificate chain. Once
- // it has found a verified chain, it stops. MSDN docs on
- // CERT_CHAIN_CONTEXT:
- //
- // When a CERT_CHAIN_CONTEXT is built, the first simple chain
- // begins with an end certificate and ends with a self-signed
- // certificate. If that self-signed certificate is not a root
- // or otherwise trusted certificate, an attempt is made to
- // build a new chain. CTLs are used to create the new chain
- // beginning with the self-signed certificate from the original
- // chain as the end certificate of the new chain. This process
- // continues building additional simple chains until the first
- // self-signed certificate is a trusted certificate or until
- // an additional simple chain cannot be built.
- //
- // The result is that we'll only get a single trusted chain to
- // return to our caller.
- var chainCtx *syscall.CertChainContext
- err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
- if err != nil {
- return nil, err
- }
- defer syscall.CertFreeCertificateChain(chainCtx)
+ // The default is to return only the highest quality chain,
+ // setting this flag will add additional lower quality contexts.
+ // These are returned in the LowerQualityChains field.
+ const CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS = 0x00000080
- err = checkChainTrustStatus(c, chainCtx)
+ // CertGetCertificateChain will traverse Windows's root stores in an attempt to build a verified certificate chain
+ var topCtx *syscall.CertChainContext
+ err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS, 0, &topCtx)
if err != nil {
return nil, err
}
+ defer syscall.CertFreeCertificateChain(topCtx)
- if opts != nil && len(opts.DNSName) > 0 {
- err = checkChainSSLServerPolicy(c, chainCtx, opts)
- if err != nil {
- return nil, err
- }
+ chain, topErr := verifyChain(c, topCtx, opts)
+ if topErr == nil {
+ chains = append(chains, chain)
}
- chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
- if err != nil {
- return nil, err
- }
- if len(chain) < 1 {
- return nil, errors.New("x509: internal error: system verifier returned an empty chain")
- }
+ if lqCtxCount := topCtx.LowerQualityChainCount; lqCtxCount > 0 {
+ lqCtxs := (*[1 << 20]*syscall.CertChainContext)(unsafe.Pointer(topCtx.LowerQualityChains))[:lqCtxCount:lqCtxCount]
- // Mitigate CVE-2020-0601, where the Windows system verifier might be
- // tricked into using custom curve parameters for a trusted root, by
- // double-checking all ECDSA signatures. If the system was tricked into
- // using spoofed parameters, the signature will be invalid for the correct
- // ones we parsed. (We don't support custom curves ourselves.)
- for i, parent := range chain[1:] {
- if parent.PublicKeyAlgorithm != ECDSA {
- continue
- }
- if err := parent.CheckSignature(chain[i].SignatureAlgorithm,
- chain[i].RawTBSCertificate, chain[i].Signature); err != nil {
- return nil, err
+ for _, ctx := range lqCtxs {
+ chain, err := verifyChain(c, ctx, opts)
+ if err == nil {
+ chains = append(chains, chain)
+ }
}
}
- return [][]*Certificate{chain}, nil
+ if len(chains) == 0 {
+ // Return the error from the highest quality context.
+ return nil, topErr
+ }
+
+ return chains, nil
}
func loadSystemRoots() (*CertPool, error) {
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index cb8d8f872d..46afb2698a 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -187,6 +187,8 @@ func (se SystemRootsError) Error() string {
return msg
}
+func (se SystemRootsError) Unwrap() error { return se.Err }
+
// errNotParsed is returned when a certificate without ASN.1 contents is
// verified. Platform-specific verification needs the ASN.1 contents.
var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
@@ -759,11 +761,13 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
if len(c.Raw) == 0 {
return nil, errNotParsed
}
- if opts.Intermediates != nil {
- for _, intermediate := range opts.Intermediates.certs {
- if len(intermediate.Raw) == 0 {
- return nil, errNotParsed
- }
+ for i := 0; i < opts.Intermediates.len(); i++ {
+ c, err := opts.Intermediates.cert(i)
+ if err != nil {
+ return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
+ }
+ if len(c.Raw) == 0 {
+ return nil, errNotParsed
}
}
@@ -889,11 +893,11 @@ func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, curre
}
}
- for _, rootNum := range opts.Roots.findPotentialParents(c) {
- considerCandidate(rootCertificate, opts.Roots.certs[rootNum])
+ for _, root := range opts.Roots.findPotentialParents(c) {
+ considerCandidate(rootCertificate, root)
}
- for _, intermediateNum := range opts.Intermediates.findPotentialParents(c) {
- considerCandidate(intermediateCertificate, opts.Intermediates.certs[intermediateNum])
+ for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
+ considerCandidate(intermediateCertificate, intermediate)
}
if len(chains) > 0 {
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 76d1ab9a47..8e0a7bef47 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -285,18 +285,6 @@ var verifyTests = []verifyTest{
errorCallback: expectHostnameError("certificate is valid for"),
},
{
- // The issuer name in the leaf doesn't exactly match the
- // subject name in the root. Go does not perform
- // canonicalization and so should reject this. See issue 14955.
- name: "IssuerSubjectMismatch",
- leaf: issuerSubjectMatchLeaf,
- roots: []string{issuerSubjectMatchRoot},
- currentTime: 1475787715,
- systemSkip: true, // does not chain to a system root
-
- errorCallback: expectSubjectIssuerMismatcthError,
- },
- {
// An X.509 v1 certificate should not be accepted as an
// intermediate.
name: "X509v1Intermediate",
@@ -430,6 +418,20 @@ var verifyTests = []verifyTest{
{"Acme LLC", "Acme Co"},
},
},
+ {
+ // When there are two parents, one with a incorrect subject but matching SKID
+ // and one with a correct subject but missing SKID, the latter should be
+ // considered as a possible parent.
+ leaf: leafMatchingAKIDMatchingIssuer,
+ roots: []string{rootMatchingSKIDMismatchingSubject, rootMismatchingSKIDMatchingSubject},
+ currentTime: 1550000000,
+ dnsName: "example",
+ systemSkip: true,
+
+ expectedChains: [][]string{
+ {"Leaf", "Root B"},
+ },
+ },
}
func expectHostnameError(msg string) func(*testing.T, error) {
@@ -474,12 +476,6 @@ func expectHashError(t *testing.T, err error) {
}
}
-func expectSubjectIssuerMismatcthError(t *testing.T, err error) {
- if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NameMismatch {
- t.Fatalf("error was not a NameMismatch: %v", err)
- }
-}
-
func expectNameConstraintsError(t *testing.T, err error) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName {
t.Fatalf("error was not a CANotAuthorizedForThisName: %v", err)
@@ -554,34 +550,55 @@ func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
}
}
- if len(chains) != len(test.expectedChains) {
- t.Errorf("wanted %d chains, got %d", len(test.expectedChains), len(chains))
+ doesMatch := func(expectedChain []string, chain []*Certificate) bool {
+ if len(chain) != len(expectedChain) {
+ return false
+ }
+
+ for k, cert := range chain {
+ if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
+ return false
+ }
+ }
+ return true
}
- // We check that each returned chain matches a chain from
- // expectedChains but an entry in expectedChains can't match
- // two chains.
- seenChains := make([]bool, len(chains))
-NextOutputChain:
- for _, chain := range chains {
- TryNextExpected:
- for j, expectedChain := range test.expectedChains {
- if seenChains[j] {
- continue
+ // Every expected chain should match 1 returned chain
+ for _, expectedChain := range test.expectedChains {
+ nChainMatched := 0
+ for _, chain := range chains {
+ if doesMatch(expectedChain, chain) {
+ nChainMatched++
}
- if len(chain) != len(expectedChain) {
- continue
+ }
+
+ if nChainMatched != 1 {
+ t.Errorf("Got %v matches instead of %v for expected chain %v", nChainMatched, 1, expectedChain)
+ for _, chain := range chains {
+ if doesMatch(expectedChain, chain) {
+ t.Errorf("\t matched %v", chainToDebugString(chain))
+ }
}
- for k, cert := range chain {
- if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
- continue TryNextExpected
+ }
+ }
+
+ // Every returned chain should match 1 expected chain (or <2 if testing against the system)
+ for _, chain := range chains {
+ nMatched := 0
+ for _, expectedChain := range test.expectedChains {
+ if doesMatch(expectedChain, chain) {
+ nMatched++
+ }
+ }
+ // Allow additional unknown chains if systemLax is set
+ if nMatched == 0 && test.systemLax == false || nMatched > 1 {
+ t.Errorf("Got %v matches for chain %v", nMatched, chainToDebugString(chain))
+ for _, expectedChain := range test.expectedChains {
+ if doesMatch(expectedChain, chain) {
+ t.Errorf("\t matched %v", expectedChain)
}
}
- // we matched
- seenChains[j] = true
- continue NextOutputChain
}
- t.Errorf("no expected chain matched %s", chainToDebugString(chain))
}
}
@@ -1615,6 +1632,36 @@ ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
ZZMqeJS7JldLx91sPUArY5A=
-----END CERTIFICATE-----`
+const rootMatchingSKIDMismatchingSubject = `-----BEGIN CERTIFICATE-----
+MIIBQjCB6aADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQTAe
+Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
+QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPK4p1uXq2aAeDtKDHIokg2rTcPM
+2gq3N9Y96wiW6/7puBK1+INEW//cO9x6FpzkcsHw/TriAqy4sck/iDAvf9WjMjAw
+MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAMBgNVHQ4EBQQDAQID
+MAoGCCqGSM49BAMCA0gAMEUCIQDgtAp7iVHxMnKxZPaLQPC+Tv2r7+DJc88k2SKH
+MPs/wQIgFjjNvBoQEl7vSHTcRGCCcFMdlN4l0Dqc9YwGa9fyrQs=
+-----END CERTIFICATE-----`
+
+const rootMismatchingSKIDMatchingSubject = `-----BEGIN CERTIFICATE-----
+MIIBNDCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
+Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
+QjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI1YRFcIlkWzm9BdEVrIsEQJ2dT6
+qiW8/WV9GoIhmDtX9SEDHospc0Cgm+TeD2QYW2iMrS5mvNe4GSw0Jezg/bOjJDAi
+MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNI
+ADBFAiEAukWOiuellx8bugRiwCS5XQ6IOJ1SZcjuZxj76WojwxkCIHqa71qNw8FM
+DtA5yoL9M2pDFF6ovFWnaCe+KlzSwAW/
+-----END CERTIFICATE-----`
+
+const leafMatchingAKIDMatchingIssuer = `-----BEGIN CERTIFICATE-----
+MIIBNTCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
+Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMA8xDTALBgNVBAMTBExlYWYw
+WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASNWERXCJZFs5vQXRFayLBECdnU+qol
+vP1lfRqCIZg7V/UhAx6LKXNAoJvk3g9kGFtojK0uZrzXuBksNCXs4P2zoyYwJDAO
+BgNVHSMEBzAFgAMBAgMwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNJ
+ADBGAiEAnV9XV7a4h0nfJB8pWv+pBUXRlRFA2uZz3mXEpee8NYACIQCWa+wL70GL
+ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA==
+-----END CERTIFICATE-----`
+
var unknownAuthorityErrorTests = []struct {
cert string
expected string
@@ -1979,3 +2026,11 @@ func TestSystemRootsError(t *testing.T) {
t.Errorf("error was not SystemRootsError: %v", err)
}
}
+
+func TestSystemRootsErrorUnwrap(t *testing.T) {
+ var err1 = errors.New("err1")
+ err := SystemRootsError{Err: err1}
+ if !errors.Is(err, err1) {
+ t.Error("errors.Is failed, wanted success")
+ }
+}
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 49ac059a0e..60dfac741b 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -14,8 +14,6 @@ import (
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
- _ "crypto/sha256"
- _ "crypto/sha512"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
@@ -28,7 +26,13 @@ import (
"strconv"
"strings"
"time"
- "unicode/utf8"
+ "unicode"
+
+ // Explicitly import these for their crypto.RegisterHash init side-effects.
+ // Keep these as blank imports, even if they're imported above.
+ _ "crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
@@ -159,10 +163,6 @@ type dsaAlgorithmParameters struct {
P, Q, G *big.Int
}
-type dsaSignature struct {
- R, S *big.Int
-}
-
type validity struct {
NotBefore, NotAfter time.Time
}
@@ -182,14 +182,15 @@ type SignatureAlgorithm int
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
- MD2WithRSA
- MD5WithRSA
+
+ MD2WithRSA // Unsupported.
+ MD5WithRSA // Only supported for signing, not verification.
SHA1WithRSA
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
- DSAWithSHA1
- DSAWithSHA256
+ DSAWithSHA1 // Unsupported.
+ DSAWithSHA256 // Unsupported.
ECDSAWithSHA1
ECDSAWithSHA256
ECDSAWithSHA384
@@ -223,7 +224,7 @@ type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
- DSA
+ DSA // Unsupported.
ECDSA
Ed25519
)
@@ -351,6 +352,19 @@ var signatureAlgorithmDetails = []struct {
{PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
}
+// hashToPSSParameters contains the DER encoded RSA PSS parameters for the
+// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
+// The parameters contain the following values:
+// * hashAlgorithm contains the associated hash identifier with NULL parameters
+// * maskGenAlgorithm always contains the default mgf1SHA1 identifier
+// * saltLength contains the length of the associated hash
+// * trailerField always contains the default trailerFieldBC value
+var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
+ crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}},
+ crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}},
+ crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}},
+}
+
// pssParameters reflects the parameters in an AlgorithmIdentifier that
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
type pssParameters struct {
@@ -363,51 +377,6 @@ type pssParameters struct {
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
}
-// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
-// in an AlgorithmIdentifier that specifies RSA PSS.
-func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
- var hashOID asn1.ObjectIdentifier
-
- switch hashFunc {
- case crypto.SHA256:
- hashOID = oidSHA256
- case crypto.SHA384:
- hashOID = oidSHA384
- case crypto.SHA512:
- hashOID = oidSHA512
- }
-
- params := pssParameters{
- Hash: pkix.AlgorithmIdentifier{
- Algorithm: hashOID,
- Parameters: asn1.NullRawValue,
- },
- MGF: pkix.AlgorithmIdentifier{
- Algorithm: oidMGF1,
- },
- SaltLength: hashFunc.Size(),
- TrailerField: 1,
- }
-
- mgf1Params := pkix.AlgorithmIdentifier{
- Algorithm: hashOID,
- Parameters: asn1.NullRawValue,
- }
-
- var err error
- params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
- if err != nil {
- panic(err)
- }
-
- serialized, err := asn1.Marshal(params)
- if err != nil {
- panic(err)
- }
-
- return asn1.RawValue{FullBytes: serialized}
-}
-
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm {
if ai.Algorithm.Equal(oidSignatureEd25519) {
// RFC 8410, Section 3
@@ -877,28 +846,6 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
} else {
return rsa.VerifyPKCS1v15(pub, hashType, signed, signature)
}
- case *dsa.PublicKey:
- if pubKeyAlgo != DSA {
- return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
- }
- dsaSig := new(dsaSignature)
- if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
- return err
- } else if len(rest) != 0 {
- return errors.New("x509: trailing data after DSA signature")
- }
- if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
- return errors.New("x509: DSA signature contained zero or negative values")
- }
- // According to FIPS 186-3, section 4.6, the hash must be truncated if it is longer
- // than the key length, but crypto/dsa doesn't do it automatically.
- if maxHashLen := pub.Q.BitLen() / 8; maxHashLen < len(signed) {
- signed = signed[:maxHashLen]
- }
- if !dsa.Verify(pub, signed, dsaSig.R, dsaSig.S) {
- return errors.New("x509: DSA verification failure")
- }
- return
case *ecdsa.PublicKey:
if pubKeyAlgo != ECDSA {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
@@ -1117,17 +1064,29 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
err = forEachSAN(value, func(tag int, data []byte) error {
switch tag {
case nameTypeEmail:
- emailAddresses = append(emailAddresses, string(data))
+ email := string(data)
+ if err := isIA5String(email); err != nil {
+ return errors.New("x509: SAN rfc822Name is malformed")
+ }
+ emailAddresses = append(emailAddresses, email)
case nameTypeDNS:
- dnsNames = append(dnsNames, string(data))
+ name := string(data)
+ if err := isIA5String(name); err != nil {
+ return errors.New("x509: SAN dNSName is malformed")
+ }
+ dnsNames = append(dnsNames, string(name))
case nameTypeURI:
- uri, err := url.Parse(string(data))
+ uriStr := string(data)
+ if err := isIA5String(uriStr); err != nil {
+ return errors.New("x509: SAN uniformResourceIdentifier is malformed")
+ }
+ uri, err := url.Parse(uriStr)
if err != nil {
- return fmt.Errorf("x509: cannot parse URI %q: %s", string(data), err)
+ return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err)
}
if len(uri.Host) > 0 {
if _, ok := domainToReverseLabels(uri.Host); !ok {
- return fmt.Errorf("x509: cannot parse URI %q: invalid domain", string(data))
+ return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr)
}
}
uris = append(uris, uri)
@@ -1379,36 +1338,17 @@ func parseCertificate(in *certificate) (*Certificate, error) {
if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
switch e.Id[3] {
case 15:
- // RFC 5280, 4.2.1.3
- var usageBits asn1.BitString
- if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
+ out.KeyUsage, err = parseKeyUsageExtension(e.Value)
+ if err != nil {
return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 KeyUsage")
- }
-
- var usage int
- for i := 0; i < 9; i++ {
- if usageBits.At(i) != 0 {
- usage |= 1 << uint(i)
- }
}
- out.KeyUsage = KeyUsage(usage)
-
case 19:
- // RFC 5280, 4.2.1.9
- var constraints basicConstraints
- if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
+ out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value)
+ if err != nil {
return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 BasicConstraints")
}
-
out.BasicConstraintsValid = true
- out.IsCA = constraints.IsCA
- out.MaxPathLen = constraints.MaxPathLen
out.MaxPathLenZero = out.MaxPathLen == 0
- // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285)
case 17:
out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value)
if err != nil {
@@ -1471,52 +1411,20 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.AuthorityKeyId = a.Id
case 37:
- // RFC 5280, 4.2.1.12. Extended Key Usage
-
- // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
- //
- // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
- //
- // KeyPurposeId ::= OBJECT IDENTIFIER
-
- var keyUsage []asn1.ObjectIdentifier
- if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil {
+ out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value)
+ if err != nil {
return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
- }
-
- for _, u := range keyUsage {
- if extKeyUsage, ok := extKeyUsageFromOID(u); ok {
- out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage)
- } else {
- out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)
- }
}
-
case 14:
- // RFC 5280, 4.2.1.2
- var keyid []byte
- if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
+ out.SubjectKeyId, err = parseSubjectKeyIdExtension(e.Value)
+ if err != nil {
return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 key-id")
}
- out.SubjectKeyId = keyid
-
case 32:
- // RFC 5280 4.2.1.4: Certificate Policies
- var policies []policyInformation
- if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil {
+ out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(e.Value)
+ if err != nil {
return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 certificate policies")
}
- out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
- for i, policy := range policies {
- out.PolicyIdentifiers[i] = policy.Policy
- }
-
default:
// Unknown extensions are recorded if critical.
unhandled = true
@@ -1554,6 +1462,87 @@ func parseCertificate(in *certificate) (*Certificate, error) {
return out, nil
}
+// parseKeyUsageExtension parses id-ce-keyUsage (2.5.29.15) from RFC 5280
+// Section 4.2.1.3
+func parseKeyUsageExtension(ext []byte) (KeyUsage, error) {
+ var usageBits asn1.BitString
+ if rest, err := asn1.Unmarshal(ext, &usageBits); err != nil {
+ return 0, err
+ } else if len(rest) != 0 {
+ return 0, errors.New("x509: trailing data after X.509 KeyUsage")
+ }
+
+ var usage int
+ for i := 0; i < 9; i++ {
+ if usageBits.At(i) != 0 {
+ usage |= 1 << uint(i)
+ }
+ }
+ return KeyUsage(usage), nil
+}
+
+// parseBasicConstraintsExtension parses id-ce-basicConstraints (2.5.29.19)
+// from RFC 5280 Section 4.2.1.9
+func parseBasicConstraintsExtension(ext []byte) (isCA bool, maxPathLen int, err error) {
+ var constraints basicConstraints
+ if rest, err := asn1.Unmarshal(ext, &constraints); err != nil {
+ return false, 0, err
+ } else if len(rest) != 0 {
+ return false, 0, errors.New("x509: trailing data after X.509 BasicConstraints")
+ }
+
+ // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285)
+ return constraints.IsCA, constraints.MaxPathLen, nil
+}
+
+// parseExtKeyUsageExtension parses id-ce-extKeyUsage (2.5.29.37) from
+// RFC 5280 Section 4.2.1.12
+func parseExtKeyUsageExtension(ext []byte) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) {
+ var keyUsage []asn1.ObjectIdentifier
+ if rest, err := asn1.Unmarshal(ext, &keyUsage); err != nil {
+ return nil, nil, err
+ } else if len(rest) != 0 {
+ return nil, nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
+ }
+
+ var extKeyUsages []ExtKeyUsage
+ var unknownUsages []asn1.ObjectIdentifier
+ for _, u := range keyUsage {
+ if extKeyUsage, ok := extKeyUsageFromOID(u); ok {
+ extKeyUsages = append(extKeyUsages, extKeyUsage)
+ } else {
+ unknownUsages = append(unknownUsages, u)
+ }
+ }
+ return extKeyUsages, unknownUsages, nil
+}
+
+// parseSubjectKeyIdExtension parses id-ce-subjectKeyIdentifier (2.5.29.14)
+// from RFC 5280 Section 4.2.1.2
+func parseSubjectKeyIdExtension(ext []byte) ([]byte, error) {
+ var keyid []byte
+ if rest, err := asn1.Unmarshal(ext, &keyid); err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, errors.New("x509: trailing data after X.509 key-id")
+ }
+ return keyid, nil
+}
+
+func parseCertificatePoliciesExtension(ext []byte) ([]asn1.ObjectIdentifier, error) {
+ var policies []policyInformation
+ if rest, err := asn1.Unmarshal(ext, &policies); err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, errors.New("x509: trailing data after X.509 certificate policies")
+ }
+ oids := make([]asn1.ObjectIdentifier, len(policies))
+ for i, policy := range policies {
+ oids[i] = policy.Policy
+ }
+ return oids, nil
+}
+
// ParseCertificate parses a single certificate from the given ASN.1 DER data.
func ParseCertificate(asn1Data []byte) (*Certificate, error) {
var cert certificate
@@ -1657,9 +1646,15 @@ func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) boo
func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) {
var rawValues []asn1.RawValue
for _, name := range dnsNames {
+ if err := isIA5String(name); err != nil {
+ return nil, err
+ }
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)})
}
for _, email := range emailAddresses {
+ if err := isIA5String(email); err != nil {
+ return nil, err
+ }
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)})
}
for _, rawIP := range ipAddresses {
@@ -1671,14 +1666,19 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris [
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip})
}
for _, uri := range uris {
- rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())})
+ uriStr := uri.String()
+ if err := isIA5String(uriStr); err != nil {
+ return nil, err
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uriStr)})
}
return asn1.Marshal(rawValues)
}
func isIA5String(s string) error {
for _, r := range s {
- if r >= utf8.RuneSelf {
+ // Per RFC5280 "IA5String is limited to the set of ASCII characters"
+ if r > unicode.MaxASCII {
return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s)
}
}
@@ -1686,67 +1686,32 @@ func isIA5String(s string) error {
return nil
}
-func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) {
+func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0
if template.KeyUsage != 0 &&
!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
- ret[n].Id = oidExtensionKeyUsage
- ret[n].Critical = true
-
- var a [2]byte
- a[0] = reverseBitsInAByte(byte(template.KeyUsage))
- a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
-
- l := 1
- if a[1] != 0 {
- l = 2
- }
-
- bitString := a[:l]
- ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
+ ret[n], err = marshalKeyUsage(template.KeyUsage)
if err != nil {
- return
+ return nil, err
}
n++
}
if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
- ret[n].Id = oidExtensionExtendedKeyUsage
-
- var oids []asn1.ObjectIdentifier
- for _, u := range template.ExtKeyUsage {
- if oid, ok := oidFromExtKeyUsage(u); ok {
- oids = append(oids, oid)
- } else {
- panic("internal error")
- }
- }
-
- oids = append(oids, template.UnknownExtKeyUsage...)
-
- ret[n].Value, err = asn1.Marshal(oids)
+ ret[n], err = marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
if err != nil {
- return
+ return nil, err
}
n++
}
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
- // Leaving MaxPathLen as zero indicates that no maximum path
- // length is desired, unless MaxPathLenZero is set. A value of
- // -1 causes encoding/asn1 to omit the value as desired.
- maxPathLen := template.MaxPathLen
- if maxPathLen == 0 && !template.MaxPathLenZero {
- maxPathLen = -1
- }
- ret[n].Id = oidExtensionBasicConstraints
- ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
- ret[n].Critical = true
+ ret[n], err = marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
if err != nil {
- return
+ return nil, err
}
n++
}
@@ -1808,14 +1773,9 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId
if len(template.PolicyIdentifiers) > 0 &&
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
- ret[n].Id = oidExtensionCertificatePolicies
- policies := make([]policyInformation, len(template.PolicyIdentifiers))
- for i, policy := range template.PolicyIdentifiers {
- policies[i].Policy = policy
- }
- ret[n].Value, err = asn1.Marshal(policies)
+ ret[n], err = marshalCertificatePolicies(template.PolicyIdentifiers)
if err != nil {
- return
+ return nil, err
}
n++
}
@@ -1948,6 +1908,141 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId
return append(ret[:n], template.ExtraExtensions...), nil
}
+func marshalKeyUsage(ku KeyUsage) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionKeyUsage, Critical: true}
+
+ var a [2]byte
+ a[0] = reverseBitsInAByte(byte(ku))
+ a[1] = reverseBitsInAByte(byte(ku >> 8))
+
+ l := 1
+ if a[1] != 0 {
+ l = 2
+ }
+
+ bitString := a[:l]
+ var err error
+ ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
+ if err != nil {
+ return ext, err
+ }
+ return ext, nil
+}
+
+func marshalExtKeyUsage(extUsages []ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionExtendedKeyUsage}
+
+ oids := make([]asn1.ObjectIdentifier, len(extUsages)+len(unknownUsages))
+ for i, u := range extUsages {
+ if oid, ok := oidFromExtKeyUsage(u); ok {
+ oids[i] = oid
+ } else {
+ return ext, errors.New("x509: unknown extended key usage")
+ }
+ }
+
+ copy(oids[len(extUsages):], unknownUsages)
+
+ var err error
+ ext.Value, err = asn1.Marshal(oids)
+ if err != nil {
+ return ext, err
+ }
+ return ext, nil
+}
+
+func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionBasicConstraints, Critical: true}
+ // Leaving MaxPathLen as zero indicates that no maximum path
+ // length is desired, unless MaxPathLenZero is set. A value of
+ // -1 causes encoding/asn1 to omit the value as desired.
+ if maxPathLen == 0 && !maxPathLenZero {
+ maxPathLen = -1
+ }
+ var err error
+ ext.Value, err = asn1.Marshal(basicConstraints{isCA, maxPathLen})
+ if err != nil {
+ return ext, nil
+ }
+ return ext, nil
+}
+
+func marshalCertificatePolicies(policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionCertificatePolicies}
+ policies := make([]policyInformation, len(policyIdentifiers))
+ for i, policy := range policyIdentifiers {
+ policies[i].Policy = policy
+ }
+ var err error
+ ext.Value, err = asn1.Marshal(policies)
+ if err != nil {
+ return ext, err
+ }
+ return ext, nil
+}
+
+func buildCSRExtensions(template *CertificateRequest) ([]pkix.Extension, error) {
+ var ret []pkix.Extension
+
+ if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
+ !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+ sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
+ if err != nil {
+ return nil, err
+ }
+
+ ret = append(ret, pkix.Extension{
+ Id: oidExtensionSubjectAltName,
+ Value: sanBytes,
+ })
+ }
+
+ if template.KeyUsage != 0 &&
+ !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
+ ext, err := marshalKeyUsage(template.KeyUsage)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, ext)
+ }
+
+ if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
+ !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
+ ext, err := marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, ext)
+ }
+
+ if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
+ ext, err := marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, ext)
+ }
+
+ if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
+ skidBytes, err := asn1.Marshal(template.SubjectKeyId)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, pkix.Extension{Id: oidExtensionSubjectKeyId, Value: skidBytes})
+ }
+
+ if len(template.PolicyIdentifiers) > 0 &&
+ !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
+ ext, err := marshalCertificatePolicies(template.PolicyIdentifiers)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, ext)
+ }
+
+ return append(ret, template.ExtraExtensions...), nil
+}
+
func subjectBytes(cert *Certificate) ([]byte, error) {
if len(cert.RawSubject) > 0 {
return cert.RawSubject, nil
@@ -2015,7 +2110,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
return
}
if requestedSigAlgo.isRSAPSS() {
- sigAlgo.Parameters = rsaPSSParameters(hashFunc)
+ sigAlgo.Parameters = hashToPSSParameters[hashFunc]
}
found = true
break
@@ -2134,7 +2229,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
subjectKeyId = h[:]
}
- extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
+ extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
if err != nil {
return
}
@@ -2178,12 +2273,26 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return
}
- return asn1.Marshal(certificate{
+ signedCert, err := asn1.Marshal(certificate{
nil,
c,
signatureAlgorithm,
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
+ if err != nil {
+ return nil, err
+ }
+
+ // Check the signature to ensure the crypto.Signer behaved correctly.
+ // We skip this check if the signature algorithm is MD5WithRSA as we
+ // only support this algorithm for signing, and not verification.
+ if sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm); sigAlg != MD5WithRSA {
+ if err := checkSignature(sigAlg, c.Raw, signature, key.Public()); err != nil {
+ return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
+ }
+ }
+
+ return signedCert, nil
}
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
@@ -2296,6 +2405,7 @@ type CertificateRequest struct {
Version int
Signature []byte
SignatureAlgorithm SignatureAlgorithm
+ KeyUsage KeyUsage
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey interface{}
@@ -2328,6 +2438,37 @@ type CertificateRequest struct {
EmailAddresses []string
IPAddresses []net.IP
URIs []*url.URL
+
+ ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
+ UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
+
+ // BasicConstraintsValid indicates whether IsCA, MaxPathLen,
+ // and MaxPathLenZero are valid.
+ BasicConstraintsValid bool
+ IsCA bool
+
+ // MaxPathLen and MaxPathLenZero indicate the presence and
+ // value of the BasicConstraints' "pathLenConstraint".
+ //
+ // When parsing a certificate, a positive non-zero MaxPathLen
+ // means that the field was specified, -1 means it was unset,
+ // and MaxPathLenZero being true mean that the field was
+ // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false
+ // should be treated equivalent to -1 (unset).
+ //
+ // When generating a certificate, an unset pathLenConstraint
+ // can be requested with either MaxPathLen == -1 or using the
+ // zero value for both MaxPathLen and MaxPathLenZero.
+ MaxPathLen int
+ // MaxPathLenZero indicates that BasicConstraintsValid==true
+ // and MaxPathLen==0 should be interpreted as an actual
+ // maximum path length of zero. Otherwise, that combination is
+ // interpreted as MaxPathLen not being set.
+ MaxPathLenZero bool
+
+ SubjectKeyId []byte
+
+ PolicyIdentifiers []asn1.ObjectIdentifier
}
// These structures reflect the ASN.1 structure of X.509 certificate
@@ -2425,6 +2566,15 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error)
// - EmailAddresses
// - IPAddresses
// - URIs
+// - KeyUsage
+// - ExtKeyUsage
+// - UnknownExtKeyUsage
+// - BasicConstraintsValid
+// - IsCA
+// - MaxPathLen
+// - MaxPathLenZero
+// - SubjectKeyId
+// - PolicyIdentifiers
// - ExtraExtensions
// - Attributes (deprecated)
//
@@ -2455,23 +2605,11 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
return nil, err
}
- var extensions []pkix.Extension
-
- if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
- !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
- sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
- if err != nil {
- return nil, err
- }
-
- extensions = append(extensions, pkix.Extension{
- Id: oidExtensionSubjectAltName,
- Value: sanBytes,
- })
+ extensions, err := buildCSRExtensions(template)
+ if err != nil {
+ return nil, err
}
- extensions = append(extensions, template.ExtraExtensions...)
-
// Make a copy of template.Attributes because we may alter it below.
attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes))
for _, attr := range template.Attributes {
@@ -2655,11 +2793,36 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
}
for _, extension := range out.Extensions {
- if extension.Id.Equal(oidExtensionSubjectAltName) {
+ switch {
+ case extension.Id.Equal(oidExtensionSubjectAltName):
out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value)
if err != nil {
return nil, err
}
+ case extension.Id.Equal(oidExtensionKeyUsage):
+ out.KeyUsage, err = parseKeyUsageExtension(extension.Value)
+ case extension.Id.Equal(oidExtensionExtendedKeyUsage):
+ out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(extension.Value)
+ if err != nil {
+ return nil, err
+ }
+ case extension.Id.Equal(oidExtensionBasicConstraints):
+ out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(extension.Value)
+ if err != nil {
+ return nil, err
+ }
+ out.BasicConstraintsValid = true
+ out.MaxPathLenZero = out.MaxPathLen == 0
+ case extension.Id.Equal(oidExtensionSubjectKeyId):
+ out.SubjectKeyId, err = parseSubjectKeyIdExtension(extension.Value)
+ if err != nil {
+ return nil, err
+ }
+ case extension.Id.Equal(oidExtensionCertificatePolicies):
+ out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(extension.Value)
+ if err != nil {
+ return nil, err
+ }
}
}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index 840f535e55..65d105db34 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -22,6 +22,7 @@ import (
"encoding/pem"
"fmt"
"internal/testenv"
+ "io"
"math/big"
"net"
"net/url"
@@ -988,51 +989,8 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {
t.Fatalf("Failed to parse certificate: %s", err)
}
// test cert is self-signed
- if err = cert.CheckSignatureFrom(cert); err != nil {
- t.Fatalf("DSA Certificate verification failed: %s", err)
- }
-}
-
-const dsaCert1024WithSha256 = `-----BEGIN CERTIFICATE-----
-MIIDKzCCAumgAwIBAgIUOXWPK4gTRZVVY7OSXTU00QEWQU8wCwYJYIZIAWUDBAMC
-MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ
-bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMTkxMDAxMDYxODUyWhgPMzAxOTAy
-MDEwNjE4NTJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
-HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggG4MIIBLAYHKoZIzjgE
-ATCCAR8CgYEAr79m/1ypU1aUbbLX1jikTyX7w2QYP+EkxNtXUiiTuxkC1KBqqxT3
-0Aht2vxFR47ODEK4B79rHO+UevhaqDaAHSH7Z/9umS0h0aS32KLDLb+LI5AneCrn
-eW5YbVhfD03N7uR4kKUCKOnWj5hAk9xiE3y7oFR0bBXzqrrHJF9LMd0CFQCB6lSj
-HSW0rGmNxIZsBl72u7JFLQKBgQCOFd1PGEQmddn0cdFgby5QQfjrqmoD1zNlFZEt
-L0x1EbndFwelLlF1ChNh3NPNUkjwRbla07FDlONs1GMJq6w4vW11ns+pUvAZ2+RM
-EVFjugip8az2ncn3UujGTVdFxnSTLBsRlMP/tFDK3ky//8zn/5ha9SKKw4v1uv6M
-JuoIbwOBhQACgYEAoeKeR90nwrnoPi5MOUPBLQvuzB87slfr+3kL8vFCmgjA6MtB
-7TxQKoBTOo5aVgWDp0lMIMxLd6btzBrm6r3VdRlh/cL8/PtbxkFwBa+Upe4o5NAh
-ISCe2/f2leT1PxtF8xxYjz/fszeUeHsJbVMilE2cuB2SYrR5tMExiqy+QpqjUzBR
-MB0GA1UdDgQWBBQDMIEL8Z3jc1d9wCxWtksUWc8RkjAfBgNVHSMEGDAWgBQDMIEL
-8Z3jc1d9wCxWtksUWc8RkjAPBgNVHRMBAf8EBTADAQH/MAsGCWCGSAFlAwQDAgMv
-ADAsAhQFehZgI4OyKBGpfnXvyJ0Z/0a6nAIUTO265Ane87LfJuQr3FrqvuCI354=
------END CERTIFICATE-----
-`
-
-func TestVerifyCertificateWithDSATooLongHash(t *testing.T) {
- pemBlock, _ := pem.Decode([]byte(dsaCert1024WithSha256))
- cert, err := ParseCertificate(pemBlock.Bytes)
- if err != nil {
- t.Fatalf("Failed to parse certificate: %s", err)
- }
-
- // test cert is self-signed
- if err = cert.CheckSignatureFrom(cert); err != nil {
- t.Fatalf("DSA Certificate self-signature verification failed: %s", err)
- }
-
- signed := []byte("A wild Gopher appears!\n")
- signature, _ := hex.DecodeString("302c0214417aca7ff458f5b566e43e7b82f994953da84be50214625901e249e33f4e4838f8b5966020c286dd610e")
-
- // This signature is using SHA256, but only has 1024 DSA key. The hash has to be truncated
- // in CheckSignature, otherwise it won't pass.
- if err = cert.CheckSignature(DSAWithSHA256, signed, signature); err != nil {
- t.Fatalf("DSA signature verification failed: %s", err)
+ if err = cert.CheckSignatureFrom(cert); err == nil {
+ t.Fatalf("Expected error verifying DSA certificate")
}
}
@@ -2002,7 +1960,7 @@ func TestSystemCertPool(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if !reflect.DeepEqual(a, b) {
+ if !certPoolEqual(a, b) {
t.Fatal("two calls to SystemCertPool had different results")
}
if ok := b.AppendCertsFromPEM([]byte(`
@@ -2702,3 +2660,348 @@ func TestCreateRevocationList(t *testing.T) {
})
}
}
+
+func TestRSAPSAParameters(t *testing.T) {
+ generateParams := func(hashFunc crypto.Hash) []byte {
+ var hashOID asn1.ObjectIdentifier
+
+ switch hashFunc {
+ case crypto.SHA256:
+ hashOID = oidSHA256
+ case crypto.SHA384:
+ hashOID = oidSHA384
+ case crypto.SHA512:
+ hashOID = oidSHA512
+ }
+
+ params := pssParameters{
+ Hash: pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.NullRawValue,
+ },
+ MGF: pkix.AlgorithmIdentifier{
+ Algorithm: oidMGF1,
+ },
+ SaltLength: hashFunc.Size(),
+ TrailerField: 1,
+ }
+
+ mgf1Params := pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.NullRawValue,
+ }
+
+ var err error
+ params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
+ if err != nil {
+ t.Fatalf("failed to marshal MGF parameters: %s", err)
+ }
+
+ serialized, err := asn1.Marshal(params)
+ if err != nil {
+ t.Fatalf("failed to marshal parameters: %s", err)
+ }
+
+ return serialized
+ }
+
+ for h, params := range hashToPSSParameters {
+ generated := generateParams(h)
+ if !bytes.Equal(params.FullBytes, generated) {
+ t.Errorf("hardcoded parameters for %s didn't match generated parameters: got (generated) %x, wanted (hardcoded) %x", h, generated, params.FullBytes)
+ }
+ }
+}
+
+func TestUnknownExtKey(t *testing.T) {
+ const errorContains = "unknown extended key usage"
+
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"foo"},
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsage(-1)},
+ }
+ signer, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Errorf("failed to generate key for TestUnknownExtKey")
+ }
+
+ _, err = CreateCertificate(rand.Reader, template, template, signer.Public(), signer)
+ if !strings.Contains(err.Error(), errorContains) {
+ t.Errorf("expected error containing %q, got %s", errorContains, err)
+ }
+}
+
+func TestIA5SANEnforcement(t *testing.T) {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("ecdsa.GenerateKey failed: %s", err)
+ }
+
+ testURL, err := url.Parse("https://example.com/")
+ if err != nil {
+ t.Fatalf("url.Parse failed: %s", err)
+ }
+ testURL.RawQuery = "∞"
+
+ marshalTests := []struct {
+ name string
+ template *Certificate
+ expectedError string
+ }{
+ {
+ name: "marshal: unicode dNSName",
+ template: &Certificate{
+ SerialNumber: big.NewInt(0),
+ DNSNames: []string{"∞"},
+ },
+ expectedError: "x509: \"∞\" cannot be encoded as an IA5String",
+ },
+ {
+ name: "marshal: unicode rfc822Name",
+ template: &Certificate{
+ SerialNumber: big.NewInt(0),
+ EmailAddresses: []string{"∞"},
+ },
+ expectedError: "x509: \"∞\" cannot be encoded as an IA5String",
+ },
+ {
+ name: "marshal: unicode uniformResourceIdentifier",
+ template: &Certificate{
+ SerialNumber: big.NewInt(0),
+ URIs: []*url.URL{testURL},
+ },
+ expectedError: "x509: \"https://example.com/?∞\" cannot be encoded as an IA5String",
+ },
+ }
+
+ for _, tc := range marshalTests {
+ t.Run(tc.name, func(t *testing.T) {
+ _, err := CreateCertificate(rand.Reader, tc.template, tc.template, k.Public(), k)
+ if err == nil {
+ t.Errorf("expected CreateCertificate to fail with template: %v", tc.template)
+ } else if err.Error() != tc.expectedError {
+ t.Errorf("unexpected error: got %q, want %q", err.Error(), tc.expectedError)
+ }
+ })
+ }
+
+ unmarshalTests := []struct {
+ name string
+ cert string
+ expectedError string
+ }{
+ {
+ name: "unmarshal: unicode dNSName",
+ cert: "308201083081aea003020102020100300a06082a8648ce3d04030230003022180f30303031303130313030303030305a180f30303031303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d0301070342000424bcc48180d8d9db794028f2575ebe3cac79f04d7b0d0151c5292e588aac3668c495f108c626168462e0668c9705e08a211dd103a659d2684e0adf8c2bfd47baa315301330110603551d110101ff040730058203e2889e300a06082a8648ce3d04030203490030460221008ac7827ac326a6ee0fa70b2afe99af575ec60b975f820f3c25f60fff43fbccd0022100bffeed93556722d43d13e461d5b3e33efc61f6349300327d3a0196cb6da501c2",
+ expectedError: "x509: SAN dNSName is malformed",
+ },
+ {
+ name: "unmarshal: unicode rfc822Name",
+ cert: "308201083081aea003020102020100300a06082a8648ce3d04030230003022180f30303031303130313030303030305a180f30303031303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d0301070342000405cb4c4ba72aac980f7b11b0285191425e29e196ce7c5df1c83f56886566e517f196657cc1b73de89ab84ce503fd634e2f2af88fde24c63ca536dc3a5eed2665a315301330110603551d110101ff040730058103e2889e300a06082a8648ce3d0403020349003046022100ed1431cd4b9bb03d88d1511a0ec128a51204375764c716280dc36e2a60142c8902210088c96d25cfaf97eea851ff17d87bb6fe619d6546656e1739f35c3566051c3d0f",
+ expectedError: "x509: SAN rfc822Name is malformed",
+ },
+ {
+ name: "unmarshal: unicode uniformResourceIdentifier",
+ cert: "3082011b3081c3a003020102020100300a06082a8648ce3d04030230003022180f30303031303130313030303030305a180f30303031303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004ce0a79b511701d9188e1ea76bcc5907f1db51de6cc1a037b803f256e8588145ca409d120288bfeb4e38f3088104674d374b35bb91fc80d768d1d519dbe2b0b5aa32a302830260603551d110101ff041c301a861868747470733a2f2f6578616d706c652e636f6d2f3fe2889e300a06082a8648ce3d0403020347003044022044f4697779fd1dae1e382d2452413c5c5ca67851e267d6bc64a8d164977c172c0220505015e657637aa1945d46e7650b6f59b968fc1508ca8b152c99f782446dfc81",
+ expectedError: "x509: SAN uniformResourceIdentifier is malformed",
+ },
+ }
+
+ for _, tc := range unmarshalTests {
+ der, err := hex.DecodeString(tc.cert)
+ if err != nil {
+ t.Fatalf("failed to decode test cert: %s", err)
+ }
+ _, err = ParseCertificate(der)
+ if err == nil {
+ t.Error("expected CreateCertificate to fail")
+ } else if err.Error() != tc.expectedError {
+ t.Errorf("unexpected error: got %q, want %q", err.Error(), tc.expectedError)
+ }
+ }
+}
+
+func BenchmarkCreateCertificate(b *testing.B) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ }
+ tests := []struct {
+ name string
+ gen func() crypto.Signer
+ }{
+ {
+ name: "RSA 2048",
+ gen: func() crypto.Signer {
+ k, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ b.Fatalf("failed to generate test key: %s", err)
+ }
+ return k
+ },
+ },
+ {
+ name: "ECDSA P256",
+ gen: func() crypto.Signer {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ b.Fatalf("failed to generate test key: %s", err)
+ }
+ return k
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ k := tc.gen()
+ b.ResetTimer()
+ b.Run(tc.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, err := CreateCertificate(rand.Reader, template, template, k.Public(), k)
+ if err != nil {
+ b.Fatalf("failed to create certificate: %s", err)
+ }
+ }
+ })
+ }
+}
+
+type brokenSigner struct {
+ pub crypto.PublicKey
+}
+
+func (bs *brokenSigner) Public() crypto.PublicKey {
+ return bs.pub
+}
+
+func (bs *brokenSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, error) {
+ return []byte{1, 2, 3}, nil
+}
+
+func TestCreateCertificateBrokenSigner(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ }
+ k, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ expectedErr := "x509: signature over certificate returned by signer is invalid: crypto/rsa: verification error"
+ _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+ if err == nil {
+ t.Fatal("expected CreateCertificate to fail with a broken signer")
+ } else if err.Error() != expectedErr {
+ t.Fatalf("CreateCertificate returned an unexpected error: got %q, want %q", err, expectedErr)
+ }
+}
+
+func TestCreateCertificateMD5(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ SignatureAlgorithm: MD5WithRSA,
+ }
+ k, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+ if err != nil {
+ t.Fatalf("CreateCertificate failed when SignatureAlgorithm = MD5WithRSA: %s", err)
+ }
+}
+
+func (s *CertPool) mustCert(t *testing.T, n int) *Certificate {
+ c, err := s.lazyCerts[n].getCert()
+ if err != nil {
+ t.Fatalf("failed to load cert %d: %v", n, err)
+ }
+ return c
+}
+
+func allCerts(t *testing.T, p *CertPool) []*Certificate {
+ all := make([]*Certificate, p.len())
+ for i := range all {
+ all[i] = p.mustCert(t, i)
+ }
+ return all
+}
+
+// certPoolEqual reports whether a and b are equal, except for the
+// function pointers.
+func certPoolEqual(a, b *CertPool) bool {
+ if (a != nil) != (b != nil) {
+ return false
+ }
+ if a == nil {
+ return true
+ }
+ if !reflect.DeepEqual(a.byName, b.byName) ||
+ len(a.lazyCerts) != len(b.lazyCerts) {
+ return false
+ }
+ for i := range a.lazyCerts {
+ la, lb := a.lazyCerts[i], b.lazyCerts[i]
+ if !bytes.Equal(la.rawSubject, lb.rawSubject) {
+ return false
+ }
+ ca, err := la.getCert()
+ if err != nil {
+ panic(err)
+ }
+ cb, err := la.getCert()
+ if err != nil {
+ panic(err)
+ }
+ if !ca.Equal(cb) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func TestCertificateRequestRoundtripFields(t *testing.T) {
+ in := &CertificateRequest{
+ KeyUsage: KeyUsageCertSign,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageAny},
+ UnknownExtKeyUsage: []asn1.ObjectIdentifier{{1, 2, 3}},
+ BasicConstraintsValid: true,
+ IsCA: true,
+ MaxPathLen: 0,
+ MaxPathLenZero: true,
+ SubjectKeyId: []byte{1, 2, 3},
+ PolicyIdentifiers: []asn1.ObjectIdentifier{{1, 2, 3}},
+ }
+ out := marshalAndParseCSR(t, in)
+
+ if in.KeyUsage != out.KeyUsage {
+ t.Fatalf("Unexpected KeyUsage: got %v, want %v", out.KeyUsage, in.KeyUsage)
+ }
+ if !reflect.DeepEqual(in.ExtKeyUsage, out.ExtKeyUsage) {
+ t.Fatalf("Unexpected ExtKeyUsage: got %v, want %v", out.ExtKeyUsage, in.ExtKeyUsage)
+ }
+ if !reflect.DeepEqual(in.UnknownExtKeyUsage, out.UnknownExtKeyUsage) {
+ t.Fatalf("Unexpected UnknownExtKeyUsage: got %v, want %v", out.UnknownExtKeyUsage, in.UnknownExtKeyUsage)
+ }
+ if in.BasicConstraintsValid != out.BasicConstraintsValid {
+ t.Fatalf("Unexpected BasicConstraintsValid: got %v, want %v", out.BasicConstraintsValid, in.BasicConstraintsValid)
+ }
+ if in.IsCA != out.IsCA {
+ t.Fatalf("Unexpected IsCA: got %v, want %v", out.IsCA, in.IsCA)
+ }
+ if in.MaxPathLen != out.MaxPathLen {
+ t.Fatalf("Unexpected MaxPathLen: got %v, want %v", out.MaxPathLen, in.MaxPathLen)
+ }
+ if in.MaxPathLenZero != out.MaxPathLenZero {
+ t.Fatalf("Unexpected MaxPathLenZero: got %v, want %v", out.MaxPathLenZero, in.MaxPathLenZero)
+ }
+ if !reflect.DeepEqual(in.SubjectKeyId, out.SubjectKeyId) {
+ t.Fatalf("Unexpected SubjectKeyId: got %v, want %v", out.SubjectKeyId, in.SubjectKeyId)
+ }
+ if !reflect.DeepEqual(in.PolicyIdentifiers, out.PolicyIdentifiers) {
+ t.Fatalf("Unexpected PolicyIdentifiers: got %v, want %v", out.PolicyIdentifiers, in.PolicyIdentifiers)
+ }
+}