| /* |
| * crypt32 Crypt*Object functions |
| * |
| * Copyright 2007 Juan Lang |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| #include <stdarg.h> |
| #define NONAMELESSUNION |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wincrypt.h" |
| #include "mssip.h" |
| #include "winuser.h" |
| #include "wintrust.h" |
| #include "crypt32_private.h" |
| #include "cryptres.h" |
| #include "wine/unicode.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(crypt); |
| |
| static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob) |
| { |
| BOOL ret = FALSE; |
| HANDLE file; |
| |
| TRACE("%s\n", debugstr_w(fileName)); |
| |
| file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, |
| OPEN_EXISTING, 0, NULL); |
| if (file != INVALID_HANDLE_VALUE) |
| { |
| ret = TRUE; |
| blob->cbData = GetFileSize(file, NULL); |
| if (blob->cbData) |
| { |
| blob->pbData = CryptMemAlloc(blob->cbData); |
| if (blob->pbData) |
| { |
| DWORD read; |
| |
| ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL) && read == blob->cbData; |
| if (!ret) CryptMemFree(blob->pbData); |
| } |
| else |
| ret = FALSE; |
| } |
| CloseHandle(file); |
| } |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob, |
| DWORD dwExpectedContentTypeFlags, HCERTSTORE store, |
| DWORD *contentType, const void **ppvContext) |
| { |
| BOOL ret = FALSE; |
| |
| if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) |
| { |
| ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING, |
| blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext); |
| if (ret && contentType) |
| *contentType = CERT_QUERY_CONTENT_CERT; |
| } |
| if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL)) |
| { |
| ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING, |
| blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext); |
| if (ret && contentType) |
| *contentType = CERT_QUERY_CONTENT_CRL; |
| } |
| if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL)) |
| { |
| ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING, |
| blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext); |
| if (ret && contentType) |
| *contentType = CERT_QUERY_CONTENT_CTL; |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject, |
| DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType, |
| HCERTSTORE *phCertStore, const void **ppvContext) |
| { |
| CERT_BLOB fileBlob; |
| const CERT_BLOB *blob; |
| HCERTSTORE store; |
| BOOL ret; |
| DWORD formatType = 0; |
| |
| switch (dwObjectType) |
| { |
| case CERT_QUERY_OBJECT_FILE: |
| /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so |
| * just read the file directly |
| */ |
| ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob); |
| blob = &fileBlob; |
| break; |
| case CERT_QUERY_OBJECT_BLOB: |
| blob = pvObject; |
| ret = TRUE; |
| break; |
| default: |
| SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ |
| ret = FALSE; |
| } |
| if (!ret) |
| return FALSE; |
| |
| ret = FALSE; |
| store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY) |
| { |
| ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store, |
| pdwContentType, ppvContext); |
| if (ret) |
| formatType = CERT_QUERY_FORMAT_BINARY; |
| } |
| if (!ret && |
| (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED)) |
| { |
| CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData }; |
| CRYPT_DATA_BLOB decoded; |
| |
| while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1]) |
| trimmed.cbData--; |
| ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData, |
| CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL); |
| if (ret) |
| { |
| decoded.pbData = CryptMemAlloc(decoded.cbData); |
| if (decoded.pbData) |
| { |
| ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, |
| trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData, |
| &decoded.cbData, NULL, NULL); |
| if (ret) |
| { |
| ret = CRYPT_QueryContextBlob(&decoded, |
| dwExpectedContentTypeFlags, store, pdwContentType, |
| ppvContext); |
| if (ret) |
| formatType = CERT_QUERY_FORMAT_BASE64_ENCODED; |
| } |
| CryptMemFree(decoded.pbData); |
| } |
| else |
| ret = FALSE; |
| } |
| } |
| if (ret) |
| { |
| if (pdwMsgAndCertEncodingType) |
| *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; |
| if (pdwFormatType) |
| *pdwFormatType = formatType; |
| if (phCertStore) |
| *phCertStore = CertDuplicateStore(store); |
| } |
| CertCloseStore(store, 0); |
| if (blob == &fileBlob) |
| CryptMemFree(blob->pbData); |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType, |
| const void *pvObject, DWORD dwExpectedContentTypeFlags, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, |
| HCERTSTORE *phCertStore, const void **ppvContext) |
| { |
| CERT_BLOB fileBlob; |
| const CERT_BLOB *blob; |
| const WINE_CONTEXT_INTERFACE *contextInterface = NULL; |
| const void *context; |
| DWORD contextType; |
| BOOL ret; |
| |
| switch (dwObjectType) |
| { |
| case CERT_QUERY_OBJECT_FILE: |
| /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so |
| * just read the file directly |
| */ |
| ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob); |
| blob = &fileBlob; |
| break; |
| case CERT_QUERY_OBJECT_BLOB: |
| blob = pvObject; |
| ret = TRUE; |
| break; |
| default: |
| SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ |
| ret = FALSE; |
| } |
| if (!ret) |
| return FALSE; |
| |
| ret = FALSE; |
| context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData, |
| CERT_STORE_ALL_CONTEXT_FLAG, &contextType); |
| if (context) |
| { |
| DWORD contentType, certStoreOffset; |
| |
| ret = TRUE; |
| switch (contextType) |
| { |
| case CERT_STORE_CERTIFICATE_CONTEXT: |
| contextInterface = pCertInterface; |
| contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT; |
| certStoreOffset = offsetof(CERT_CONTEXT, hCertStore); |
| if (!(dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT)) |
| { |
| SetLastError(ERROR_INVALID_DATA); |
| ret = FALSE; |
| goto end; |
| } |
| break; |
| case CERT_STORE_CRL_CONTEXT: |
| contextInterface = pCRLInterface; |
| contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL; |
| certStoreOffset = offsetof(CRL_CONTEXT, hCertStore); |
| if (!(dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL)) |
| { |
| SetLastError(ERROR_INVALID_DATA); |
| ret = FALSE; |
| goto end; |
| } |
| break; |
| case CERT_STORE_CTL_CONTEXT: |
| contextInterface = pCTLInterface; |
| contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL; |
| certStoreOffset = offsetof(CTL_CONTEXT, hCertStore); |
| if (!(dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)) |
| { |
| SetLastError(ERROR_INVALID_DATA); |
| ret = FALSE; |
| goto end; |
| } |
| break; |
| default: |
| SetLastError(ERROR_INVALID_DATA); |
| ret = FALSE; |
| goto end; |
| } |
| if (pdwMsgAndCertEncodingType) |
| *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; |
| if (pdwContentType) |
| *pdwContentType = contentType; |
| if (phCertStore) |
| *phCertStore = CertDuplicateStore( |
| *(HCERTSTORE *)((const BYTE *)context + certStoreOffset)); |
| if (ppvContext) |
| { |
| *ppvContext = context; |
| Context_AddRef(context_from_ptr(context)); |
| } |
| } |
| |
| end: |
| if (contextInterface && context) |
| Context_Release(context_from_ptr(context)); |
| if (blob == &fileBlob) |
| CryptMemFree(blob->pbData); |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, |
| HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) |
| { |
| HANDLE file; |
| BOOL ret = FALSE; |
| |
| TRACE("%s\n", debugstr_w(fileName)); |
| file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, |
| OPEN_EXISTING, 0, NULL); |
| if (file != INVALID_HANDLE_VALUE) |
| { |
| HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| |
| ret = CRYPT_ReadSerializedStoreFromFile(file, store); |
| if (ret) |
| { |
| if (pdwMsgAndCertEncodingType) |
| *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; |
| if (pdwContentType) |
| *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE; |
| if (phCertStore) |
| *phCertStore = CertDuplicateStore(store); |
| } |
| CertCloseStore(store, 0); |
| CloseHandle(file); |
| } |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, |
| HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) |
| { |
| HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| BOOL ret; |
| |
| TRACE("(%d, %p)\n", blob->cbData, blob->pbData); |
| |
| ret = CRYPT_ReadSerializedStoreFromBlob(blob, store); |
| if (ret) |
| { |
| if (pdwMsgAndCertEncodingType) |
| *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; |
| if (pdwContentType) |
| *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE; |
| if (phCertStore) |
| *phCertStore = CertDuplicateStore(store); |
| } |
| CertCloseStore(store, 0); |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType, |
| const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, |
| HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) |
| { |
| switch (dwObjectType) |
| { |
| case CERT_QUERY_OBJECT_FILE: |
| return CRYPT_QuerySerializedStoreFromFile(pvObject, |
| pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg); |
| case CERT_QUERY_OBJECT_BLOB: |
| return CRYPT_QuerySerializedStoreFromBlob(pvObject, |
| pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg); |
| default: |
| FIXME("unimplemented for type %d\n", dwObjectType); |
| SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ |
| return FALSE; |
| } |
| } |
| |
| static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg) |
| { |
| DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| BOOL ret = FALSE; |
| HCRYPTMSG msg; |
| |
| if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL))) |
| { |
| ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); |
| if (ret) |
| { |
| DWORD type, len = sizeof(type); |
| |
| ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len); |
| if (ret) |
| { |
| if (type != CMSG_SIGNED) |
| { |
| SetLastError(ERROR_INVALID_DATA); |
| ret = FALSE; |
| } |
| } |
| } |
| if (!ret) |
| { |
| CryptMsgClose(msg); |
| msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, |
| NULL); |
| if (msg) |
| { |
| ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); |
| if (!ret) |
| { |
| CryptMsgClose(msg); |
| msg = NULL; |
| } |
| } |
| } |
| } |
| if (ret) |
| { |
| if (pdwMsgAndCertEncodingType) |
| *pdwMsgAndCertEncodingType = encodingType; |
| if (pdwContentType) |
| *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED; |
| if (phMsg) |
| *phMsg = msg; |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg) |
| { |
| DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| BOOL ret = FALSE; |
| HCRYPTMSG msg; |
| |
| if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL))) |
| { |
| ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); |
| if (ret) |
| { |
| DWORD type, len = sizeof(type); |
| |
| ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len); |
| if (ret) |
| { |
| if (type != CMSG_DATA) |
| { |
| SetLastError(ERROR_INVALID_DATA); |
| ret = FALSE; |
| } |
| } |
| } |
| if (!ret) |
| { |
| CryptMsgClose(msg); |
| msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, |
| NULL, NULL); |
| if (msg) |
| { |
| ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); |
| if (!ret) |
| { |
| CryptMsgClose(msg); |
| msg = NULL; |
| } |
| } |
| } |
| } |
| if (ret) |
| { |
| if (pdwMsgAndCertEncodingType) |
| *pdwMsgAndCertEncodingType = encodingType; |
| if (pdwContentType) |
| *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED; |
| if (phMsg) |
| *phMsg = msg; |
| } |
| return ret; |
| } |
| |
| /* Used to decode non-embedded messages */ |
| static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject, |
| DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType, |
| HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) |
| { |
| CERT_BLOB fileBlob; |
| const CERT_BLOB *blob; |
| BOOL ret; |
| HCRYPTMSG msg = NULL; |
| DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| DWORD formatType = 0; |
| |
| TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject, |
| dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, |
| pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore, |
| phMsg); |
| |
| switch (dwObjectType) |
| { |
| case CERT_QUERY_OBJECT_FILE: |
| /* This isn't an embedded PKCS7 message, so just read the file |
| * directly |
| */ |
| ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob); |
| blob = &fileBlob; |
| break; |
| case CERT_QUERY_OBJECT_BLOB: |
| blob = pvObject; |
| ret = TRUE; |
| break; |
| default: |
| SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ |
| ret = FALSE; |
| } |
| if (!ret) |
| return FALSE; |
| |
| ret = FALSE; |
| if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY) |
| { |
| /* Try it first as a signed message */ |
| if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) |
| ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType, |
| pdwContentType, &msg); |
| /* Failing that, try as an unsigned message */ |
| if (!ret && |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) |
| ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType, |
| pdwContentType, &msg); |
| if (ret) |
| formatType = CERT_QUERY_FORMAT_BINARY; |
| } |
| if (!ret && |
| (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED)) |
| { |
| CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData }; |
| CRYPT_DATA_BLOB decoded; |
| |
| while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1]) |
| trimmed.cbData--; |
| ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData, |
| CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL); |
| if (ret) |
| { |
| decoded.pbData = CryptMemAlloc(decoded.cbData); |
| if (decoded.pbData) |
| { |
| ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, |
| trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData, |
| &decoded.cbData, NULL, NULL); |
| if (ret) |
| { |
| /* Try it first as a signed message */ |
| if (dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) |
| ret = CRYPT_QuerySignedMessage(&decoded, |
| pdwMsgAndCertEncodingType, pdwContentType, &msg); |
| /* Failing that, try as an unsigned message */ |
| if (!ret && (dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) |
| ret = CRYPT_QueryUnsignedMessage(&decoded, |
| pdwMsgAndCertEncodingType, pdwContentType, &msg); |
| if (ret) |
| formatType = CERT_QUERY_FORMAT_BASE64_ENCODED; |
| } |
| CryptMemFree(decoded.pbData); |
| } |
| else |
| ret = FALSE; |
| } |
| if (!ret && !(blob->cbData % sizeof(WCHAR))) |
| { |
| CRYPT_DATA_BLOB decoded; |
| LPWSTR str = (LPWSTR)blob->pbData; |
| DWORD strLen = blob->cbData / sizeof(WCHAR); |
| |
| /* Try again, assuming the input string is UTF-16 base64 */ |
| while (strLen && !str[strLen - 1]) |
| strLen--; |
| ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY, |
| NULL, &decoded.cbData, NULL, NULL); |
| if (ret) |
| { |
| decoded.pbData = CryptMemAlloc(decoded.cbData); |
| if (decoded.pbData) |
| { |
| ret = CryptStringToBinaryW(str, strLen, |
| CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData, |
| NULL, NULL); |
| if (ret) |
| { |
| /* Try it first as a signed message */ |
| if (dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) |
| ret = CRYPT_QuerySignedMessage(&decoded, |
| pdwMsgAndCertEncodingType, pdwContentType, &msg); |
| /* Failing that, try as an unsigned message */ |
| if (!ret && (dwExpectedContentTypeFlags & |
| CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) |
| ret = CRYPT_QueryUnsignedMessage(&decoded, |
| pdwMsgAndCertEncodingType, pdwContentType, &msg); |
| if (ret) |
| formatType = CERT_QUERY_FORMAT_BASE64_ENCODED; |
| } |
| CryptMemFree(decoded.pbData); |
| } |
| else |
| ret = FALSE; |
| } |
| } |
| } |
| if (ret) |
| { |
| if (pdwFormatType) |
| *pdwFormatType = formatType; |
| if (phCertStore) |
| *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0, |
| 0, msg); |
| if (phMsg) |
| *phMsg = msg; |
| else |
| CryptMsgClose(msg); |
| } |
| if (blob == &fileBlob) |
| CryptMemFree(blob->pbData); |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType, |
| const void *pvObject, DWORD dwExpectedContentTypeFlags, |
| DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, |
| HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) |
| { |
| HANDLE file; |
| GUID subject; |
| BOOL ret = FALSE; |
| |
| TRACE("%s\n", debugstr_w(pvObject)); |
| |
| if (dwObjectType != CERT_QUERY_OBJECT_FILE) |
| { |
| WARN("don't know what to do for type %d embedded signed messages\n", |
| dwObjectType); |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ, |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| if (file != INVALID_HANDLE_VALUE) |
| { |
| ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject); |
| if (ret) |
| { |
| SIP_DISPATCH_INFO sip; |
| |
| memset(&sip, 0, sizeof(sip)); |
| sip.cbSize = sizeof(sip); |
| ret = CryptSIPLoad(&subject, 0, &sip); |
| if (ret) |
| { |
| SIP_SUBJECTINFO subjectInfo; |
| CERT_BLOB blob; |
| DWORD encodingType; |
| |
| memset(&subjectInfo, 0, sizeof(subjectInfo)); |
| subjectInfo.cbSize = sizeof(subjectInfo); |
| subjectInfo.pgSubjectType = &subject; |
| subjectInfo.hFile = file; |
| subjectInfo.pwsFileName = pvObject; |
| ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData, |
| NULL); |
| if (ret) |
| { |
| blob.pbData = CryptMemAlloc(blob.cbData); |
| if (blob.pbData) |
| { |
| ret = sip.pfGet(&subjectInfo, &encodingType, 0, |
| &blob.cbData, blob.pbData); |
| if (ret) |
| { |
| ret = CRYPT_QueryMessageObject( |
| CERT_QUERY_OBJECT_BLOB, &blob, |
| CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, |
| CERT_QUERY_FORMAT_FLAG_BINARY, |
| pdwMsgAndCertEncodingType, NULL, NULL, |
| phCertStore, phMsg); |
| if (ret && pdwContentType) |
| *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED; |
| } |
| CryptMemFree(blob.pbData); |
| } |
| else |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| ret = FALSE; |
| } |
| } |
| } |
| } |
| CloseHandle(file); |
| } |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject, |
| DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, |
| DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, |
| DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg, |
| const void **ppvContext) |
| { |
| static const DWORD unimplementedTypes = |
| CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX | |
| CERT_QUERY_CONTENT_FLAG_CERT_PAIR; |
| BOOL ret = TRUE; |
| |
| TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n", |
| dwObjectType, pvObject, dwExpectedContentTypeFlags, |
| dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType, |
| pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext); |
| |
| if (dwObjectType != CERT_QUERY_OBJECT_BLOB && |
| dwObjectType != CERT_QUERY_OBJECT_FILE) |
| { |
| WARN("unsupported type %d\n", dwObjectType); |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if (!pvObject) |
| { |
| WARN("missing required argument\n"); |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if (dwExpectedContentTypeFlags & unimplementedTypes) |
| WARN("unimplemented for types %08x\n", |
| dwExpectedContentTypeFlags & unimplementedTypes); |
| |
| if (pdwFormatType) |
| *pdwFormatType = CERT_QUERY_FORMAT_BINARY; |
| if (phCertStore) |
| *phCertStore = NULL; |
| if (phMsg) |
| *phMsg = NULL; |
| if (ppvContext) |
| *ppvContext = NULL; |
| |
| ret = FALSE; |
| if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) || |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) || |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL)) |
| { |
| ret = CRYPT_QueryContextObject(dwObjectType, pvObject, |
| dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, |
| pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore, |
| ppvContext); |
| } |
| if (!ret && |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE)) |
| { |
| ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject, |
| pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg); |
| } |
| if (!ret && |
| ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) || |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) || |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))) |
| { |
| ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject, |
| dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, |
| phCertStore, ppvContext); |
| } |
| if (!ret && |
| ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) || |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))) |
| { |
| ret = CRYPT_QueryMessageObject(dwObjectType, pvObject, |
| dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, |
| pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, |
| phCertStore, phMsg); |
| } |
| if (!ret && |
| (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED)) |
| { |
| ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject, |
| dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, |
| phCertStore, phMsg); |
| } |
| if (!ret) |
| SetLastError(CRYPT_E_NO_MATCH); |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| BOOL ret; |
| DWORD bytesNeeded; |
| |
| if (cbEncoded) |
| bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR); |
| else |
| bytesNeeded = sizeof(WCHAR); |
| if (!pbFormat) |
| { |
| *pcbFormat = bytesNeeded; |
| ret = TRUE; |
| } |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| static const WCHAR fmt[] = { '%','0','2','x',' ',0 }; |
| static const WCHAR endFmt[] = { '%','0','2','x',0 }; |
| DWORD i; |
| LPWSTR ptr = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| if (cbEncoded) |
| { |
| for (i = 0; i < cbEncoded; i++) |
| { |
| if (i < cbEncoded - 1) |
| ptr += sprintfW(ptr, fmt, pbEncoded[i]); |
| else |
| ptr += sprintfW(ptr, endFmt, pbEncoded[i]); |
| } |
| } |
| else |
| *ptr = 0; |
| ret = TRUE; |
| } |
| return ret; |
| } |
| |
| #define MAX_STRING_RESOURCE_LEN 128 |
| |
| static const WCHAR commaSpace[] = { ',',' ',0 }; |
| |
| struct BitToString |
| { |
| BYTE bit; |
| int id; |
| WCHAR str[MAX_STRING_RESOURCE_LEN]; |
| }; |
| |
| static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map, |
| DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first) |
| { |
| DWORD bytesNeeded = sizeof(WCHAR); |
| unsigned int i; |
| BOOL ret = TRUE, localFirst = *first; |
| |
| for (i = 0; i < mapEntries; i++) |
| if (bits & map[i].bit) |
| { |
| if (!localFirst) |
| bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR); |
| localFirst = FALSE; |
| bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR); |
| } |
| if (!pbFormat) |
| { |
| *first = localFirst; |
| *pcbFormat = bytesNeeded; |
| } |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *first = localFirst; |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| localFirst = *first; |
| *pcbFormat = bytesNeeded; |
| for (i = 0; i < mapEntries; i++) |
| if (bits & map[i].bit) |
| { |
| if (!localFirst) |
| { |
| strcpyW(str, commaSpace); |
| str += strlenW(commaSpace); |
| } |
| localFirst = FALSE; |
| strcpyW(str, map[i].str); |
| str += strlenW(map[i].str); |
| } |
| *first = localFirst; |
| } |
| return ret; |
| } |
| |
| static struct BitToString keyUsageByte0Map[] = { |
| { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } }, |
| { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } }, |
| { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } }, |
| { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } }, |
| { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } }, |
| { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } }, |
| { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } }, |
| { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } }, |
| { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } }, |
| }; |
| static struct BitToString keyUsageByte1Map[] = { |
| { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } }, |
| }; |
| |
| static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| DWORD size; |
| CRYPT_BIT_BLOB *bits; |
| BOOL ret; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size))) |
| { |
| WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; |
| DWORD bytesNeeded = sizeof(WCHAR); |
| |
| LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, |
| sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); |
| if (!bits->cbData || bits->cbData > 2) |
| { |
| bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| strcpyW(str, infoNotAvailable); |
| } |
| } |
| else |
| { |
| static BOOL stringsLoaded = FALSE; |
| unsigned int i; |
| DWORD bitStringLen; |
| BOOL first = TRUE; |
| |
| if (!stringsLoaded) |
| { |
| for (i = 0; |
| i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]); |
| i++) |
| LoadStringW(hInstance, keyUsageByte0Map[i].id, |
| keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN); |
| for (i = 0; |
| i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]); |
| i++) |
| LoadStringW(hInstance, keyUsageByte1Map[i].id, |
| keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN); |
| stringsLoaded = TRUE; |
| } |
| CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, |
| sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]), |
| NULL, &bitStringLen, &first); |
| bytesNeeded += bitStringLen; |
| if (bits->cbData == 2) |
| { |
| CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, |
| sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]), |
| NULL, &bitStringLen, &first); |
| bytesNeeded += bitStringLen; |
| } |
| bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */ |
| CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, |
| bits->cbData, NULL, &size); |
| bytesNeeded += size; |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| bitStringLen = bytesNeeded; |
| first = TRUE; |
| CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, |
| sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]), |
| str, &bitStringLen, &first); |
| str += bitStringLen / sizeof(WCHAR) - 1; |
| if (bits->cbData == 2) |
| { |
| bitStringLen = bytesNeeded; |
| CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, |
| sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]), |
| str, &bitStringLen, &first); |
| str += bitStringLen / sizeof(WCHAR) - 1; |
| } |
| *str++ = ' '; |
| *str++ = '('; |
| CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, |
| bits->cbData, str, &size); |
| str += size / sizeof(WCHAR) - 1; |
| *str++ = ')'; |
| *str = 0; |
| } |
| } |
| LocalFree(bits); |
| } |
| return ret; |
| } |
| |
| static const WCHAR crlf[] = { '\r','\n',0 }; |
| |
| static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN]; |
| |
| static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| DWORD size; |
| CERT_BASIC_CONSTRAINTS2_INFO *info; |
| BOOL ret; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) |
| { |
| static const WCHAR pathFmt[] = { '%','d',0 }; |
| static BOOL stringsLoaded = FALSE; |
| DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */ |
| WCHAR pathLength[MAX_STRING_RESOURCE_LEN]; |
| LPCWSTR sep, subjectType; |
| DWORD sepLen; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| sep = crlf; |
| sepLen = strlenW(crlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sep = commaSpace; |
| sepLen = strlenW(commaSpace) * sizeof(WCHAR); |
| } |
| |
| if (!stringsLoaded) |
| { |
| LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader, |
| sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0])); |
| LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA, |
| sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0])); |
| LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT, |
| subjectTypeEndCert, |
| sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0])); |
| LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader, |
| sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0])); |
| stringsLoaded = TRUE; |
| } |
| bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR); |
| if (info->fCA) |
| subjectType = subjectTypeCA; |
| else |
| subjectType = subjectTypeEndCert; |
| bytesNeeded += strlenW(subjectType) * sizeof(WCHAR); |
| bytesNeeded += sepLen; |
| bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR); |
| if (info->fPathLenConstraint) |
| sprintfW(pathLength, pathFmt, info->dwPathLenConstraint); |
| else |
| LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength, |
| sizeof(pathLength) / sizeof(pathLength[0])); |
| bytesNeeded += strlenW(pathLength) * sizeof(WCHAR); |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| strcpyW(str, subjectTypeHeader); |
| str += strlenW(subjectTypeHeader); |
| strcpyW(str, subjectType); |
| str += strlenW(subjectType); |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| strcpyW(str, pathLengthHeader); |
| str += strlenW(pathLengthHeader); |
| strcpyW(str, pathLength); |
| } |
| LocalFree(info); |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id, |
| LPWSTR str, DWORD *pcbStr) |
| { |
| WCHAR buf[MAX_STRING_RESOURCE_LEN]; |
| DWORD bytesNeeded; |
| BOOL ret; |
| |
| LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0])); |
| CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL, |
| blob->pbData, blob->cbData, NULL, &bytesNeeded); |
| bytesNeeded += strlenW(buf) * sizeof(WCHAR); |
| if (!str) |
| { |
| *pcbStr = bytesNeeded; |
| ret = TRUE; |
| } |
| else if (*pcbStr < bytesNeeded) |
| { |
| *pcbStr = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| *pcbStr = bytesNeeded; |
| strcpyW(str, buf); |
| str += strlenW(str); |
| bytesNeeded -= strlenW(str) * sizeof(WCHAR); |
| ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL, |
| blob->pbData, blob->cbData, str, &bytesNeeded); |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str, |
| DWORD *pcbStr) |
| { |
| return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr); |
| } |
| |
| static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str, |
| DWORD *pcbStr) |
| { |
| return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER, |
| str, pcbStr); |
| } |
| |
| static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 }; |
| static const WCHAR colonCrlf[] = { ':','\r','\n',0 }; |
| |
| static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel, |
| const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr) |
| { |
| BOOL ret; |
| WCHAR buf[MAX_STRING_RESOURCE_LEN]; |
| WCHAR mask[MAX_STRING_RESOURCE_LEN]; |
| WCHAR ipAddrBuf[32]; |
| WCHAR maskBuf[16]; |
| DWORD bytesNeeded = sizeof(WCHAR); |
| DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR); |
| switch (entry->dwAltNameChoice) |
| { |
| case CERT_ALT_NAME_RFC822_NAME: |
| LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf, |
| sizeof(buf) / sizeof(buf[0])); |
| bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR); |
| ret = TRUE; |
| break; |
| case CERT_ALT_NAME_DNS_NAME: |
| LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf, |
| sizeof(buf) / sizeof(buf[0])); |
| bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR); |
| ret = TRUE; |
| break; |
| case CERT_ALT_NAME_DIRECTORY_NAME: |
| { |
| DWORD directoryNameLen; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| strType |= CERT_NAME_STR_CRLF_FLAG; |
| directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING, |
| indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0); |
| LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf, |
| sizeof(buf) / sizeof(buf[0])); |
| bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR); |
| else |
| bytesNeeded += sizeof(WCHAR); /* '=' */ |
| ret = TRUE; |
| break; |
| } |
| case CERT_ALT_NAME_URL: |
| LoadStringW(hInstance, IDS_ALT_NAME_URL, buf, |
| sizeof(buf) / sizeof(buf[0])); |
| bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR); |
| ret = TRUE; |
| break; |
| case CERT_ALT_NAME_IP_ADDRESS: |
| { |
| static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.', |
| '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0 |
| }; |
| static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d', |
| '.','%','d',0 }; |
| |
| LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf, |
| sizeof(buf) / sizeof(buf[0])); |
| if (entry->u.IPAddress.cbData == 8) |
| { |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask, |
| sizeof(mask) / sizeof(mask[0])); |
| bytesNeeded += strlenW(mask) * sizeof(WCHAR); |
| sprintfW(ipAddrBuf, ipAddrFmt, |
| entry->u.IPAddress.pbData[0], |
| entry->u.IPAddress.pbData[1], |
| entry->u.IPAddress.pbData[2], |
| entry->u.IPAddress.pbData[3]); |
| bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR); |
| /* indent again, for the mask line */ |
| bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR); |
| sprintfW(maskBuf, ipAddrFmt, |
| entry->u.IPAddress.pbData[4], |
| entry->u.IPAddress.pbData[5], |
| entry->u.IPAddress.pbData[6], |
| entry->u.IPAddress.pbData[7]); |
| bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR); |
| bytesNeeded += strlenW(crlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sprintfW(ipAddrBuf, ipAddrWithMaskFmt, |
| entry->u.IPAddress.pbData[0], |
| entry->u.IPAddress.pbData[1], |
| entry->u.IPAddress.pbData[2], |
| entry->u.IPAddress.pbData[3], |
| entry->u.IPAddress.pbData[4], |
| entry->u.IPAddress.pbData[5], |
| entry->u.IPAddress.pbData[6], |
| entry->u.IPAddress.pbData[7]); |
| bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR); |
| } |
| ret = TRUE; |
| } |
| else |
| { |
| FIXME("unknown IP address format (%d bytes)\n", |
| entry->u.IPAddress.cbData); |
| ret = FALSE; |
| } |
| break; |
| } |
| default: |
| FIXME("unimplemented for %d\n", entry->dwAltNameChoice); |
| ret = FALSE; |
| } |
| if (ret) |
| { |
| bytesNeeded += strlenW(buf) * sizeof(WCHAR); |
| if (!str) |
| *pcbStr = bytesNeeded; |
| else if (*pcbStr < bytesNeeded) |
| { |
| *pcbStr = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| DWORD i; |
| |
| *pcbStr = bytesNeeded; |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| for (i = 0; i < indentLevel; i++) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| strcpyW(str, buf); |
| str += strlenW(str); |
| switch (entry->dwAltNameChoice) |
| { |
| case CERT_ALT_NAME_RFC822_NAME: |
| case CERT_ALT_NAME_DNS_NAME: |
| case CERT_ALT_NAME_URL: |
| strcpyW(str, entry->u.pwszURL); |
| break; |
| case CERT_ALT_NAME_DIRECTORY_NAME: |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| strcpyW(str, colonCrlf); |
| str += strlenW(colonCrlf); |
| } |
| else |
| *str++ = '='; |
| cert_name_to_str_with_indent(X509_ASN_ENCODING, |
| indentLevel + 1, &entry->u.DirectoryName, strType, str, |
| bytesNeeded / sizeof(WCHAR)); |
| break; |
| case CERT_ALT_NAME_IP_ADDRESS: |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| strcpyW(str, ipAddrBuf); |
| str += strlenW(ipAddrBuf); |
| strcpyW(str, crlf); |
| str += strlenW(crlf); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| for (i = 0; i < indentLevel; i++) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| strcpyW(str, mask); |
| str += strlenW(mask); |
| strcpyW(str, maskBuf); |
| } |
| else |
| strcpyW(str, ipAddrBuf); |
| break; |
| } |
| } |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel, |
| const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr) |
| { |
| DWORD i, size, bytesNeeded = 0; |
| BOOL ret = TRUE; |
| LPCWSTR sep; |
| DWORD sepLen; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| sep = crlf; |
| sepLen = strlenW(crlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sep = commaSpace; |
| sepLen = strlenW(commaSpace) * sizeof(WCHAR); |
| } |
| |
| for (i = 0; ret && i < name->cAltEntry; i++) |
| { |
| ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel, |
| &name->rgAltEntry[i], NULL, &size); |
| if (ret) |
| { |
| bytesNeeded += size - sizeof(WCHAR); |
| if (i < name->cAltEntry - 1) |
| bytesNeeded += sepLen; |
| } |
| } |
| if (ret) |
| { |
| bytesNeeded += sizeof(WCHAR); |
| if (!str) |
| *pcbStr = bytesNeeded; |
| else if (*pcbStr < bytesNeeded) |
| { |
| *pcbStr = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| *pcbStr = bytesNeeded; |
| for (i = 0; ret && i < name->cAltEntry; i++) |
| { |
| ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel, |
| &name->rgAltEntry[i], str, &size); |
| if (ret) |
| { |
| str += size / sizeof(WCHAR) - 1; |
| if (i < name->cAltEntry - 1) |
| { |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| } |
| } |
| } |
| } |
| } |
| return ret; |
| } |
| |
| static const WCHAR colonSep[] = { ':',' ',0 }; |
| |
| static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| BOOL ret; |
| CERT_ALT_NAME_INFO *info; |
| DWORD size; |
| |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) |
| { |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat); |
| LocalFree(info); |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType, |
| const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr) |
| { |
| WCHAR buf[MAX_STRING_RESOURCE_LEN]; |
| DWORD bytesNeeded, sepLen; |
| LPCWSTR sep; |
| BOOL ret; |
| |
| LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0])); |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL, |
| &bytesNeeded); |
| bytesNeeded += strlenW(buf) * sizeof(WCHAR); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| sep = colonCrlf; |
| sepLen = strlenW(colonCrlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sep = colonSep; |
| sepLen = strlenW(colonSep) * sizeof(WCHAR); |
| } |
| bytesNeeded += sepLen; |
| if (ret) |
| { |
| if (!str) |
| *pcbStr = bytesNeeded; |
| else if (*pcbStr < bytesNeeded) |
| { |
| *pcbStr = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| *pcbStr = bytesNeeded; |
| strcpyW(str, buf); |
| bytesNeeded -= strlenW(str) * sizeof(WCHAR); |
| str += strlenW(str); |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str, |
| &bytesNeeded); |
| } |
| } |
| return ret; |
| } |
| |
| static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| CERT_AUTHORITY_KEY_ID2_INFO *info; |
| DWORD size; |
| BOOL ret = FALSE; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) |
| { |
| DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */ |
| LPCWSTR sep; |
| DWORD sepLen; |
| BOOL needSeparator = FALSE; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| sep = crlf; |
| sepLen = strlenW(crlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sep = commaSpace; |
| sepLen = strlenW(commaSpace) * sizeof(WCHAR); |
| } |
| |
| if (info->KeyId.cbData) |
| { |
| needSeparator = TRUE; |
| ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size); |
| if (ret) |
| { |
| /* don't include NULL-terminator more than once */ |
| bytesNeeded += size - sizeof(WCHAR); |
| } |
| } |
| if (info->AuthorityCertIssuer.cAltEntry) |
| { |
| if (needSeparator) |
| bytesNeeded += sepLen; |
| needSeparator = TRUE; |
| ret = CRYPT_FormatCertIssuer(dwFormatStrType, |
| &info->AuthorityCertIssuer, NULL, &size); |
| if (ret) |
| { |
| /* don't include NULL-terminator more than once */ |
| bytesNeeded += size - sizeof(WCHAR); |
| } |
| } |
| if (info->AuthorityCertSerialNumber.cbData) |
| { |
| if (needSeparator) |
| bytesNeeded += sepLen; |
| ret = CRYPT_FormatCertSerialNumber( |
| &info->AuthorityCertSerialNumber, NULL, &size); |
| if (ret) |
| { |
| /* don't include NULL-terminator more than once */ |
| bytesNeeded += size - sizeof(WCHAR); |
| } |
| } |
| if (ret) |
| { |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| needSeparator = FALSE; |
| if (info->KeyId.cbData) |
| { |
| needSeparator = TRUE; |
| /* Overestimate size available, it's already been checked |
| * above. |
| */ |
| size = bytesNeeded; |
| ret = CRYPT_FormatKeyId(&info->KeyId, str, &size); |
| if (ret) |
| str += size / sizeof(WCHAR) - 1; |
| } |
| if (info->AuthorityCertIssuer.cAltEntry) |
| { |
| if (needSeparator) |
| { |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| } |
| needSeparator = TRUE; |
| /* Overestimate size available, it's already been checked |
| * above. |
| */ |
| size = bytesNeeded; |
| ret = CRYPT_FormatCertIssuer(dwFormatStrType, |
| &info->AuthorityCertIssuer, str, &size); |
| if (ret) |
| str += size / sizeof(WCHAR) - 1; |
| } |
| if (info->AuthorityCertSerialNumber.cbData) |
| { |
| if (needSeparator) |
| { |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| } |
| /* Overestimate size available, it's already been checked |
| * above. |
| */ |
| size = bytesNeeded; |
| ret = CRYPT_FormatCertSerialNumber( |
| &info->AuthorityCertSerialNumber, str, &size); |
| } |
| } |
| } |
| LocalFree(info); |
| } |
| return ret; |
| } |
| |
| static WCHAR aia[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR ocsp[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR unknown[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN]; |
| |
| static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| CERT_AUTHORITY_INFO_ACCESS *info; |
| DWORD size; |
| BOOL ret = FALSE; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, |
| X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, |
| NULL, &info, &size))) |
| { |
| DWORD bytesNeeded = sizeof(WCHAR); |
| |
| if (!info->cAccDescr) |
| { |
| WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; |
| |
| LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, |
| sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); |
| bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| *pcbFormat = bytesNeeded; |
| strcpyW(pbFormat, infoNotAvailable); |
| } |
| } |
| else |
| { |
| static const WCHAR numFmt[] = { '%','d',0 }; |
| static const WCHAR equal[] = { '=',0 }; |
| static BOOL stringsLoaded = FALSE; |
| DWORD i; |
| LPCWSTR headingSep, accessMethodSep, locationSep; |
| WCHAR accessDescrNum[11]; |
| |
| if (!stringsLoaded) |
| { |
| LoadStringW(hInstance, IDS_AIA, aia, |
| sizeof(aia) / sizeof(aia[0])); |
| LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod, |
| sizeof(accessMethod) / sizeof(accessMethod[0])); |
| LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp, |
| sizeof(ocsp) / sizeof(ocsp[0])); |
| LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers, |
| sizeof(caIssuers) / sizeof(caIssuers[0])); |
| LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown, |
| sizeof(unknown) / sizeof(unknown[0])); |
| LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation, |
| sizeof(accessLocation) / sizeof(accessLocation[0])); |
| stringsLoaded = TRUE; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| headingSep = crlf; |
| accessMethodSep = crlf; |
| locationSep = colonCrlf; |
| } |
| else |
| { |
| headingSep = colonSep; |
| accessMethodSep = commaSpace; |
| locationSep = equal; |
| } |
| |
| for (i = 0; ret && i < info->cAccDescr; i++) |
| { |
| /* Heading */ |
| bytesNeeded += sizeof(WCHAR); /* left bracket */ |
| sprintfW(accessDescrNum, numFmt, i + 1); |
| bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR); |
| bytesNeeded += sizeof(WCHAR); /* right bracket */ |
| bytesNeeded += strlenW(aia) * sizeof(WCHAR); |
| bytesNeeded += strlenW(headingSep) * sizeof(WCHAR); |
| /* Access method */ |
| bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| bytesNeeded += strlenW(indent) * sizeof(WCHAR); |
| if (!strcmp(info->rgAccDescr[i].pszAccessMethod, |
| szOID_PKIX_OCSP)) |
| bytesNeeded += strlenW(ocsp) * sizeof(WCHAR); |
| else if (!strcmp(info->rgAccDescr[i].pszAccessMethod, |
| szOID_PKIX_CA_ISSUERS)) |
| bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers); |
| else |
| bytesNeeded += strlenW(unknown) * sizeof(WCHAR); |
| bytesNeeded += sizeof(WCHAR); /* space */ |
| bytesNeeded += sizeof(WCHAR); /* left paren */ |
| bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod) |
| * sizeof(WCHAR); |
| bytesNeeded += sizeof(WCHAR); /* right paren */ |
| /* Delimiter between access method and location */ |
| bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| bytesNeeded += strlenW(indent) * sizeof(WCHAR); |
| bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR); |
| bytesNeeded += strlenW(locationSep) * sizeof(WCHAR); |
| ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2, |
| &info->rgAccDescr[i].AccessLocation, NULL, &size); |
| if (ret) |
| bytesNeeded += size - sizeof(WCHAR); |
| /* Need extra delimiter between access method entries */ |
| if (i < info->cAccDescr - 1) |
| bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR); |
| } |
| if (ret) |
| { |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| DWORD altNameEntrySize; |
| |
| *pcbFormat = bytesNeeded; |
| for (i = 0; ret && i < info->cAccDescr; i++) |
| { |
| LPCSTR oidPtr; |
| |
| *str++ = '['; |
| sprintfW(accessDescrNum, numFmt, i + 1); |
| strcpyW(str, accessDescrNum); |
| str += strlenW(accessDescrNum); |
| *str++ = ']'; |
| strcpyW(str, aia); |
| str += strlenW(aia); |
| strcpyW(str, headingSep); |
| str += strlenW(headingSep); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| strcpyW(str, accessMethod); |
| str += strlenW(accessMethod); |
| if (!strcmp(info->rgAccDescr[i].pszAccessMethod, |
| szOID_PKIX_OCSP)) |
| { |
| strcpyW(str, ocsp); |
| str += strlenW(ocsp); |
| } |
| else if (!strcmp(info->rgAccDescr[i].pszAccessMethod, |
| szOID_PKIX_CA_ISSUERS)) |
| { |
| strcpyW(str, caIssuers); |
| str += strlenW(caIssuers); |
| } |
| else |
| { |
| strcpyW(str, unknown); |
| str += strlenW(unknown); |
| } |
| *str++ = ' '; |
| *str++ = '('; |
| for (oidPtr = info->rgAccDescr[i].pszAccessMethod; |
| *oidPtr; oidPtr++, str++) |
| *str = *oidPtr; |
| *str++ = ')'; |
| strcpyW(str, accessMethodSep); |
| str += strlenW(accessMethodSep); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| strcpyW(str, accessLocation); |
| str += strlenW(accessLocation); |
| strcpyW(str, locationSep); |
| str += strlenW(locationSep); |
| /* This overestimates the size available, but that |
| * won't matter since we checked earlier whether enough |
| * space for the entire string was available. |
| */ |
| altNameEntrySize = bytesNeeded; |
| ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2, |
| &info->rgAccDescr[i].AccessLocation, str, |
| &altNameEntrySize); |
| if (ret) |
| str += altNameEntrySize / sizeof(WCHAR) - 1; |
| if (i < info->cAccDescr - 1) |
| { |
| strcpyW(str, accessMethodSep); |
| str += strlenW(accessMethodSep); |
| } |
| } |
| } |
| } |
| } |
| LocalFree(info); |
| } |
| return ret; |
| } |
| |
| static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR superseded[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN]; |
| |
| struct reason_map_entry |
| { |
| BYTE reasonBit; |
| LPWSTR reason; |
| int id; |
| }; |
| static struct reason_map_entry reason_map[] = { |
| { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE }, |
| { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE }, |
| { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged, |
| IDS_REASON_AFFILIATION_CHANGED }, |
| { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED }, |
| { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased, |
| IDS_REASON_CESSATION_OF_OPERATION }, |
| { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold, |
| IDS_REASON_CERTIFICATE_HOLD }, |
| }; |
| |
| static BOOL CRYPT_FormatReason(DWORD dwFormatStrType, |
| const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr) |
| { |
| static const WCHAR sep[] = { ',',' ',0 }; |
| static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 }; |
| static BOOL stringsLoaded = FALSE; |
| unsigned int i, numReasons = 0; |
| BOOL ret = TRUE; |
| DWORD bytesNeeded = sizeof(WCHAR); |
| WCHAR bits[6]; |
| |
| if (!stringsLoaded) |
| { |
| for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) |
| LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason, |
| MAX_STRING_RESOURCE_LEN); |
| stringsLoaded = TRUE; |
| } |
| /* No need to check reasonFlags->cbData, we already know it's positive. |
| * Ignore any other bytes, as they're for undefined bits. |
| */ |
| for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) |
| { |
| if (reasonFlags->pbData[0] & reason_map[i].reasonBit) |
| { |
| bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR); |
| if (numReasons++) |
| bytesNeeded += strlenW(sep) * sizeof(WCHAR); |
| } |
| } |
| sprintfW(bits, bitsFmt, reasonFlags->pbData[0]); |
| bytesNeeded += strlenW(bits); |
| if (!str) |
| *pcbStr = bytesNeeded; |
| else if (*pcbStr < bytesNeeded) |
| { |
| *pcbStr = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| *pcbStr = bytesNeeded; |
| for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) |
| { |
| if (reasonFlags->pbData[0] & reason_map[i].reasonBit) |
| { |
| strcpyW(str, reason_map[i].reason); |
| str += strlenW(reason_map[i].reason); |
| if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 && |
| numReasons) |
| { |
| strcpyW(str, sep); |
| str += strlenW(sep); |
| } |
| } |
| } |
| strcpyW(str, bits); |
| } |
| return ret; |
| } |
| |
| static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR distPointName[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR fullName[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR rdnName[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR reason[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR issuer[MAX_STRING_RESOURCE_LEN]; |
| |
| static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| CRL_DIST_POINTS_INFO *info; |
| DWORD size; |
| BOOL ret = FALSE; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) |
| { |
| static const WCHAR numFmt[] = { '%','d',0 }; |
| static const WCHAR colon[] = { ':',0 }; |
| static BOOL stringsLoaded = FALSE; |
| DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */ |
| BOOL haveAnEntry = FALSE; |
| LPCWSTR headingSep, nameSep; |
| WCHAR distPointNum[11]; |
| DWORD i; |
| |
| if (!stringsLoaded) |
| { |
| LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint, |
| sizeof(crlDistPoint) / sizeof(crlDistPoint[0])); |
| LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName, |
| sizeof(distPointName) / sizeof(distPointName[0])); |
| LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName, |
| sizeof(fullName) / sizeof(fullName[0])); |
| LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName, |
| sizeof(rdnName) / sizeof(rdnName[0])); |
| LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason, |
| sizeof(reason) / sizeof(reason[0])); |
| LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer, |
| sizeof(issuer) / sizeof(issuer[0])); |
| stringsLoaded = TRUE; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| headingSep = crlf; |
| nameSep = colonCrlf; |
| } |
| else |
| { |
| headingSep = colonSep; |
| nameSep = colon; |
| } |
| |
| for (i = 0; ret && i < info->cDistPoint; i++) |
| { |
| CRL_DIST_POINT *distPoint = &info->rgDistPoint[i]; |
| |
| if (distPoint->DistPointName.dwDistPointNameChoice != |
| CRL_DIST_POINT_NO_NAME) |
| { |
| bytesNeeded += strlenW(distPointName) * sizeof(WCHAR); |
| bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); |
| if (distPoint->DistPointName.dwDistPointNameChoice == |
| CRL_DIST_POINT_FULL_NAME) |
| bytesNeeded += strlenW(fullName) * sizeof(WCHAR); |
| else |
| bytesNeeded += strlenW(rdnName) * sizeof(WCHAR); |
| bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR); |
| /* The indent level (3) is higher than when used as the issuer, |
| * because the name is subordinate to the name type (full vs. |
| * RDN.) |
| */ |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3, |
| &distPoint->DistPointName.u.FullName, NULL, &size); |
| if (ret) |
| bytesNeeded += size - sizeof(WCHAR); |
| haveAnEntry = TRUE; |
| } |
| else if (distPoint->ReasonFlags.cbData) |
| { |
| bytesNeeded += strlenW(reason) * sizeof(WCHAR); |
| ret = CRYPT_FormatReason(dwFormatStrType, |
| &distPoint->ReasonFlags, NULL, &size); |
| if (ret) |
| bytesNeeded += size - sizeof(WCHAR); |
| haveAnEntry = TRUE; |
| } |
| else if (distPoint->CRLIssuer.cAltEntry) |
| { |
| bytesNeeded += strlenW(issuer) * sizeof(WCHAR); |
| bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2, |
| &distPoint->CRLIssuer, NULL, &size); |
| if (ret) |
| bytesNeeded += size - sizeof(WCHAR); |
| haveAnEntry = TRUE; |
| } |
| if (haveAnEntry) |
| { |
| bytesNeeded += sizeof(WCHAR); /* left bracket */ |
| sprintfW(distPointNum, numFmt, i + 1); |
| bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR); |
| bytesNeeded += sizeof(WCHAR); /* right bracket */ |
| bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR); |
| bytesNeeded += strlenW(headingSep) * sizeof(WCHAR); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| bytesNeeded += strlenW(indent) * sizeof(WCHAR); |
| } |
| } |
| if (!haveAnEntry) |
| { |
| WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; |
| |
| LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, |
| sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); |
| bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| *pcbFormat = bytesNeeded; |
| strcpyW(pbFormat, infoNotAvailable); |
| } |
| } |
| else |
| { |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| for (i = 0; ret && i < info->cDistPoint; i++) |
| { |
| CRL_DIST_POINT *distPoint = &info->rgDistPoint[i]; |
| |
| *str++ = '['; |
| sprintfW(distPointNum, numFmt, i + 1); |
| strcpyW(str, distPointNum); |
| str += strlenW(distPointNum); |
| *str++ = ']'; |
| strcpyW(str, crlDistPoint); |
| str += strlenW(crlDistPoint); |
| strcpyW(str, headingSep); |
| str += strlenW(headingSep); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| if (distPoint->DistPointName.dwDistPointNameChoice != |
| CRL_DIST_POINT_NO_NAME) |
| { |
| DWORD altNameSize = bytesNeeded; |
| |
| strcpyW(str, distPointName); |
| str += strlenW(distPointName); |
| strcpyW(str, nameSep); |
| str += strlenW(nameSep); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| if (distPoint->DistPointName.dwDistPointNameChoice == |
| CRL_DIST_POINT_FULL_NAME) |
| { |
| strcpyW(str, fullName); |
| str += strlenW(fullName); |
| } |
| else |
| { |
| strcpyW(str, rdnName); |
| str += strlenW(rdnName); |
| } |
| strcpyW(str, nameSep); |
| str += strlenW(nameSep); |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3, |
| &distPoint->DistPointName.u.FullName, str, |
| &altNameSize); |
| if (ret) |
| str += altNameSize / sizeof(WCHAR) - 1; |
| } |
| else if (distPoint->ReasonFlags.cbData) |
| { |
| DWORD reasonSize = bytesNeeded; |
| |
| strcpyW(str, reason); |
| str += strlenW(reason); |
| ret = CRYPT_FormatReason(dwFormatStrType, |
| &distPoint->ReasonFlags, str, &reasonSize); |
| if (ret) |
| str += reasonSize / sizeof(WCHAR) - 1; |
| } |
| else if (distPoint->CRLIssuer.cAltEntry) |
| { |
| DWORD crlIssuerSize = bytesNeeded; |
| |
| strcpyW(str, issuer); |
| str += strlenW(issuer); |
| strcpyW(str, nameSep); |
| str += strlenW(nameSep); |
| ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2, |
| &distPoint->CRLIssuer, str, |
| &crlIssuerSize); |
| if (ret) |
| str += crlIssuerSize / sizeof(WCHAR) - 1; |
| } |
| } |
| } |
| } |
| LocalFree(info); |
| } |
| return ret; |
| } |
| |
| static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| CERT_ENHKEY_USAGE *usage; |
| DWORD size; |
| BOOL ret = FALSE; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size))) |
| { |
| WCHAR unknown[MAX_STRING_RESOURCE_LEN]; |
| DWORD i; |
| DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */ |
| LPCWSTR sep; |
| DWORD sepLen; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| sep = crlf; |
| sepLen = strlenW(crlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sep = commaSpace; |
| sepLen = strlenW(commaSpace) * sizeof(WCHAR); |
| } |
| |
| LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown, |
| sizeof(unknown) / sizeof(unknown[0])); |
| for (i = 0; i < usage->cUsageIdentifier; i++) |
| { |
| PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, |
| usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID); |
| |
| if (info) |
| bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR); |
| else |
| bytesNeeded += strlenW(unknown) * sizeof(WCHAR); |
| bytesNeeded += sizeof(WCHAR); /* space */ |
| bytesNeeded += sizeof(WCHAR); /* left paren */ |
| bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) * |
| sizeof(WCHAR); |
| bytesNeeded += sizeof(WCHAR); /* right paren */ |
| if (i < usage->cUsageIdentifier - 1) |
| bytesNeeded += sepLen; |
| } |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| for (i = 0; i < usage->cUsageIdentifier; i++) |
| { |
| PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, |
| usage->rgpszUsageIdentifier[i], |
| CRYPT_ENHKEY_USAGE_OID_GROUP_ID); |
| LPCSTR oidPtr; |
| |
| if (info) |
| { |
| strcpyW(str, info->pwszName); |
| str += strlenW(info->pwszName); |
| } |
| else |
| { |
| strcpyW(str, unknown); |
| str += strlenW(unknown); |
| } |
| *str++ = ' '; |
| *str++ = '('; |
| for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++) |
| *str++ = *oidPtr; |
| *str++ = ')'; |
| *str = 0; |
| if (i < usage->cUsageIdentifier - 1) |
| { |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| } |
| } |
| } |
| LocalFree(usage); |
| } |
| return ret; |
| } |
| |
| static struct BitToString netscapeCertTypeMap[] = { |
| { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } }, |
| { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } }, |
| { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } }, |
| { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } }, |
| { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } }, |
| { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } }, |
| { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } }, |
| }; |
| |
| static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| DWORD size; |
| CRYPT_BIT_BLOB *bits; |
| BOOL ret; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size))) |
| { |
| WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; |
| DWORD bytesNeeded = sizeof(WCHAR); |
| |
| LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, |
| sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); |
| if (!bits->cbData || bits->cbData > 1) |
| { |
| bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| strcpyW(str, infoNotAvailable); |
| } |
| } |
| else |
| { |
| static BOOL stringsLoaded = FALSE; |
| unsigned int i; |
| DWORD bitStringLen; |
| BOOL first = TRUE; |
| |
| if (!stringsLoaded) |
| { |
| for (i = 0; i < sizeof(netscapeCertTypeMap) / |
| sizeof(netscapeCertTypeMap[0]); i++) |
| LoadStringW(hInstance, netscapeCertTypeMap[i].id, |
| netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN); |
| stringsLoaded = TRUE; |
| } |
| CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, |
| sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]), |
| NULL, &bitStringLen, &first); |
| bytesNeeded += bitStringLen; |
| bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */ |
| CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, |
| bits->cbData, NULL, &size); |
| bytesNeeded += size; |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| bitStringLen = bytesNeeded; |
| first = TRUE; |
| CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, |
| sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]), |
| str, &bitStringLen, &first); |
| str += bitStringLen / sizeof(WCHAR) - 1; |
| *str++ = ' '; |
| *str++ = '('; |
| CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, |
| bits->cbData, str, &size); |
| str += size / sizeof(WCHAR) - 1; |
| *str++ = ')'; |
| *str = 0; |
| } |
| } |
| LocalFree(bits); |
| } |
| return ret; |
| } |
| |
| static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR available[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR yes[MAX_STRING_RESOURCE_LEN]; |
| static WCHAR no[MAX_STRING_RESOURCE_LEN]; |
| |
| static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| SPC_FINANCIAL_CRITERIA criteria; |
| DWORD size = sizeof(criteria); |
| BOOL ret = FALSE; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, |
| SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria, |
| &size))) |
| { |
| static BOOL stringsLoaded = FALSE; |
| DWORD bytesNeeded = sizeof(WCHAR); |
| LPCWSTR sep; |
| DWORD sepLen; |
| |
| if (!stringsLoaded) |
| { |
| LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria, |
| sizeof(financialCriteria) / sizeof(financialCriteria[0])); |
| LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available, |
| sizeof(available) / sizeof(available[0])); |
| LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE, |
| notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0])); |
| LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA, |
| meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0])); |
| LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0])); |
| LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0])); |
| stringsLoaded = TRUE; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| sep = crlf; |
| sepLen = strlenW(crlf) * sizeof(WCHAR); |
| } |
| else |
| { |
| sep = commaSpace; |
| sepLen = strlenW(commaSpace) * sizeof(WCHAR); |
| } |
| bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR); |
| if (criteria.fFinancialInfoAvailable) |
| { |
| bytesNeeded += strlenW(available) * sizeof(WCHAR); |
| bytesNeeded += sepLen; |
| bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR); |
| if (criteria.fMeetsCriteria) |
| bytesNeeded += strlenW(yes) * sizeof(WCHAR); |
| else |
| bytesNeeded += strlenW(no) * sizeof(WCHAR); |
| } |
| else |
| bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR); |
| if (!pbFormat) |
| *pcbFormat = bytesNeeded; |
| else if (*pcbFormat < bytesNeeded) |
| { |
| *pcbFormat = bytesNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = bytesNeeded; |
| strcpyW(str, financialCriteria); |
| str += strlenW(financialCriteria); |
| if (criteria.fFinancialInfoAvailable) |
| { |
| strcpyW(str, available); |
| str += strlenW(available); |
| strcpyW(str, sep); |
| str += sepLen / sizeof(WCHAR); |
| strcpyW(str, meetsCriteria); |
| str += strlenW(meetsCriteria); |
| if (criteria.fMeetsCriteria) |
| strcpyW(str, yes); |
| else |
| strcpyW(str, no); |
| } |
| else |
| { |
| strcpyW(str, notAvailable); |
| } |
| } |
| } |
| return ret; |
| } |
| |
| static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| CERT_NAME_VALUE *value; |
| DWORD size; |
| BOOL ret; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size))) |
| { |
| if (!pbFormat) |
| *pcbFormat = value->Value.cbData; |
| else if (*pcbFormat < value->Value.cbData) |
| { |
| *pcbFormat = value->Value.cbData; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| LPWSTR str = pbFormat; |
| |
| *pcbFormat = value->Value.cbData; |
| strcpyW(str, (LPWSTR)value->Value.pbData); |
| } |
| } |
| return ret; |
| } |
| |
| typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *, |
| LPCSTR, const BYTE *, DWORD, void *, DWORD *); |
| |
| static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType, |
| DWORD formatStrType, LPCSTR lpszStructType) |
| { |
| CryptFormatObjectFunc format = NULL; |
| |
| if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING) |
| { |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return NULL; |
| } |
| if (IS_INTOID(lpszStructType)) |
| { |
| switch (LOWORD(lpszStructType)) |
| { |
| case LOWORD(X509_KEY_USAGE): |
| format = CRYPT_FormatKeyUsage; |
| break; |
| case LOWORD(X509_ALTERNATE_NAME): |
| format = CRYPT_FormatAltName; |
| break; |
| case LOWORD(X509_BASIC_CONSTRAINTS2): |
| format = CRYPT_FormatBasicConstraints2; |
| break; |
| case LOWORD(X509_AUTHORITY_KEY_ID2): |
| format = CRYPT_FormatAuthorityKeyId2; |
| break; |
| case LOWORD(X509_AUTHORITY_INFO_ACCESS): |
| format = CRYPT_FormatAuthorityInfoAccess; |
| break; |
| case LOWORD(X509_CRL_DIST_POINTS): |
| format = CRYPT_FormatCRLDistPoints; |
| break; |
| case LOWORD(X509_ENHANCED_KEY_USAGE): |
| format = CRYPT_FormatEnhancedKeyUsage; |
| break; |
| case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT): |
| format = CRYPT_FormatSpcFinancialCriteria; |
| break; |
| } |
| } |
| else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME)) |
| format = CRYPT_FormatAltName; |
| else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) |
| format = CRYPT_FormatAltName; |
| else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) |
| format = CRYPT_FormatKeyUsage; |
| else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) |
| format = CRYPT_FormatAltName; |
| else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2)) |
| format = CRYPT_FormatAltName; |
| else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) |
| format = CRYPT_FormatBasicConstraints2; |
| else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS)) |
| format = CRYPT_FormatAuthorityInfoAccess; |
| else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) |
| format = CRYPT_FormatAuthorityKeyId2; |
| else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) |
| format = CRYPT_FormatCRLDistPoints; |
| else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) |
| format = CRYPT_FormatEnhancedKeyUsage; |
| else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE)) |
| format = CRYPT_FormatNetscapeCertType; |
| else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) || |
| !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) || |
| !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) || |
| !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) || |
| !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) || |
| !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) || |
| !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT)) |
| format = CRYPT_FormatUnicodeString; |
| else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID)) |
| format = CRYPT_FormatSpcFinancialCriteria; |
| return format; |
| } |
| |
| BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType, |
| DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType, |
| const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat) |
| { |
| CryptFormatObjectFunc format = NULL; |
| HCRYPTOIDFUNCADDR hFunc = NULL; |
| BOOL ret = FALSE; |
| |
| TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType, |
| dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType), |
| pbEncoded, cbEncoded, pbFormat, pcbFormat); |
| |
| if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType, |
| dwFormatStrType, lpszStructType))) |
| { |
| static HCRYPTOIDFUNCSET set = NULL; |
| |
| if (!set) |
| set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0); |
| CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, |
| (void **)&format, &hFunc); |
| } |
| if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == |
| X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX)) |
| format = CRYPT_FormatHexString; |
| if (format) |
| ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType, |
| pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat, |
| pcbFormat); |
| if (hFunc) |
| CryptFreeOIDFunctionAddress(hFunc, 0); |
| return ret; |
| } |