Alessandro Pilotti 7bf618155a Fixes WinRM listener plugin x509 end time
The end date assigned to the x509 certifciate in use for the WinRM
HTTPS listener is not properly computed, resulting in issues during
leap days. This patch solves the issue by employing the appropriate
Win32 API.

Closes-Bug: #1551211

Change-Id: Ib36a2db58634caba4282f19a0386191ca33a4168
2016-02-29 20:29:01 +02:00

246 lines
8.8 KiB
Python

# Copyright 2013 Cloudbase Solutions Srl
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from ctypes import windll
from ctypes import wintypes
class CryptoAPIException(Exception):
def __init__(self):
message = self._get_windows_error()
super(CryptoAPIException, self).__init__(message)
def _get_windows_error(self):
err_code = GetLastError()
return "CryptoAPI error: 0x%0x" % err_code
class SYSTEMTIME(ctypes.Structure):
_fields_ = [
('wYear', wintypes.WORD),
('wMonth', wintypes.WORD),
('wDayOfWeek', wintypes.WORD),
('wDay', wintypes.WORD),
('wHour', wintypes.WORD),
('wMinute', wintypes.WORD),
('wSecond', wintypes.WORD),
('wMilliseconds', wintypes.WORD),
]
class FILETIME(ctypes.Structure):
_fields_ = [
('dwLowDateTime', wintypes.DWORD),
('dwHighDateTime', wintypes.DWORD),
]
class CERT_CONTEXT(ctypes.Structure):
_fields_ = [
('dwCertEncodingType', wintypes.DWORD),
('pbCertEncoded', ctypes.POINTER(wintypes.BYTE)),
('cbCertEncoded', wintypes.DWORD),
('pCertInfo', ctypes.c_void_p),
('hCertStore', wintypes.HANDLE),
]
class CRYPTOAPI_BLOB(ctypes.Structure):
_fields_ = [
('cbData', wintypes.DWORD),
('pbData', ctypes.POINTER(wintypes.BYTE)),
]
class CRYPT_ALGORITHM_IDENTIFIER(ctypes.Structure):
_fields_ = [
('pszObjId', wintypes.LPSTR),
('Parameters', CRYPTOAPI_BLOB),
]
class CRYPT_KEY_PROV_PARAM(ctypes.Structure):
_fields_ = [
('dwParam', wintypes.DWORD),
('pbData', ctypes.POINTER(wintypes.BYTE)),
('cbData', wintypes.DWORD),
('dwFlags', wintypes.DWORD),
]
class CRYPT_KEY_PROV_INFO(ctypes.Structure):
_fields_ = [
('pwszContainerName', wintypes.LPWSTR),
('pwszProvName', wintypes.LPWSTR),
('dwProvType', wintypes.DWORD),
('dwFlags', wintypes.DWORD),
('cProvParam', wintypes.DWORD),
('cProvParam', ctypes.POINTER(CRYPT_KEY_PROV_PARAM)),
('dwKeySpec', wintypes.DWORD),
]
AT_SIGNATURE = 2
CERT_NAME_UPN_TYPE = 8
CERT_SHA1_HASH_PROP_ID = 3
CERT_STORE_ADD_REPLACE_EXISTING = 3
CERT_STORE_PROV_SYSTEM = wintypes.LPSTR(10)
CERT_SYSTEM_STORE_CURRENT_USER = 65536
CERT_SYSTEM_STORE_LOCAL_MACHINE = 131072
CERT_X500_NAME_STR = 3
CRYPT_MACHINE_KEYSET = 32
CRYPT_NEWKEYSET = 8
CRYPT_STRING_BASE64 = 1
PKCS_7_ASN_ENCODING = 65536
PROV_RSA_FULL = 1
X509_ASN_ENCODING = 1
szOID_PKIX_KP_SERVER_AUTH = b"1.3.6.1.5.5.7.3.1"
szOID_RSA_SHA1RSA = b"1.2.840.113549.1.1.5"
advapi32 = windll.advapi32
crypt32 = windll.crypt32
kernel32 = windll.kernel32
advapi32.CryptAcquireContextW.restype = wintypes.BOOL
advapi32.CryptAcquireContextW.argtypes = [wintypes.HANDLE, wintypes.LPCWSTR,
wintypes.LPCWSTR, wintypes.DWORD,
wintypes.DWORD]
CryptAcquireContext = advapi32.CryptAcquireContextW
advapi32.CryptReleaseContext.restype = wintypes.BOOL
advapi32.CryptReleaseContext.argtypes = [wintypes.HANDLE, wintypes.DWORD]
CryptReleaseContext = advapi32.CryptReleaseContext
advapi32.CryptGenKey.restype = wintypes.BOOL
advapi32.CryptGenKey.argtypes = [wintypes.HANDLE,
wintypes.DWORD,
wintypes.DWORD,
ctypes.POINTER(wintypes.HANDLE)]
CryptGenKey = advapi32.CryptGenKey
advapi32.CryptDestroyKey.restype = wintypes.BOOL
advapi32.CryptDestroyKey.argtypes = [wintypes.HANDLE]
CryptDestroyKey = advapi32.CryptDestroyKey
crypt32.CertStrToNameW.restype = wintypes.BOOL
crypt32.CertStrToNameW.argtypes = [wintypes.DWORD, wintypes.LPCWSTR,
wintypes.DWORD, ctypes.c_void_p,
ctypes.POINTER(wintypes.BYTE),
ctypes.POINTER(wintypes.DWORD),
ctypes.POINTER(wintypes.LPCWSTR)]
CertStrToName = crypt32.CertStrToNameW
# TODO(alexpilotti): the following time related functions are not CryptoAPI
# specific, putting them in a separate module would be more correct
kernel32.GetSystemTime.restype = None
kernel32.GetSystemTime.argtypes = [ctypes.POINTER(SYSTEMTIME)]
GetSystemTime = kernel32.GetSystemTime
kernel32.SystemTimeToFileTime.restype = wintypes.BOOL
kernel32.SystemTimeToFileTime.argtypes = [ctypes.POINTER(SYSTEMTIME),
ctypes.POINTER(FILETIME)]
SystemTimeToFileTime = kernel32.SystemTimeToFileTime
kernel32.FileTimeToSystemTime.restype = wintypes.BOOL
kernel32.FileTimeToSystemTime.argtypes = [ctypes.POINTER(FILETIME),
ctypes.POINTER(SYSTEMTIME)]
FileTimeToSystemTime = kernel32.FileTimeToSystemTime
# TODO(alexpilotti): this is not a CryptoAPI funtion, putting it in a separate
# module would be more correct
kernel32.GetLastError.restype = wintypes.DWORD
kernel32.GetLastError.argtypes = []
GetLastError = kernel32.GetLastError
crypt32.CertCreateSelfSignCertificate.restype = ctypes.POINTER(CERT_CONTEXT)
crypt32.CertCreateSelfSignCertificate.argtypes = [
wintypes.HANDLE,
ctypes.POINTER(CRYPTOAPI_BLOB),
wintypes.DWORD,
ctypes.POINTER(CRYPT_KEY_PROV_INFO),
ctypes.POINTER(CRYPT_ALGORITHM_IDENTIFIER),
ctypes.POINTER(SYSTEMTIME),
ctypes.POINTER(SYSTEMTIME),
# PCERT_EXTENSIONS
ctypes.c_void_p]
CertCreateSelfSignCertificate = crypt32.CertCreateSelfSignCertificate
crypt32.CertAddEnhancedKeyUsageIdentifier.restype = wintypes.BOOL
crypt32.CertAddEnhancedKeyUsageIdentifier.argtypes = [
ctypes.POINTER(CERT_CONTEXT),
wintypes.LPCSTR]
CertAddEnhancedKeyUsageIdentifier = crypt32.CertAddEnhancedKeyUsageIdentifier
crypt32.CertOpenStore.restype = wintypes.HANDLE
crypt32.CertOpenStore.argtypes = [wintypes.LPCSTR, wintypes.DWORD,
wintypes.HANDLE, wintypes.DWORD,
ctypes.c_void_p]
CertOpenStore = crypt32.CertOpenStore
crypt32.CertAddCertificateContextToStore.restype = wintypes.BOOL
crypt32.CertAddCertificateContextToStore.argtypes = [
wintypes.HANDLE,
ctypes.POINTER(CERT_CONTEXT),
wintypes.DWORD,
ctypes.POINTER(CERT_CONTEXT)]
CertAddCertificateContextToStore = crypt32.CertAddCertificateContextToStore
crypt32.CryptStringToBinaryW.restype = wintypes.BOOL
crypt32.CryptStringToBinaryW.argtypes = [wintypes.LPCWSTR,
wintypes.DWORD,
wintypes.DWORD,
ctypes.POINTER(wintypes.BYTE),
ctypes.POINTER(wintypes.DWORD),
ctypes.POINTER(wintypes.DWORD),
ctypes.POINTER(wintypes.DWORD)]
CryptStringToBinaryW = crypt32.CryptStringToBinaryW
crypt32.CertAddEncodedCertificateToStore.restype = wintypes.BOOL
crypt32.CertAddEncodedCertificateToStore.argtypes = [
wintypes.HANDLE,
wintypes.DWORD,
ctypes.POINTER(wintypes.BYTE),
wintypes.DWORD,
wintypes.DWORD,
ctypes.POINTER(ctypes.POINTER(CERT_CONTEXT))]
CertAddEncodedCertificateToStore = crypt32.CertAddEncodedCertificateToStore
crypt32.CertGetNameStringW.restype = wintypes.DWORD
crypt32.CertGetNameStringW.argtypes = [ctypes.POINTER(CERT_CONTEXT),
wintypes.DWORD,
wintypes.DWORD,
ctypes.c_void_p,
wintypes.LPWSTR,
wintypes.DWORD]
CertGetNameString = crypt32.CertGetNameStringW
crypt32.CertFreeCertificateContext.restype = wintypes.BOOL
crypt32.CertFreeCertificateContext.argtypes = [ctypes.POINTER(CERT_CONTEXT)]
CertFreeCertificateContext = crypt32.CertFreeCertificateContext
crypt32.CertCloseStore.restype = wintypes.BOOL
crypt32.CertCloseStore.argtypes = [wintypes.HANDLE, wintypes.DWORD]
CertCloseStore = crypt32.CertCloseStore
crypt32.CertGetCertificateContextProperty.restype = wintypes.BOOL
crypt32.CertGetCertificateContextProperty.argtypes = [
ctypes.POINTER(CERT_CONTEXT),
wintypes.DWORD,
ctypes.c_void_p,
ctypes.POINTER(wintypes.DWORD)]
CertGetCertificateContextProperty = crypt32.CertGetCertificateContextProperty