diff options
Diffstat (limited to 'src/crypto/x509/root_windows.go')
-rw-r--r-- | src/crypto/x509/root_windows.go | 46 |
1 files changed, 33 insertions, 13 deletions
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go index ebf159c178..94669f229e 100644 --- a/src/crypto/x509/root_windows.go +++ b/src/crypto/x509/root_windows.go @@ -88,6 +88,9 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e switch status { case syscall.CERT_TRUST_IS_NOT_TIME_VALID: return CertificateInvalidError{c, Expired, ""} + case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE: + return CertificateInvalidError{c, IncompatibleUsage, ""} + // TODO(filippo): surface more error statuses. default: return UnknownAuthorityError{c, nil, nil} } @@ -138,11 +141,19 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex return nil } +// windowsExtKeyUsageOIDs are the C NUL-terminated string representations of the +// OIDs for use with the Windows API. +var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs)) + +func init() { + for _, eku := range extKeyUsageOIDs { + windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00") + } +} + // 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) { - hasDNSName := opts != nil && len(opts.DNSName) > 0 - storeCtx, err := createStoreContext(c, opts) if err != nil { return nil, err @@ -152,17 +163,26 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate para := new(syscall.CertChainPara) para.Size = uint32(unsafe.Sizeof(*para)) - // If there's a DNSName set in opts, assume we're verifying - // a certificate from a TLS server. - if hasDNSName { - oids := []*byte{ - &syscall.OID_PKIX_KP_SERVER_AUTH[0], - // Both IE and Chrome allow certificates with - // Server Gated Crypto as well. Some certificates - // in the wild require them. - &syscall.OID_SERVER_GATED_CRYPTO[0], - &syscall.OID_SGC_NETSCAPE[0], + keyUsages := opts.KeyUsages + if len(keyUsages) == 0 { + keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} + } + oids := make([]*byte, 0, len(keyUsages)) + for _, eku := range keyUsages { + if eku == ExtKeyUsageAny { + oids = nil + break + } + if oid, ok := windowsExtKeyUsageOIDs[eku]; ok { + oids = append(oids, &oid[0]) } + // Like the standard verifier, accept SGC EKUs as equivalent to ServerAuth. + if eku == ExtKeyUsageServerAuth { + oids = append(oids, &syscall.OID_SERVER_GATED_CRYPTO[0]) + oids = append(oids, &syscall.OID_SGC_NETSCAPE[0]) + } + } + if oids != nil { para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR para.RequestedUsage.Usage.Length = uint32(len(oids)) para.RequestedUsage.Usage.UsageIdentifiers = &oids[0] @@ -208,7 +228,7 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate return nil, err } - if hasDNSName { + if opts != nil && len(opts.DNSName) > 0 { err = checkChainSSLServerPolicy(c, chainCtx, opts) if err != nil { return nil, err |