Show More
@@ -22,6 +22,7 b' 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 b' 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 b' 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 b' 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