Source file
src/crypto/x509/root_windows.go
1
2
3
4
5 package x509
6
7 import (
8 "bytes"
9 "errors"
10 "strings"
11 "syscall"
12 "unsafe"
13 )
14
15 func loadSystemRoots() (*CertPool, error) {
16 return &CertPool{systemPool: true}, nil
17 }
18
19
20
21
22
23
24
25
26 func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
27 var storeCtx *syscall.CertContext
28
29 leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
30 if err != nil {
31 return nil, err
32 }
33 defer syscall.CertFreeCertificateContext(leafCtx)
34
35 handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
36 if err != nil {
37 return nil, err
38 }
39 defer syscall.CertCloseStore(handle, 0)
40
41 err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
42 if err != nil {
43 return nil, err
44 }
45
46 if opts.Intermediates != nil {
47 for i := 0; i < opts.Intermediates.len(); i++ {
48 intermediate, _, err := opts.Intermediates.cert(i)
49 if err != nil {
50 return nil, err
51 }
52 ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
53 if err != nil {
54 return nil, err
55 }
56
57 err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
58 syscall.CertFreeCertificateContext(ctx)
59 if err != nil {
60 return nil, err
61 }
62 }
63 }
64
65 return storeCtx, nil
66 }
67
68
69 func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
70 if simpleChain == nil || count == 0 {
71 return nil, errors.New("x509: invalid simple chain")
72 }
73
74 simpleChains := unsafe.Slice(simpleChain, count)
75 lastChain := simpleChains[count-1]
76 elements := unsafe.Slice(lastChain.Elements, lastChain.NumElements)
77 for i := 0; i < int(lastChain.NumElements); i++ {
78
79 cert := elements[i].CertContext
80 encodedCert := unsafe.Slice(cert.EncodedCert, cert.Length)
81 buf := bytes.Clone(encodedCert)
82 parsedCert, err := ParseCertificate(buf)
83 if err != nil {
84 return nil, err
85 }
86 chain = append(chain, parsedCert)
87 }
88
89 return chain, nil
90 }
91
92
93
94 func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
95 if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
96 status := chainCtx.TrustStatus.ErrorStatus
97 switch status {
98 case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
99 return CertificateInvalidError{c, Expired, ""}
100 case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
101 return CertificateInvalidError{c, IncompatibleUsage, ""}
102
103 default:
104 return UnknownAuthorityError{c, nil, nil}
105 }
106 }
107 return nil
108 }
109
110
111
112 func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
113 servernamep, err := syscall.UTF16PtrFromString(strings.TrimSuffix(opts.DNSName, "."))
114 if err != nil {
115 return err
116 }
117 sslPara := &syscall.SSLExtraCertChainPolicyPara{
118 AuthType: syscall.AUTHTYPE_SERVER,
119 ServerName: servernamep,
120 }
121 sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
122
123 para := &syscall.CertChainPolicyPara{
124 ExtraPolicyPara: (syscall.Pointer)(unsafe.Pointer(sslPara)),
125 }
126 para.Size = uint32(unsafe.Sizeof(*para))
127
128 status := syscall.CertChainPolicyStatus{}
129 err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
130 if err != nil {
131 return err
132 }
133
134
135
136
137 if status.Error != 0 {
138 switch status.Error {
139 case syscall.CERT_E_EXPIRED:
140 return CertificateInvalidError{c, Expired, ""}
141 case syscall.CERT_E_CN_NO_MATCH:
142 return HostnameError{c, opts.DNSName}
143 case syscall.CERT_E_UNTRUSTEDROOT:
144 return UnknownAuthorityError{c, nil, nil}
145 default:
146 return UnknownAuthorityError{c, nil, nil}
147 }
148 }
149
150 return nil
151 }
152
153
154
155 var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs))
156
157 func init() {
158 for _, eku := range extKeyUsageOIDs {
159 windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00")
160 }
161 }
162
163 func verifyChain(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) (chain []*Certificate, err error) {
164 err = checkChainTrustStatus(c, chainCtx)
165 if err != nil {
166 return nil, err
167 }
168
169 if opts != nil && len(opts.DNSName) > 0 {
170 err = checkChainSSLServerPolicy(c, chainCtx, opts)
171 if err != nil {
172 return nil, err
173 }
174 }
175
176 chain, err = extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
177 if err != nil {
178 return nil, err
179 }
180 if len(chain) == 0 {
181 return nil, errors.New("x509: internal error: system verifier returned an empty chain")
182 }
183
184
185
186
187
188
189 for i, parent := range chain[1:] {
190 if parent.PublicKeyAlgorithm != ECDSA {
191 continue
192 }
193 if err := parent.CheckSignature(chain[i].SignatureAlgorithm,
194 chain[i].RawTBSCertificate, chain[i].Signature); err != nil {
195 return nil, err
196 }
197 }
198 return chain, nil
199 }
200
201
202
203 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
204 storeCtx, err := createStoreContext(c, opts)
205 if err != nil {
206 return nil, err
207 }
208 defer syscall.CertFreeCertificateContext(storeCtx)
209
210 para := new(syscall.CertChainPara)
211 para.Size = uint32(unsafe.Sizeof(*para))
212
213 keyUsages := opts.KeyUsages
214 if len(keyUsages) == 0 {
215 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
216 }
217 oids := make([]*byte, 0, len(keyUsages))
218 for _, eku := range keyUsages {
219 if eku == ExtKeyUsageAny {
220 oids = nil
221 break
222 }
223 if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
224 oids = append(oids, &oid[0])
225 }
226 }
227 if oids != nil {
228 para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
229 para.RequestedUsage.Usage.Length = uint32(len(oids))
230 para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
231 } else {
232 para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
233 para.RequestedUsage.Usage.Length = 0
234 para.RequestedUsage.Usage.UsageIdentifiers = nil
235 }
236
237 var verifyTime *syscall.Filetime
238 if opts != nil && !opts.CurrentTime.IsZero() {
239 ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
240 verifyTime = &ft
241 }
242
243
244
245
246 const CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS = 0x00000080
247
248
249 var topCtx *syscall.CertChainContext
250 err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS, 0, &topCtx)
251 if err != nil {
252 return nil, err
253 }
254 defer syscall.CertFreeCertificateChain(topCtx)
255
256 chain, topErr := verifyChain(c, topCtx, opts)
257 if topErr == nil {
258 chains = append(chains, chain)
259 }
260
261 if lqCtxCount := topCtx.LowerQualityChainCount; lqCtxCount > 0 {
262 lqCtxs := unsafe.Slice(topCtx.LowerQualityChains, lqCtxCount)
263 for _, ctx := range lqCtxs {
264 chain, err := verifyChain(c, ctx, opts)
265 if err == nil {
266 chains = append(chains, chain)
267 }
268 }
269 }
270
271 if len(chains) == 0 {
272
273 return nil, topErr
274 }
275
276 return chains, nil
277 }
278
View as plain text