From 8e1151ec182a49c5b6641a928af3bf1b2429e143 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 25 Sep 2007 14:45:29 -0700 Subject: [PATCH] crypt32: Partially implement CryptQueryObject. --- dlls/crypt32/Makefile.in | 2 + dlls/crypt32/main.c | 13 -- dlls/crypt32/object.c | 471 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 473 insertions(+), 13 deletions(-) create mode 100644 dlls/crypt32/object.c diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in index b7319bf1725..47ea46922a1 100644 --- a/dlls/crypt32/Makefile.in +++ b/dlls/crypt32/Makefile.in @@ -6,6 +6,7 @@ VPATH = @srcdir@ MODULE = crypt32.dll IMPORTLIB = libcrypt32.$(IMPLIBEXT) IMPORTS = user32 advapi32 kernel32 ntdll +DELAYIMPORTS = imagehlp C_SRCS = \ base64.c \ @@ -19,6 +20,7 @@ C_SRCS = \ filestore.c \ main.c \ msg.c \ + object.c \ oid.c \ proplist.c \ protectdata.c \ diff --git a/dlls/crypt32/main.c b/dlls/crypt32/main.c index db1744720de..f10a9c9b2bb 100644 --- a/dlls/crypt32/main.c +++ b/dlls/crypt32/main.c @@ -229,16 +229,3 @@ BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType, debugstr_a(lpszStructType), pbEncoded, cbEncoded, pbFormat, pcbFormat); return FALSE; } - -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) -{ - FIXME( "%08x %p %08x %08x %08x %p %p %p %p %p %p\n", dwObjectType, - pvObject, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, - dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, - phCertStore, phMsg, ppvContext); - return FALSE; -} diff --git a/dlls/crypt32/object.c b/dlls/crypt32/object.c new file mode 100644 index 00000000000..e12ace37a8c --- /dev/null +++ b/dlls/crypt32/object.c @@ -0,0 +1,471 @@ +/* + * 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 +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "imagehlp.h" +#include "crypt32_private.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); + } + } + CloseHandle(file); + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject, + DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType, + DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext) +{ + CERT_BLOB fileBlob; + const CERT_BLOB *blob; + HCERTSTORE store; + DWORD contentType; + 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((LPCWSTR)pvObject, &fileBlob); + blob = &fileBlob; + break; + case CERT_QUERY_OBJECT_BLOB: + blob = (const CERT_BLOB *)pvObject; + ret = TRUE; + break; + default: + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + ret = FALSE; + } + if (!ret) + return FALSE; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + 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 = 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 = 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 = CERT_QUERY_CONTENT_CTL; + } + if (ret) + { + if (pdwMsgAndCertEncodingType) + *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; + if (pdwContentType) + *pdwContentType = contentType; + 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((LPCWSTR)pvObject, &fileBlob); + blob = &fileBlob; + break; + case CERT_QUERY_OBJECT_BLOB: + blob = (const CERT_BLOB *)pvObject; + ret = TRUE; + break; + default: + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + ret = FALSE; + } + if (!ret) + return 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 = contextInterface->duplicate(context); + } + +end: + if (contextInterface && context) + contextInterface->free(context); + if (blob == &fileBlob) + CryptMemFree(blob->pbData); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType, + const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) +{ + LPCWSTR fileName = (LPCWSTR)pvObject; + HANDLE file; + BOOL ret = FALSE; + + if (dwObjectType != CERT_QUERY_OBJECT_FILE) + { + FIXME("unimplemented for non-file type %d\n", dwObjectType); + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + return 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_ReadSerializedFile(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; +} + +/* Used to decode non-embedded messages */ +static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject, + DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType, + DWORD *pdwContentType, 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; + + switch (dwObjectType) + { + case CERT_QUERY_OBJECT_FILE: + /* This isn't an embedded PKCS7 message, so just read the file + * directly + */ + ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob); + blob = &fileBlob; + break; + case CERT_QUERY_OBJECT_BLOB: + blob = (const CERT_BLOB *)pvObject; + ret = TRUE; + break; + default: + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + ret = FALSE; + } + if (!ret) + return FALSE; + + ret = FALSE; + if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) + { + 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 (msg && pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED; + } + if (!ret && + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) + { + 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 (msg && pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED; + } + if (pdwMsgAndCertEncodingType) + *pdwMsgAndCertEncodingType = encodingType; + if (msg) + { + if (phMsg) + *phMsg = msg; + if (phCertStore) + *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0, + 0, 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; + BOOL ret = FALSE; + + if (dwObjectType != CERT_QUERY_OBJECT_FILE) + { + FIXME("don't know what to do for type %d embedded signed messages\n", + dwObjectType); + SetLastError(E_INVALIDARG); + return FALSE; + } + file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + CERT_BLOB blob; + + ret = ImageGetCertificateData(file, 0, NULL, &blob.cbData); + if (ret) + { + blob.pbData = HeapAlloc(GetProcessHeap(), 0, blob.cbData); + if (blob.pbData) + { + ret = ImageGetCertificateData(file, 0, + (WIN_CERTIFICATE *)blob.pbData, &blob.cbData); + if (ret) + { + ret = CRYPT_QueryMessageObject(CERT_QUERY_OBJECT_BLOB, + &blob, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, + pdwMsgAndCertEncodingType, NULL, phCertStore, phMsg); + if (ret && pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED; + } + HeapFree(GetProcessHeap(), 0, blob.pbData); + } + } + 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 (dwExpectedContentTypeFlags & unimplementedTypes) + WARN("unimplemented for types %08x\n", + dwExpectedContentTypeFlags & unimplementedTypes); + if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)) + { + FIXME("unimplemented for anything but binary\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + 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, pdwMsgAndCertEncodingType, pdwContentType, + 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, pdwMsgAndCertEncodingType, pdwContentType, + phCertStore, phMsg); + } + if (!ret && + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED)) + { + ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject, + dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, + phCertStore, phMsg); + } + TRACE("returning %d\n"); + return ret; +}