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 _, 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)))
43 if err != nil {
44 return nil, err
45 }
46
47 err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
48 syscall.CertFreeCertificateContext(ctx)
49 if err != nil {
50 return nil, err
51 }
52 }
53 }
54
55 return storeCtx, nil
56 }
57
58
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")
62 }
63
64 simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:count:count]
65 lastChain := simpleChains[count-1]
66 elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:lastChain.NumElements:lastChain.NumElements]
67 for i := 0; i < int(lastChain.NumElements); i++ {
68
69 cert := elements[i].CertContext
70 encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length:cert.Length]
71 buf := make([]byte, cert.Length)
72 copy(buf, encodedCert)
73 parsedCert, err := ParseCertificate(buf)
74 if err != nil {
75 return nil, err
76 }
77 chain = append(chain, parsedCert)
78 }
79
80 return chain, nil
81 }
82
83
84
85 func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
86 if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
87 status := chainCtx.TrustStatus.ErrorStatus
88 switch status {
89 case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
90 return CertificateInvalidError{c, Expired, ""}
91 default:
92 return UnknownAuthorityError{c, nil, nil}
93 }
94 }
95 return nil
96 }
97
98
99
100 func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
101 servernamep, err := syscall.UTF16PtrFromString(opts.DNSName)
102 if err != nil {
103 return err
104 }
105 sslPara := &syscall.SSLExtraCertChainPolicyPara{
106 AuthType: syscall.AUTHTYPE_SERVER,
107 ServerName: servernamep,
108 }
109 sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
110
111 para := &syscall.CertChainPolicyPara{
112 ExtraPolicyPara: convertToPolicyParaType(unsafe.Pointer(sslPara)),
113 }
114 para.Size = uint32(unsafe.Sizeof(*para))
115
116 status := syscall.CertChainPolicyStatus{}
117 err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
118 if err != nil {
119 return err
120 }
121
122
123
124
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, nil, nil}
133 default:
134 return UnknownAuthorityError{c, nil, nil}
135 }
136 }
137
138 return nil
139 }
140
141
142
143 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
144 hasDNSName := opts != nil && len(opts.DNSName) > 0
145
146 storeCtx, err := createStoreContext(c, opts)
147 if err != nil {
148 return nil, err
149 }
150 defer syscall.CertFreeCertificateContext(storeCtx)
151
152 para := new(syscall.CertChainPara)
153 para.Size = uint32(unsafe.Sizeof(*para))
154
155
156
157 if hasDNSName {
158 oids := []*byte{
159 &syscall.OID_PKIX_KP_SERVER_AUTH[0],
160
161
162
163 &syscall.OID_SERVER_GATED_CRYPTO[0],
164 &syscall.OID_SGC_NETSCAPE[0],
165 }
166 para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
167 para.RequestedUsage.Usage.Length = uint32(len(oids))
168 para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
169 } else {
170 para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
171 para.RequestedUsage.Usage.Length = 0
172 para.RequestedUsage.Usage.UsageIdentifiers = nil
173 }
174
175 var verifyTime *syscall.Filetime
176 if opts != nil && !opts.CurrentTime.IsZero() {
177 ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
178 verifyTime = &ft
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 var chainCtx *syscall.CertChainContext
200 err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
201 if err != nil {
202 return nil, err
203 }
204 defer syscall.CertFreeCertificateChain(chainCtx)
205
206 err = checkChainTrustStatus(c, chainCtx)
207 if err != nil {
208 return nil, err
209 }
210
211 if hasDNSName {
212 err = checkChainSSLServerPolicy(c, chainCtx, opts)
213 if err != nil {
214 return nil, err
215 }
216 }
217
218 chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
219 if err != nil {
220 return nil, err
221 }
222 if len(chain) < 1 {
223 return nil, errors.New("x509: internal error: system verifier returned an empty chain")
224 }
225
226
227
228
229
230
231 for i, parent := range chain[1:] {
232 if parent.PublicKeyAlgorithm != ECDSA {
233 continue
234 }
235 if err := parent.CheckSignature(chain[i].SignatureAlgorithm,
236 chain[i].RawTBSCertificate, chain[i].Signature); err != nil {
237 return nil, err
238 }
239 }
240
241 return [][]*Certificate{chain}, nil
242 }
243
244 func loadSystemRoots() (*CertPool, error) {
245
246
247
248
249
250 if true {
251 return nil, nil
252 }
253
254 const CRYPT_E_NOT_FOUND = 0x80092004
255
256 store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
257 if err != nil {
258 return nil, err
259 }
260 defer syscall.CertCloseStore(store, 0)
261
262 roots := NewCertPool()
263 var cert *syscall.CertContext
264 for {
265 cert, err = syscall.CertEnumCertificatesInStore(store, cert)
266 if err != nil {
267 if errno, ok := err.(syscall.Errno); ok {
268 if errno == CRYPT_E_NOT_FOUND {
269 break
270 }
271 }
272 return nil, err
273 }
274 if cert == nil {
275 break
276 }
277
278 buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length:cert.Length]
279 buf2 := make([]byte, cert.Length)
280 copy(buf2, buf)
281 if c, err := ParseCertificate(buf2); err == nil {
282 roots.AddCert(c)
283 }
284 }
285 return roots, nil
286 }
287
View as plain text