1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 // Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
14 // certificate store containing itself and all of the intermediate certificates specified
15 // in the opts.Intermediates CertPool.
17 // A pointer to the in-memory store is available in the returned CertContext's Store field.
18 // The store is automatically freed when the CertContext is freed using
19 // syscall.CertFreeCertificateContext.
20 func createStoreContext(leaf
*Certificate
, opts
*VerifyOptions
) (*syscall
.CertContext
, error
) {
21 var storeCtx
*syscall
.CertContext
23 leafCtx
, err
:= syscall
.CertCreateCertificateContext(syscall
.X509_ASN_ENCODING|syscall
.PKCS_7_ASN_ENCODING
, &leaf
.Raw
[0], uint32(len(leaf
.Raw
)))
27 defer syscall
.CertFreeCertificateContext(leafCtx
)
29 handle
, err
:= syscall
.CertOpenStore(syscall
.CERT_STORE_PROV_MEMORY
, 0, 0, syscall
.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG
, 0)
33 defer syscall
.CertCloseStore(handle
, 0)
35 err
= syscall
.CertAddCertificateContextToStore(handle
, leafCtx
, syscall
.CERT_STORE_ADD_ALWAYS
, &storeCtx
)
40 if opts
.Intermediates
!= nil {
41 for _
, intermediate
:= range opts
.Intermediates
.certs
{
42 ctx
, err
:= syscall
.CertCreateCertificateContext(syscall
.X509_ASN_ENCODING|syscall
.PKCS_7_ASN_ENCODING
, &intermediate
.Raw
[0], uint32(len(intermediate
.Raw
)))
47 err
= syscall
.CertAddCertificateContextToStore(handle
, ctx
, syscall
.CERT_STORE_ADD_ALWAYS
, nil)
48 syscall
.CertFreeCertificateContext(ctx
)
58 // extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
59 func extractSimpleChain(simpleChain
**syscall
.CertSimpleChain
, count
int) (chain
[]*Certificate
, err error
) {
60 if simpleChain
== nil || count
== 0 {
61 return nil, errors
.New("x509: invalid simple chain")
64 simpleChains
:= (*[1 << 20]*syscall
.CertSimpleChain
)(unsafe
.Pointer(simpleChain
))[:]
65 lastChain
:= simpleChains
[count
-1]
66 elements
:= (*[1 << 20]*syscall
.CertChainElement
)(unsafe
.Pointer(lastChain
.Elements
))[:]
67 for i
:= 0; i
< int(lastChain
.NumElements
); i
++ {
68 // Copy the buf, since ParseCertificate does not create its own copy.
69 cert
:= elements
[i
].CertContext
70 encodedCert
:= (*[1 << 20]byte)(unsafe
.Pointer(cert
.EncodedCert
))[:]
71 buf
:= make([]byte, cert
.Length
)
72 copy(buf
, encodedCert
[:])
73 parsedCert
, err
:= ParseCertificate(buf
)
77 chain
= append(chain
, parsedCert
)
83 // checkChainTrustStatus checks the trust status of the certificate chain, translating
84 // any errors it finds into Go errors in the process.
85 func checkChainTrustStatus(c
*Certificate
, chainCtx
*syscall
.CertChainContext
) error
{
86 if chainCtx
.TrustStatus
.ErrorStatus
!= syscall
.CERT_TRUST_NO_ERROR
{
87 status
:= chainCtx
.TrustStatus
.ErrorStatus
89 case syscall
.CERT_TRUST_IS_NOT_TIME_VALID
:
90 return CertificateInvalidError
{c
, Expired
}
92 return UnknownAuthorityError
{c
}
98 // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
99 // use as a certificate chain for a SSL/TLS server.
100 func checkChainSSLServerPolicy(c
*Certificate
, chainCtx
*syscall
.CertChainContext
, opts
*VerifyOptions
) error
{
101 servernamep
, err
:= syscall
.UTF16PtrFromString(opts
.DNSName
)
105 sslPara
:= &syscall
.SSLExtraCertChainPolicyPara
{
106 AuthType
: syscall
.AUTHTYPE_SERVER
,
107 ServerName
: servernamep
,
109 sslPara
.Size
= uint32(unsafe
.Sizeof(*sslPara
))
111 para
:= &syscall
.CertChainPolicyPara
{
112 ExtraPolicyPara
: uintptr(unsafe
.Pointer(sslPara
)),
114 para
.Size
= uint32(unsafe
.Sizeof(*para
))
116 status
:= syscall
.CertChainPolicyStatus
{}
117 err
= syscall
.CertVerifyCertificateChainPolicy(syscall
.CERT_CHAIN_POLICY_SSL
, chainCtx
, para
, &status
)
122 // TODO(mkrautz): use the lChainIndex and lElementIndex fields
123 // of the CertChainPolicyStatus to provide proper context, instead
125 if status
.Error
!= 0 {
126 switch status
.Error
{
127 case syscall
.CERT_E_EXPIRED
:
128 return CertificateInvalidError
{c
, Expired
}
129 case syscall
.CERT_E_CN_NO_MATCH
:
130 return HostnameError
{c
, opts
.DNSName
}
131 case syscall
.CERT_E_UNTRUSTEDROOT
:
132 return UnknownAuthorityError
{c
}
134 return UnknownAuthorityError
{c
}
141 // systemVerify is like Verify, except that it uses CryptoAPI calls
142 // to build certificate chains and verify them.
143 func (c
*Certificate
) systemVerify(opts
*VerifyOptions
) (chains
[][]*Certificate
, err error
) {
144 hasDNSName
:= opts
!= nil && len(opts
.DNSName
) > 0
146 storeCtx
, err
:= createStoreContext(c
, opts
)
150 defer syscall
.CertFreeCertificateContext(storeCtx
)
152 para
:= new(syscall
.CertChainPara
)
153 para
.Size
= uint32(unsafe
.Sizeof(*para
))
155 // If there's a DNSName set in opts, assume we're verifying
156 // a certificate from a TLS server.
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 para
.RequestedUsage
.Type
= syscall
.USAGE_MATCH_TYPE_OR
167 para
.RequestedUsage
.Usage
.Length
= uint32(len(oids
))
168 para
.RequestedUsage
.Usage
.UsageIdentifiers
= &oids
[0]
170 para
.RequestedUsage
.Type
= syscall
.USAGE_MATCH_TYPE_AND
171 para
.RequestedUsage
.Usage
.Length
= 0
172 para
.RequestedUsage
.Usage
.UsageIdentifiers
= nil
175 var verifyTime
*syscall
.Filetime
176 if opts
!= nil && !opts
.CurrentTime
.IsZero() {
177 ft
:= syscall
.NsecToFiletime(opts
.CurrentTime
.UnixNano())
181 // CertGetCertificateChain will traverse Windows's root stores
182 // in an attempt to build a verified certificate chain. Once
183 // it has found a verified chain, it stops. MSDN docs on
184 // CERT_CHAIN_CONTEXT:
186 // When a CERT_CHAIN_CONTEXT is built, the first simple chain
187 // begins with an end certificate and ends with a self-signed
188 // certificate. If that self-signed certificate is not a root
189 // or otherwise trusted certificate, an attempt is made to
190 // build a new chain. CTLs are used to create the new chain
191 // beginning with the self-signed certificate from the original
192 // chain as the end certificate of the new chain. This process
193 // continues building additional simple chains until the first
194 // self-signed certificate is a trusted certificate or until
195 // an additional simple chain cannot be built.
197 // The result is that we'll only get a single trusted chain to
198 // return to our caller.
199 var chainCtx
*syscall
.CertChainContext
200 err
= syscall
.CertGetCertificateChain(syscall
.Handle(0), storeCtx
, verifyTime
, storeCtx
.Store
, para
, 0, 0, &chainCtx
)
204 defer syscall
.CertFreeCertificateChain(chainCtx
)
206 err
= checkChainTrustStatus(c
, chainCtx
)
212 err
= checkChainSSLServerPolicy(c
, chainCtx
, opts
)
218 chain
, err
:= extractSimpleChain(chainCtx
.Chains
, int(chainCtx
.ChainCount
))
223 chains
= append(chains
, chain
)
228 func initSystemRoots() {