Source file
src/crypto/x509/root_windows.go
1
2
3
4
5 package x509
6
7 import (
8 "errors"
9 "syscall"
10 "unsafe"
11 )
12
13
14
15
16
17
18
19
20 func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
21 var storeCtx *syscall.CertContext
22
23 leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
24 if err != nil {
25 return nil, err
26 }
27 defer syscall.CertFreeCertificateContext(leafCtx)
28
29 handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
30 if err != nil {
31 return nil, err
32 }
33 defer syscall.CertCloseStore(handle, 0)
34
35 err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
36 if err != nil {
37 return nil, err
38 }
39
40 if opts.Intermediates != nil {
41 for i := 0; i < opts.Intermediates.len(); i++ {
42 intermediate, err := opts.Intermediates.cert(i)
43 if err != nil {
44 return nil, err
45 }
46 ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
47 if err != nil {
48 return nil, err
49 }
50
51 err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
52 syscall.CertFreeCertificateContext(ctx)
53 if err != nil {
54 return nil, err
55 }
56 }
57 }
58
59 return storeCtx, nil
60 }
61
62
63 func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
64 if simpleChain == nil || count == 0 {
65 return nil, errors.New("x509: invalid simple chain")
66 }
67
68 simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:count:count]
69 lastChain := simpleChains[count-1]
70 elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:lastChain.NumElements:lastChain.NumElements]
71 for i := 0; i < int(lastChain.NumElements); i++ {
72
73 cert := elements[i].CertContext
74 encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length:cert.Length]
75 buf := make([]byte, cert.Length)
76 copy(buf, encodedCert)
77 parsedCert, err := ParseCertificate(buf)
78 if err != nil {
79 return nil, err
80 }
81 chain = append(chain, parsedCert)
82 }
83
84 return chain, nil
85 }
86
87
88
89 func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
90 if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
91 status := chainCtx.TrustStatus.ErrorStatus
92 switch status {
93 case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
94 return CertificateInvalidError{c, Expired, ""}
95 case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
96 return CertificateInvalidError{c, IncompatibleUsage, ""}
97
98 default:
99 return UnknownAuthorityError{c, nil, nil}
100 }
101 }
102 return nil
103 }
104
105
106
107 func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
108 servernamep, err := syscall.UTF16PtrFromString(opts.DNSName)
109 if err != nil {
110 return err
111 }
112 sslPara := &syscall.SSLExtraCertChainPolicyPara{
113 AuthType: syscall.AUTHTYPE_SERVER,
114 ServerName: servernamep,
115 }
116 sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
117
118 para := &syscall.CertChainPolicyPara{
119 ExtraPolicyPara: (syscall.Pointer)(unsafe.Pointer(sslPara)),
120 }
121 para.Size = uint32(unsafe.Sizeof(*para))
122
123 status := syscall.CertChainPolicyStatus{}
124 err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
125 if err != nil {
126 return err
127 }
128
129
130
131
132 if status.Error != 0 {
133 switch status.Error {
134 case syscall.CERT_E_EXPIRED:
135 return CertificateInvalidError{c, Expired, ""}
136 case syscall.CERT_E_CN_NO_MATCH:
137 return HostnameError{c, opts.DNSName}
138 case syscall.CERT_E_UNTRUSTEDROOT:
139 return UnknownAuthorityError{c, nil, nil}
140 default:
141 return UnknownAuthorityError{c, nil, nil}
142 }
143 }
144
145 return nil
146 }
147
148
149
150 var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs))
151
152 func init() {
153 for _, eku := range extKeyUsageOIDs {
154 windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00")
155 }
156 }
157
158 func verifyChain(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) (chain []*Certificate, err error) {
159 err = checkChainTrustStatus(c, chainCtx)
160 if err != nil {
161 return nil, err
162 }
163
164 if opts != nil && len(opts.DNSName) > 0 {
165 err = checkChainSSLServerPolicy(c, chainCtx, opts)
166 if err != nil {
167 return nil, err
168 }
169 }
170
171 chain, err = extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
172 if err != nil {
173 return nil, err
174 }
175 if len(chain) == 0 {
176 return nil, errors.New("x509: internal error: system verifier returned an empty chain")
177 }
178
179
180
181
182
183
184 for i, parent := range chain[1:] {
185 if parent.PublicKeyAlgorithm != ECDSA {
186 continue
187 }
188 if err := parent.CheckSignature(chain[i].SignatureAlgorithm,
189 chain[i].RawTBSCertificate, chain[i].Signature); err != nil {
190 return nil, err
191 }
192 }
193 return chain, nil
194 }
195
196
197
198 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
199 storeCtx, err := createStoreContext(c, opts)
200 if err != nil {
201 return nil, err
202 }
203 defer syscall.CertFreeCertificateContext(storeCtx)
204
205 para := new(syscall.CertChainPara)
206 para.Size = uint32(unsafe.Sizeof(*para))
207
208 keyUsages := opts.KeyUsages
209 if len(keyUsages) == 0 {
210 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
211 }
212 oids := make([]*byte, 0, len(keyUsages))
213 for _, eku := range keyUsages {
214 if eku == ExtKeyUsageAny {
215 oids = nil
216 break
217 }
218 if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
219 oids = append(oids, &oid[0])
220 }
221
222 if eku == ExtKeyUsageServerAuth {
223 oids = append(oids, &syscall.OID_SERVER_GATED_CRYPTO[0])
224 oids = append(oids, &syscall.OID_SGC_NETSCAPE[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 := (*[1 << 20]*syscall.CertChainContext)(unsafe.Pointer(topCtx.LowerQualityChains))[:lqCtxCount:lqCtxCount]
263
264 for _, ctx := range lqCtxs {
265 chain, err := verifyChain(c, ctx, opts)
266 if err == nil {
267 chains = append(chains, chain)
268 }
269 }
270 }
271
272 if len(chains) == 0 {
273
274 return nil, topErr
275 }
276
277 return chains, nil
278 }
279
280 func loadSystemRoots() (*CertPool, error) {
281
282
283
284
285
286 if true {
287 return nil, nil
288 }
289
290 const CRYPT_E_NOT_FOUND = 0x80092004
291
292 store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
293 if err != nil {
294 return nil, err
295 }
296 defer syscall.CertCloseStore(store, 0)
297
298 roots := NewCertPool()
299 var cert *syscall.CertContext
300 for {
301 cert, err = syscall.CertEnumCertificatesInStore(store, cert)
302 if err != nil {
303 if errno, ok := err.(syscall.Errno); ok {
304 if errno == CRYPT_E_NOT_FOUND {
305 break
306 }
307 }
308 return nil, err
309 }
310 if cert == nil {
311 break
312 }
313
314 buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length:cert.Length]
315 buf2 := make([]byte, cert.Length)
316 copy(buf2, buf)
317 if c, err := ParseCertificate(buf2); err == nil {
318 roots.AddCert(c)
319 }
320 }
321 return roots, nil
322 }
323
View as plain text