##// END OF EJS Templates
win32: add a method to trigger the Crypto API to complete a certificate chain...
Matt Harbison -
r33492:14af0439 default
parent child Browse files
Show More
@@ -22,6 +22,7 from . import (
22 22 _kernel32 = ctypes.windll.kernel32
23 23 _advapi32 = ctypes.windll.advapi32
24 24 _user32 = ctypes.windll.user32
25 _crypt32 = ctypes.windll.crypt32
25 26
26 27 _BOOL = ctypes.c_long
27 28 _WORD = ctypes.c_ushort
@@ -31,6 +32,7 from . import (
31 32 _LPCSTR = _LPSTR = ctypes.c_char_p
32 33 _HANDLE = ctypes.c_void_p
33 34 _HWND = _HANDLE
35 _PCCERT_CONTEXT = ctypes.c_void_p
34 36
35 37 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
36 38
@@ -134,8 +136,74 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes
134 136 _STD_OUTPUT_HANDLE = _DWORD(-11).value
135 137 _STD_ERROR_HANDLE = _DWORD(-12).value
136 138
139 # CERT_TRUST_STATUS dwErrorStatus
140 CERT_TRUST_IS_PARTIAL_CHAIN = 0x10000
141
142 # CertCreateCertificateContext encodings
143 X509_ASN_ENCODING = 0x00000001
144 PKCS_7_ASN_ENCODING = 0x00010000
145
146 # These structs are only complete enough to achieve what we need.
147 class CERT_CHAIN_CONTEXT(ctypes.Structure):
148 _fields_ = (
149 ("cbSize", _DWORD),
150
151 # CERT_TRUST_STATUS struct
152 ("dwErrorStatus", _DWORD),
153 ("dwInfoStatus", _DWORD),
154
155 ("cChain", _DWORD),
156 ("rgpChain", ctypes.c_void_p),
157 ("cLowerQualityChainContext", _DWORD),
158 ("rgpLowerQualityChainContext", ctypes.c_void_p),
159 ("fHasRevocationFreshnessTime", _BOOL),
160 ("dwRevocationFreshnessTime", _DWORD),
161 )
162
163 class CERT_USAGE_MATCH(ctypes.Structure):
164 _fields_ = (
165 ("dwType", _DWORD),
166
167 # CERT_ENHKEY_USAGE struct
168 ("cUsageIdentifier", _DWORD),
169 ("rgpszUsageIdentifier", ctypes.c_void_p), # LPSTR *
170 )
171
172 class CERT_CHAIN_PARA(ctypes.Structure):
173 _fields_ = (
174 ("cbSize", _DWORD),
175 ("RequestedUsage", CERT_USAGE_MATCH),
176 ("RequestedIssuancePolicy", CERT_USAGE_MATCH),
177 ("dwUrlRetrievalTimeout", _DWORD),
178 ("fCheckRevocationFreshnessTime", _BOOL),
179 ("dwRevocationFreshnessTime", _DWORD),
180 ("pftCacheResync", ctypes.c_void_p), # LPFILETIME
181 ("pStrongSignPara", ctypes.c_void_p), # PCCERT_STRONG_SIGN_PARA
182 ("dwStrongSignFlags", _DWORD),
183 )
184
137 185 # types of parameters of C functions used (required by pypy)
138 186
187 _crypt32.CertCreateCertificateContext.argtypes = [_DWORD, # cert encoding
188 ctypes.c_char_p, # cert
189 _DWORD] # cert size
190 _crypt32.CertCreateCertificateContext.restype = _PCCERT_CONTEXT
191
192 _crypt32.CertGetCertificateChain.argtypes = [
193 ctypes.c_void_p, # HCERTCHAINENGINE
194 _PCCERT_CONTEXT,
195 ctypes.c_void_p, # LPFILETIME
196 ctypes.c_void_p, # HCERTSTORE
197 ctypes.c_void_p, # PCERT_CHAIN_PARA
198 _DWORD,
199 ctypes.c_void_p, # LPVOID
200 ctypes.c_void_p # PCCERT_CHAIN_CONTEXT *
201 ]
202 _crypt32.CertGetCertificateChain.restype = _BOOL
203
204 _crypt32.CertFreeCertificateContext.argtypes = [_PCCERT_CONTEXT]
205 _crypt32.CertFreeCertificateContext.restype = _BOOL
206
139 207 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
140 208 _DWORD, _DWORD, _HANDLE]
141 209 _kernel32.CreateFileA.restype = _HANDLE
@@ -234,6 +302,51 def _getfileinfo(name):
234 302 finally:
235 303 _kernel32.CloseHandle(fh)
236 304
305 def checkcertificatechain(cert, build=True):
306 '''Tests the given certificate to see if there is a complete chain to a
307 trusted root certificate. As a side effect, missing certificates are
308 downloaded and installed unless ``build=False``. True is returned if a
309 chain to a trusted root exists (even if built on the fly), otherwise
310 False. NB: A chain to a trusted root does NOT imply that the certificate
311 is valid.
312 '''
313
314 chainctxptr = ctypes.POINTER(CERT_CHAIN_CONTEXT)
315
316 pchainctx = chainctxptr()
317 chainpara = CERT_CHAIN_PARA(cbSize=ctypes.sizeof(CERT_CHAIN_PARA),
318 RequestedUsage=CERT_USAGE_MATCH())
319
320 certctx = _crypt32.CertCreateCertificateContext(X509_ASN_ENCODING, cert,
321 len(cert))
322 if certctx is None:
323 _raiseoserror('CertCreateCertificateContext')
324
325 flags = 0
326
327 if not build:
328 flags |= 0x100 # CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE
329
330 try:
331 # Building the certificate chain will update root certs as necessary.
332 if not _crypt32.CertGetCertificateChain(None, # hChainEngine
333 certctx, # pCertContext
334 None, # pTime
335 None, # hAdditionalStore
336 ctypes.byref(chainpara),
337 flags,
338 None, # pvReserved
339 ctypes.byref(pchainctx)):
340 _raiseoserror('CertGetCertificateChain')
341
342 chainctx = pchainctx.contents
343
344 return chainctx.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN == 0
345 finally:
346 if pchainctx:
347 _crypt32.CertFreeCertificateChain(pchainctx)
348 _crypt32.CertFreeCertificateContext(certctx)
349
237 350 def oslink(src, dst):
238 351 try:
239 352 if not _kernel32.CreateHardLinkA(dst, src, None):
General Comments 0
You need to be logged in to leave comments. Login now