Skip to content

Commit 4a4c8d3

Browse files
FiloSottilekatiehockman
authored andcommitted
[release-branch.go1.13-security] crypto/x509: respect VerifyOptions.KeyUsages on Windows
When using the platform verifier on Windows (because Roots is nil) we were always enforcing server auth EKUs if DNSName was set, and none otherwise. If an application was setting KeyUsages, they were not being respected. Started correctly surfacing IncompatibleUsage errors from the system verifier, as those are the ones applications will see if they are affected by this change. Also refactored verify_test.go to make it easier to add tests for this, and replaced the EKULeaf chain with a new one that doesn't have a SHA-1 signature. Thanks to Niall Newman for reporting this. Fixes #39360 Fixes CVE-2020-14039 Change-Id: If5c00d615f2944f7d57007891aae1307f9571c32 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/774414 Reviewed-by: Katie Hockman <[email protected]> Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/793509 Reviewed-by: Filippo Valsorda <[email protected]>
1 parent e434185 commit 4a4c8d3

File tree

3 files changed

+430
-548
lines changed

3 files changed

+430
-548
lines changed

src/crypto/x509/root_windows.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
8888
switch status {
8989
case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
9090
return CertificateInvalidError{c, Expired, ""}
91+
case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
92+
return CertificateInvalidError{c, IncompatibleUsage, ""}
93+
// TODO(filippo): surface more error statuses.
9194
default:
9295
return UnknownAuthorityError{c, nil, nil}
9396
}
@@ -138,11 +141,19 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
138141
return nil
139142
}
140143

144+
// windowsExtKeyUsageOIDs are the C NUL-terminated string representations of the
145+
// OIDs for use with the Windows API.
146+
var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs))
147+
148+
func init() {
149+
for _, eku := range extKeyUsageOIDs {
150+
windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00")
151+
}
152+
}
153+
141154
// systemVerify is like Verify, except that it uses CryptoAPI calls
142155
// to build certificate chains and verify them.
143156
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
144-
hasDNSName := opts != nil && len(opts.DNSName) > 0
145-
146157
storeCtx, err := createStoreContext(c, opts)
147158
if err != nil {
148159
return nil, err
@@ -152,17 +163,26 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
152163
para := new(syscall.CertChainPara)
153164
para.Size = uint32(unsafe.Sizeof(*para))
154165

155-
// If there's a DNSName set in opts, assume we're verifying
156-
// a certificate from a TLS server.
157-
if hasDNSName {
158-
oids := []*byte{
159-
&syscall.OID_PKIX_KP_SERVER_AUTH[0],
160-
// Both IE and Chrome allow certificates with
161-
// Server Gated Crypto as well. Some certificates
162-
// in the wild require them.
163-
&syscall.OID_SERVER_GATED_CRYPTO[0],
164-
&syscall.OID_SGC_NETSCAPE[0],
166+
keyUsages := opts.KeyUsages
167+
if len(keyUsages) == 0 {
168+
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
169+
}
170+
oids := make([]*byte, 0, len(keyUsages))
171+
for _, eku := range keyUsages {
172+
if eku == ExtKeyUsageAny {
173+
oids = nil
174+
break
175+
}
176+
if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
177+
oids = append(oids, &oid[0])
165178
}
179+
// Like the standard verifier, accept SGC EKUs as equivalent to ServerAuth.
180+
if eku == ExtKeyUsageServerAuth {
181+
oids = append(oids, &syscall.OID_SERVER_GATED_CRYPTO[0])
182+
oids = append(oids, &syscall.OID_SGC_NETSCAPE[0])
183+
}
184+
}
185+
if oids != nil {
166186
para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
167187
para.RequestedUsage.Usage.Length = uint32(len(oids))
168188
para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
@@ -208,7 +228,7 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
208228
return nil, err
209229
}
210230

211-
if hasDNSName {
231+
if opts != nil && len(opts.DNSName) > 0 {
212232
err = checkChainSSLServerPolicy(c, chainCtx, opts)
213233
if err != nil {
214234
return nil, err

src/crypto/x509/verify.go

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -188,23 +188,32 @@ var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificat
188188
// VerifyOptions contains parameters for Certificate.Verify. It's a structure
189189
// because other PKIX verification APIs have ended up needing many options.
190190
type VerifyOptions struct {
191-
DNSName string
191+
// DNSName, if set, is checked against the leaf certificate with
192+
// Certificate.VerifyHostname or the platform verifier.
193+
DNSName string
194+
195+
// Intermediates is an optional pool of certificates that are not trust
196+
// anchors, but can be used to form a chain from the leaf certificate to a
197+
// root certificate.
192198
Intermediates *CertPool
193-
Roots *CertPool // if nil, the system roots are used
194-
CurrentTime time.Time // if zero, the current time is used
195-
// KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
196-
// certificate is accepted if it contains any of the listed values. An empty
197-
// list means ExtKeyUsageServerAuth. To accept any key usage, include
198-
// ExtKeyUsageAny.
199-
//
200-
// Certificate chains are required to nest these extended key usage values.
201-
// (This matches the Windows CryptoAPI behavior, but not the spec.)
199+
// Roots is the set of trusted root certificates the leaf certificate needs
200+
// to chain up to. If nil, the system roots or the platform verifier are used.
201+
Roots *CertPool
202+
203+
// CurrentTime is used to check the validity of all certificates in the
204+
// chain. If zero, the current time is used.
205+
CurrentTime time.Time
206+
207+
// KeyUsages specifies which Extended Key Usage values are acceptable. A
208+
// chain is accepted if it allows any of the listed values. An empty list
209+
// means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny.
202210
KeyUsages []ExtKeyUsage
211+
203212
// MaxConstraintComparisions is the maximum number of comparisons to
204213
// perform when checking a given certificate's name constraints. If
205214
// zero, a sensible default is used. This limit prevents pathological
206215
// certificates from consuming excessive amounts of CPU time when
207-
// validating.
216+
// validating. It does not apply to the platform verifier.
208217
MaxConstraintComparisions int
209218
}
210219

@@ -707,18 +716,21 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
707716
// needed. If successful, it returns one or more chains where the first
708717
// element of the chain is c and the last element is from opts.Roots.
709718
//
710-
// If opts.Roots is nil and system roots are unavailable the returned error
711-
// will be of type SystemRootsError.
719+
// If opts.Roots is nil, the platform verifier might be used, and
720+
// verification details might differ from what is described below. If system
721+
// roots are unavailable the returned error will be of type SystemRootsError.
712722
//
713723
// Name constraints in the intermediates will be applied to all names claimed
714724
// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
715725
// example.com if an intermediate doesn't permit it, even if example.com is not
716726
// the name being validated. Note that DirectoryName constraints are not
717727
// supported.
718728
//
719-
// Extended Key Usage values are enforced down a chain, so an intermediate or
720-
// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
721-
// list.
729+
//
730+
// Extended Key Usage values are enforced nested down a chain, so an intermediate
731+
// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
732+
// list. (While this is not specified, it is common practice in order to limit
733+
// the types of certificates a CA can issue.)
722734
//
723735
// WARNING: this function doesn't do any revocation checking.
724736
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {

0 commit comments

Comments
 (0)