From 03475ee8e974f1e8d0fe6eeb0b4e9c8c3ea47fef Mon Sep 17 00:00:00 2001 From: The Wine Synchronizer Date: Thu, 6 Jul 2006 10:19:03 +0000 Subject: [PATCH] Autosyncing with Wine HEAD svn path=/trunk/; revision=22883 --- reactos/dll/win32/crypt32/base64.c | 579 ++++ reactos/dll/win32/crypt32/cert.c | 1168 ++++++- reactos/dll/win32/crypt32/context.c | 308 ++ reactos/dll/win32/crypt32/crl.c | 535 +++ reactos/dll/win32/crypt32/crypt32.rbuild | 19 +- reactos/dll/win32/crypt32/crypt32.rc | 2 +- reactos/dll/win32/crypt32/crypt32.spec | 37 +- reactos/dll/win32/crypt32/crypt32_De.rc | 4 +- reactos/dll/win32/crypt32/crypt32_En.rc | 2 +- reactos/dll/win32/crypt32/crypt32_Ko.rc | 2 +- reactos/dll/win32/crypt32/crypt32_No.rc | 2 +- reactos/dll/win32/crypt32/crypt32_private.h | 130 +- reactos/dll/win32/crypt32/crypt32_ros.diff | 15 +- reactos/dll/win32/crypt32/cryptres.h | 2 +- reactos/dll/win32/crypt32/decode.c | 3281 ++++++++++++++++++ reactos/dll/win32/crypt32/encode.c | 3307 +------------------ reactos/dll/win32/crypt32/main.c | 2 +- reactos/dll/win32/crypt32/oid.c | 19 +- reactos/dll/win32/crypt32/proplist.c | 4 +- reactos/dll/win32/crypt32/protectdata.c | 6 +- reactos/dll/win32/crypt32/serialize.c | 170 +- reactos/dll/win32/crypt32/store.c | 1786 ++++------ reactos/dll/win32/crypt32/str.c | 2 +- reactos/dll/win32/crypt32/version.rc | 28 + 24 files changed, 6998 insertions(+), 4412 deletions(-) create mode 100644 reactos/dll/win32/crypt32/base64.c create mode 100644 reactos/dll/win32/crypt32/context.c create mode 100644 reactos/dll/win32/crypt32/crl.c create mode 100644 reactos/dll/win32/crypt32/decode.c create mode 100644 reactos/dll/win32/crypt32/version.rc diff --git a/reactos/dll/win32/crypt32/base64.c b/reactos/dll/win32/crypt32/base64.c new file mode 100644 index 00000000000..e4c2dd49255 --- /dev/null +++ b/reactos/dll/win32/crypt32/base64.c @@ -0,0 +1,579 @@ +/* + * base64 encoder/decoder + * + * Copyright 2005 by Kai Blin + * Copyright 2006 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 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 "winerror.h" +#include "wincrypt.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +#define CERT_HEADER "-----BEGIN CERTIFICATE-----" +#define CERT_TRAILER "-----END CERTIFICATE-----" +#define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----" +#define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----" +#define X509_HEADER "-----BEGIN X509 CRL-----" +#define X509_TRAILER "-----END X509 CRL-----" + +static const char b64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString); + +static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) +{ + BOOL ret = TRUE; + + if (*pcchString < cbBinary) + { + if (!pszString) + *pcchString = cbBinary; + else + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + *pcchString = cbBinary; + ret = FALSE; + } + } + else + { + if (cbBinary) + memcpy(pszString, pbBinary, cbBinary); + *pcchString = cbBinary; + } + return ret; +} + +static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep, + char* out_buf, DWORD *out_len) +{ + int div, i; + const BYTE *d = in_buf; + int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0; + DWORD needed; + LPSTR ptr; + + TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes); + needed = bytes + pad_bytes + 1; + needed += (needed / 64 + 1) * strlen(sep); + + if (needed > *out_len) + { + *out_len = needed; + return ERROR_INSUFFICIENT_BUFFER; + } + else + *out_len = needed; + + /* Three bytes of input give 4 chars of output */ + div = in_len / 3; + + ptr = out_buf; + i = 0; + while (div > 0) + { + if (i && i % 64 == 0) + { + strcpy(ptr, sep); + ptr += strlen(sep); + } + /* first char is the first 6 bits of the first byte*/ + *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; + /* second char is the last 2 bits of the first byte and the first 4 + * bits of the second byte */ + *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; + /* third char is the last 4 bits of the second byte and the first 2 + * bits of the third byte */ + *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)]; + /* fourth char is the remaining 6 bits of the third byte */ + *ptr++ = b64[ d[2] & 0x3f]; + i += 4; + d += 3; + div--; + } + + switch(pad_bytes) + { + case 1: + /* first char is the first 6 bits of the first byte*/ + *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; + /* second char is the last 2 bits of the first byte and the first 4 + * bits of the second byte */ + *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; + /* third char is the last 4 bits of the second byte padded with + * two zeroes */ + *ptr++ = b64[ ((d[1] << 2) & 0x3c) ]; + /* fourth char is a = to indicate one byte of padding */ + *ptr++ = '='; + break; + case 2: + /* first char is the first 6 bits of the first byte*/ + *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; + /* second char is the last 2 bits of the first byte padded with + * four zeroes*/ + *ptr++ = b64[ ((d[0] << 4) & 0x30)]; + /* third char is = to indicate padding */ + *ptr++ = '='; + /* fourth char is = to indicate padding */ + *ptr++ = '='; + break; + } + strcpy(ptr, sep); + + return ERROR_SUCCESS; +} + +static BOOL BinaryToBase64A(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) +{ + static const char crlf[] = "\r\n", lf[] = "\n"; + BOOL ret = TRUE; + LPCSTR header = NULL, trailer = NULL, sep = NULL; + DWORD charsNeeded; + + if (dwFlags & CRYPT_STRING_NOCR) + sep = lf; + else + sep = crlf; + switch (dwFlags & 0x7fffffff) + { + case CRYPT_STRING_BASE64: + /* no header or footer */ + break; + case CRYPT_STRING_BASE64HEADER: + header = CERT_HEADER; + trailer = CERT_TRAILER; + break; + case CRYPT_STRING_BASE64REQUESTHEADER: + header = CERT_REQUEST_HEADER; + trailer = CERT_REQUEST_TRAILER; + break; + case CRYPT_STRING_BASE64X509CRLHEADER: + header = X509_HEADER; + trailer = X509_TRAILER; + break; + } + + charsNeeded = 0; + encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded); + charsNeeded += strlen(sep); + if (header) + charsNeeded += strlen(header) + strlen(sep); + if (trailer) + charsNeeded += strlen(trailer) + strlen(sep); + if (charsNeeded <= *pcchString) + { + LPSTR ptr = pszString; + DWORD size = charsNeeded; + + if (header) + { + strcpy(ptr, header); + ptr += strlen(ptr); + strcpy(ptr, sep); + ptr += strlen(sep); + } + encodeBase64A(pbBinary, cbBinary, sep, ptr, &size); + ptr += size - 1; + if (trailer) + { + strcpy(ptr, trailer); + ptr += strlen(ptr); + strcpy(ptr, sep); + ptr += strlen(sep); + } + *pcchString = charsNeeded - 1; + } + else if (pszString) + { + *pcchString = charsNeeded; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + ret = FALSE; + } + else + *pcchString = charsNeeded; + return ret; +} + +BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) +{ + BinaryToStringAFunc encoder = NULL; + + TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString, + pcchString); + + if (!pbBinary) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!pcchString) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + switch (dwFlags & 0x7fffffff) + { + case CRYPT_STRING_BINARY: + encoder = EncodeBinaryToBinaryA; + break; + case CRYPT_STRING_BASE64: + case CRYPT_STRING_BASE64HEADER: + case CRYPT_STRING_BASE64REQUESTHEADER: + case CRYPT_STRING_BASE64X509CRLHEADER: + encoder = BinaryToBase64A; + break; + case CRYPT_STRING_HEX: + case CRYPT_STRING_HEXASCII: + case CRYPT_STRING_HEXADDR: + case CRYPT_STRING_HEXASCIIADDR: + FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff); + /* fall through */ + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString); +} + +static inline BYTE decodeBase64Byte(char c) +{ + BYTE ret; + + if (c >= 'A' && c <= 'Z') + ret = c - 'A'; + else if (c >= 'a' && c <= 'z') + ret = c - 'a' + 26; + else if (c >= '0' && c <= '9') + ret = c - '0' + 52; + else if (c == '+') + ret = 62; + else if (c == '/') + ret = 63; + else + ret = 64; + return ret; +} + +static LONG decodeBase64Block(const char *in_buf, int in_len, + const char **nextBlock, PBYTE out_buf, DWORD *out_len) +{ + int len = in_len, i; + const char *d = in_buf; + int ip0, ip1, ip2, ip3; + + if (len < 4) + return ERROR_INVALID_DATA; + + i = 0; + if (d[2] == '=') + { + if ((ip0 = decodeBase64Byte(d[0])) > 63) + return ERROR_INVALID_DATA; + if ((ip1 = decodeBase64Byte(d[1])) > 63) + return ERROR_INVALID_DATA; + + if (out_buf) + out_buf[i] = (ip0 << 2) | (ip1 >> 4); + i++; + } + else if (d[3] == '=') + { + if ((ip0 = decodeBase64Byte(d[0])) > 63) + return ERROR_INVALID_DATA; + if ((ip1 = decodeBase64Byte(d[1])) > 63) + return ERROR_INVALID_DATA; + if ((ip2 = decodeBase64Byte(d[2])) > 63) + return ERROR_INVALID_DATA; + + if (out_buf) + { + out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); + out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); + } + i += 2; + } + else + { + if ((ip0 = decodeBase64Byte(d[0])) > 63) + return ERROR_INVALID_DATA; + if ((ip1 = decodeBase64Byte(d[1])) > 63) + return ERROR_INVALID_DATA; + if ((ip2 = decodeBase64Byte(d[2])) > 63) + return ERROR_INVALID_DATA; + if ((ip3 = decodeBase64Byte(d[3])) > 63) + return ERROR_INVALID_DATA; + + if (out_buf) + { + out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); + out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); + out_buf[i + 2] = (ip2 << 6) | ip3; + } + i += 3; + } + if (len >= 6 && d[4] == '\r' && d[5] == '\n') + *nextBlock = d + 6; + else if (len >= 5 && d[4] == '\n') + *nextBlock = d + 5; + else if (len >= 4 && d[4]) + *nextBlock = d + 4; + else + *nextBlock = NULL; + *out_len = i; + return ERROR_SUCCESS; +} + +/* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the + * string to convert. + */ +typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags); + +static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = ERROR_SUCCESS; + const char *nextBlock; + DWORD outLen = 0; + + nextBlock = pszString; + while (nextBlock && !ret) + { + DWORD len = 0; + + ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString), + &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len); + if (!ret) + outLen += len; + if (cchString - (nextBlock - pszString) <= 0) + nextBlock = NULL; + } + *pcbBinary = outLen; + if (!ret) + { + if (pdwSkip) + *pdwSkip = 0; + if (pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64; + } + else if (ret == ERROR_INSUFFICIENT_BUFFER) + { + if (!pbBinary) + ret = ERROR_SUCCESS; + } + return ret; +} + +static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString, + DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary, + DWORD *pcbBinary, DWORD *pdwSkip) +{ + LONG ret; + LPCSTR ptr; + + if (cchString > strlen(header) + strlen(trailer) + && (ptr = strstr(pszString, header)) != NULL) + { + LPCSTR trailerSpot = pszString + cchString - strlen(trailer); + + if (pszString[cchString - 1] == '\n') + { + cchString--; + trailerSpot--; + } + if (pszString[cchString - 1] == '\r') + { + cchString--; + trailerSpot--; + } + if (!strncmp(trailerSpot, trailer, strlen(trailer))) + { + if (pdwSkip) + *pdwSkip = ptr - pszString; + ptr += strlen(header); + if (*ptr == '\r') ptr++; + if (*ptr == '\n') ptr++; + cchString -= ptr - pszString + strlen(trailer); + ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL, + NULL); + } + else + ret = ERROR_INVALID_DATA; + } + else + ret = ERROR_INVALID_DATA; + return ret; +} + +static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString, + CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip); + + if (!ret && pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64HEADER; + return ret; +} + +static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString, + CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip); + + if (!ret && pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER; + return ret; +} + +static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString, + X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip); + + if (!ret && pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER; + return ret; +} + +static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret; + + ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + if (ret == ERROR_INVALID_DATA) + ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + return ret; +} + +static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = ERROR_SUCCESS; + + if (*pcbBinary < cchString) + { + if (!pbBinary) + *pcbBinary = cchString; + else + { + ret = ERROR_INSUFFICIENT_BUFFER; + *pcbBinary = cchString; + } + } + else + { + if (cchString) + memcpy(pbBinary, pszString, cchString); + *pcbBinary = cchString; + } + return ret; +} + +static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret; + + ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + if (ret == ERROR_INVALID_DATA) + ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + if (ret == ERROR_INVALID_DATA) + ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + return ret; +} + +BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString, + DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, + DWORD *pdwSkip, DWORD *pdwFlags) +{ + StringToBinaryAFunc decoder; + LONG ret; + + TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_a(pszString), + cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags); + + if (!pszString) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + /* Only the bottom byte contains valid types */ + if (dwFlags & 0xfffffff0) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + switch (dwFlags) + { + case CRYPT_STRING_BASE64_ANY: + decoder = Base64AnyToBinaryA; + break; + case CRYPT_STRING_BASE64: + decoder = Base64ToBinaryA; + break; + case CRYPT_STRING_BASE64HEADER: + decoder = Base64HeaderToBinaryA; + break; + case CRYPT_STRING_BASE64REQUESTHEADER: + decoder = Base64RequestHeaderToBinaryA; + break; + case CRYPT_STRING_BASE64X509CRLHEADER: + decoder = Base64X509HeaderToBinaryA; + break; + case CRYPT_STRING_BINARY: + decoder = DecodeBinaryToBinaryA; + break; + case CRYPT_STRING_ANY: + decoder = DecodeAnyA; + break; + case CRYPT_STRING_HEX: + case CRYPT_STRING_HEXASCII: + case CRYPT_STRING_HEXADDR: + case CRYPT_STRING_HEXASCIIADDR: + FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff); + /* fall through */ + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!cchString) + cchString = strlen(pszString); + ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags); + if (ret) + SetLastError(ret); + return (ret == ERROR_SUCCESS) ? TRUE : FALSE; +} diff --git a/reactos/dll/win32/crypt32/cert.c b/reactos/dll/win32/crypt32/cert.c index 52b8ce11511..2bcc4f73ad5 100644 --- a/reactos/dll/win32/crypt32/cert.c +++ b/reactos/dll/win32/crypt32/cert.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */ @@ -22,11 +22,771 @@ #include "windef.h" #include "winbase.h" #include "wincrypt.h" +#include "winnls.h" +#include "rpc.h" #include "wine/debug.h" #include "crypt32_private.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); +/* Internal version of CertGetCertificateContextProperty that gets properties + * directly from the context (or the context it's linked to, depending on its + * type.) Doesn't handle special-case properties, since they are handled by + * CertGetCertificateContextProperty, and are particular to the store in which + * the property exists (which is separate from the context.) + */ +static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId, + void *pvData, DWORD *pcbData); + +/* Internal version of CertSetCertificateContextProperty that sets properties + * directly on the context (or the context it's linked to, depending on its + * type.) Doesn't handle special cases, since they're handled by + * CertSetCertificateContextProperty anyway. + */ +static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId, + DWORD dwFlags, const void *pvData); + +BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, + DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext) +{ + PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType, + pbCertEncoded, cbCertEncoded); + BOOL ret; + + TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType, + pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext); + + if (cert) + { + ret = CertAddCertificateContextToStore(hCertStore, cert, + dwAddDisposition, ppCertContext); + CertFreeCertificateContext(cert); + } + else + ret = FALSE; + return ret; +} + +PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType, + const BYTE *pbCertEncoded, DWORD cbCertEncoded) +{ + PCERT_CONTEXT cert = NULL; + BOOL ret; + PCERT_INFO certInfo = NULL; + DWORD size = 0; + + TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, + cbCertEncoded); + + ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED, + pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&certInfo, &size); + if (ret) + { + BYTE *data = NULL; + + cert = (PCERT_CONTEXT)Context_CreateDataContext(sizeof(CERT_CONTEXT)); + if (!cert) + goto end; + data = CryptMemAlloc(cbCertEncoded); + if (!data) + { + CryptMemFree(cert); + cert = NULL; + goto end; + } + memcpy(data, pbCertEncoded, cbCertEncoded); + cert->dwCertEncodingType = dwCertEncodingType; + cert->pbCertEncoded = data; + cert->cbCertEncoded = cbCertEncoded; + cert->pCertInfo = certInfo; + cert->hCertStore = 0; + } + +end: + return (PCCERT_CONTEXT)cert; +} + +PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext( + PCCERT_CONTEXT pCertContext) +{ + TRACE("(%p)\n", pCertContext); + Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT)); + return pCertContext; +} + +static void CertDataContext_Free(void *context) +{ + PCERT_CONTEXT certContext = (PCERT_CONTEXT)context; + + CryptMemFree(certContext->pbCertEncoded); + LocalFree(certContext->pCertInfo); +} + +BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) +{ + TRACE("(%p)\n", pCertContext); + + if (pCertContext) + Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT), + CertDataContext_Free); + return TRUE; +} + +DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext, + DWORD dwPropId) +{ + PCONTEXT_PROPERTY_LIST properties = Context_GetProperties( + (void *)pCertContext, sizeof(CERT_CONTEXT)); + DWORD ret; + + TRACE("(%p, %ld)\n", pCertContext, dwPropId); + + if (properties) + ret = ContextPropertyList_EnumPropIDs(properties, dwPropId); + else + ret = 0; + return ret; +} + +static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId, + ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, + DWORD *pcbData) +{ + BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, + pcbData); + if (ret) + { + CRYPT_DATA_BLOB blob = { *pcbData, pvData }; + + ret = CertContext_SetProperty(context, dwPropId, 0, &blob); + } + return ret; +} + +static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId, + void *pvData, DWORD *pcbData) +{ + PCCERT_CONTEXT pCertContext = (PCCERT_CONTEXT)context; + PCONTEXT_PROPERTY_LIST properties = + Context_GetProperties(context, sizeof(CERT_CONTEXT)); + BOOL ret; + CRYPT_DATA_BLOB blob; + + TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData); + + if (properties) + ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob); + else + ret = FALSE; + if (ret) + { + if (!pvData) + { + *pcbData = blob.cbData; + ret = TRUE; + } + else if (*pcbData < blob.cbData) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = blob.cbData; + } + else + { + memcpy(pvData, blob.pbData, blob.cbData); + *pcbData = blob.cbData; + ret = TRUE; + } + } + else + { + /* Implicit properties */ + switch (dwPropId) + { + case CERT_SHA1_HASH_PROP_ID: + ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1, + pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData, + pcbData); + break; + case CERT_MD5_HASH_PROP_ID: + ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5, + pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData, + pcbData); + break; + case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: + ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5, + pCertContext->pCertInfo->Subject.pbData, + pCertContext->pCertInfo->Subject.cbData, + pvData, pcbData); + break; + case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: + ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5, + pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, + pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, + pvData, pcbData); + break; + case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: + ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5, + pCertContext->pCertInfo->SerialNumber.pbData, + pCertContext->pCertInfo->SerialNumber.cbData, + pvData, pcbData); + break; + case CERT_SIGNATURE_HASH_PROP_ID: + FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n"); + SetLastError(CRYPT_E_NOT_FOUND); + break; + default: + SetLastError(CRYPT_E_NOT_FOUND); + } + } + TRACE("returning %d\n", ret); + return ret; +} + +/* info is assumed to be a CRYPT_KEY_PROV_INFO, followed by its container name, + * provider name, and any provider parameters, in a contiguous buffer, but + * where info's pointers are assumed to be invalid. Upon return, info's + * pointers point to the appropriate memory locations. + */ +static void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info) +{ + DWORD i, containerLen, provNameLen; + LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO); + + info->pwszContainerName = (LPWSTR)data; + containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); + data += containerLen; + + info->pwszProvName = (LPWSTR)data; + provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); + data += provNameLen; + + info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data; + data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM); + + for (i = 0; i < info->cProvParam; i++) + { + info->rgProvParam[i].pbData = data; + data += info->rgProvParam[i].cbData; + } +} + +BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, + DWORD dwPropId, void *pvData, DWORD *pcbData) +{ + BOOL ret; + + TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData); + + switch (dwPropId) + { + case 0: + case CERT_CERT_PROP_ID: + case CERT_CRL_PROP_ID: + case CERT_CTL_PROP_ID: + SetLastError(E_INVALIDARG); + ret = FALSE; + break; + case CERT_ACCESS_STATE_PROP_ID: + if (!pvData) + { + *pcbData = sizeof(DWORD); + ret = TRUE; + } + else if (*pcbData < sizeof(DWORD)) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = sizeof(DWORD); + ret = FALSE; + } + else + { + *(DWORD *)pvData = + CertStore_GetAccessState(pCertContext->hCertStore); + ret = TRUE; + } + break; + case CERT_KEY_PROV_INFO_PROP_ID: + ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData, + pcbData); + if (ret && pvData) + CRYPT_FixKeyProvInfoPointers((PCRYPT_KEY_PROV_INFO)pvData); + break; + default: + ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData, + pcbData); + } + + TRACE("returning %d\n", ret); + return ret; +} + +/* Copies key provider info from from into to, where to is assumed to be a + * contiguous buffer of memory large enough for from and all its associated + * data, but whose pointers are uninitialized. + * Upon return, to contains a contiguous copy of from, packed in the following + * order: + * - CRYPT_KEY_PROV_INFO + * - pwszContainerName + * - pwszProvName + * - rgProvParam[0]... + */ +static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to, + PCRYPT_KEY_PROV_INFO from) +{ + DWORD i; + LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO); + + to->pwszContainerName = (LPWSTR)nextData; + lstrcpyW(to->pwszContainerName, from->pwszContainerName); + nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR); + to->pwszProvName = (LPWSTR)nextData; + lstrcpyW(to->pwszProvName, from->pwszProvName); + nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR); + to->dwProvType = from->dwProvType; + to->dwFlags = from->dwFlags; + to->cProvParam = from->cProvParam; + to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData; + nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM); + to->dwKeySpec = from->dwKeySpec; + for (i = 0; i < to->cProvParam; i++) + { + memcpy(&to->rgProvParam[i], &from->rgProvParam[i], + sizeof(CRYPT_KEY_PROV_PARAM)); + to->rgProvParam[i].pbData = nextData; + memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData, + from->rgProvParam[i].cbData); + nextData += from->rgProvParam[i].cbData; + } +} + +static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties, + PCRYPT_KEY_PROV_INFO info) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize; + + containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); + provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); + size += containerSize + provNameSize; + for (i = 0; i < info->cProvParam; i++) + size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData; + buf = CryptMemAlloc(size); + if (buf) + { + CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info); + ret = ContextPropertyList_SetProperty(properties, + CERT_KEY_PROV_INFO_PROP_ID, buf, size); + CryptMemFree(buf); + } + else + ret = FALSE; + return ret; +} + +static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId, + DWORD dwFlags, const void *pvData) +{ + PCONTEXT_PROPERTY_LIST properties = + Context_GetProperties(context, sizeof(CERT_CONTEXT)); + BOOL ret; + + TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData); + + if (!properties) + ret = FALSE; + else if (!pvData) + { + ContextPropertyList_RemoveProperty(properties, dwPropId); + ret = TRUE; + } + else + { + switch (dwPropId) + { + case CERT_AUTO_ENROLL_PROP_ID: + case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ + case CERT_DESCRIPTION_PROP_ID: + case CERT_FRIENDLY_NAME_PROP_ID: + case CERT_HASH_PROP_ID: + case CERT_KEY_IDENTIFIER_PROP_ID: + case CERT_MD5_HASH_PROP_ID: + case CERT_NEXT_UPDATE_LOCATION_PROP_ID: + case CERT_PUBKEY_ALG_PARA_PROP_ID: + case CERT_PVK_FILE_PROP_ID: + case CERT_SIGNATURE_HASH_PROP_ID: + case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: + case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_ENROLLMENT_PROP_ID: + case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: + case CERT_RENEWAL_PROP_ID: + { + PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData; + + ret = ContextPropertyList_SetProperty(properties, dwPropId, + blob->pbData, blob->cbData); + break; + } + case CERT_DATE_STAMP_PROP_ID: + ret = ContextPropertyList_SetProperty(properties, dwPropId, + (LPBYTE)pvData, sizeof(FILETIME)); + break; + case CERT_KEY_PROV_INFO_PROP_ID: + ret = CertContext_SetKeyProvInfoProperty(properties, + (PCRYPT_KEY_PROV_INFO)pvData); + break; + default: + FIXME("%ld: stub\n", dwPropId); + ret = FALSE; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext, + DWORD dwPropId, DWORD dwFlags, const void *pvData) +{ + BOOL ret; + + TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData); + + /* Handle special cases for "read-only"/invalid prop IDs. Windows just + * crashes on most of these, I'll be safer. + */ + switch (dwPropId) + { + case 0: + case CERT_ACCESS_STATE_PROP_ID: + case CERT_CERT_PROP_ID: + case CERT_CRL_PROP_ID: + case CERT_CTL_PROP_ID: + SetLastError(E_INVALIDARG); + return FALSE; + } + ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags, + pvData); + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType, + PCERT_INFO pCertId1, PCERT_INFO pCertId2) +{ + TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2); + + return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer, + &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber, + &pCertId2->SerialNumber); +} + +BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType, + PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2) +{ + BOOL ret; + + TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2); + + if (pCertName1->cbData == pCertName2->cbData) + { + if (pCertName1->cbData) + ret = !memcmp(pCertName1->pbData, pCertName2->pbData, + pCertName1->cbData); + else + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +/* Returns the number of significant bytes in pInt, where a byte is + * insignificant if it's a leading 0 for positive numbers or a leading 0xff + * for negative numbers. pInt is assumed to be little-endian. + */ +static DWORD CRYPT_significantBytes(PCRYPT_INTEGER_BLOB pInt) +{ + DWORD ret = pInt->cbData; + + while (ret > 1) + { + if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0) + ret--; + else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff) + ret--; + else + break; + } + return ret; +} + +BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1, + PCRYPT_INTEGER_BLOB pInt2) +{ + BOOL ret; + DWORD cb1, cb2; + + TRACE("(%p, %p)\n", pInt1, pInt2); + + cb1 = CRYPT_significantBytes(pInt1); + cb2 = CRYPT_significantBytes(pInt2); + if (cb1 == cb2) + { + if (cb1) + ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1); + else + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType, + PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2) +{ + BOOL ret; + + TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2); + + if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData && + pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits) + { + if (pPublicKey2->PublicKey.cbData) + ret = !memcmp(pPublicKey1->PublicKey.pbData, + pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData); + else + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara); + +static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + return TRUE; +} + +static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + BYTE hash[16]; + DWORD size = sizeof(hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_MD5_HASH_PROP_ID, hash, &size); + if (ret) + { + const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; + + if (size == pHash->cbData) + ret = !memcmp(pHash->pbData, hash, size); + else + ret = FALSE; + } + return ret; +} + +static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + BYTE hash[20]; + DWORD size = sizeof(hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_SHA1_HASH_PROP_ID, hash, &size); + if (ret) + { + const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; + + if (size == pHash->cbData) + ret = !memcmp(pHash->pbData, hash, size); + else + ret = FALSE; + } + return ret; +} + +static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare; + BOOL ret; + + if (dwType & CERT_INFO_SUBJECT_FLAG) + toCompare = &pCertContext->pCertInfo->Subject; + else + toCompare = &pCertContext->pCertInfo->Issuer; + ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, + toCompare, blob); + return ret; +} + +static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, + DWORD dwType, DWORD dwFlags, const void *pvPara) +{ + CERT_INFO *pCertInfo = (CERT_INFO *)pvPara; + + return CertCompareCertificateName(pCertContext->dwCertEncodingType, + &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject); +} + +static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, + DWORD dwType, DWORD dwFlags, const void *pvPara) +{ + return compare_cert_by_subject_cert(pCertContext, dwType, dwFlags, + ((PCCERT_CONTEXT)pvPara)->pCertInfo); +} + +PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara, + PCCERT_CONTEXT pPrevCertContext) +{ + PCCERT_CONTEXT ret; + CertCompareFunc compare; + + TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType, + dwFlags, dwType, pvPara, pPrevCertContext); + + switch (dwType >> CERT_COMPARE_SHIFT) + { + case CERT_COMPARE_ANY: + compare = compare_cert_any; + break; + case CERT_COMPARE_MD5_HASH: + compare = compare_cert_by_md5_hash; + break; + case CERT_COMPARE_SHA1_HASH: + compare = compare_cert_by_sha1_hash; + break; + case CERT_COMPARE_NAME: + compare = compare_cert_by_name; + break; + case CERT_COMPARE_SUBJECT_CERT: + compare = compare_cert_by_subject_cert; + break; + case CERT_COMPARE_ISSUER_OF: + compare = compare_cert_by_issuer; + break; + default: + FIXME("find type %08lx unimplemented\n", dwType); + compare = NULL; + } + + if (compare) + { + BOOL matches = FALSE; + + ret = pPrevCertContext; + do { + ret = CertEnumCertificatesInStore(hCertStore, ret); + if (ret) + matches = compare(ret, dwType, dwFlags, pvPara); + } while (ret != NULL && !matches); + if (!ret) + SetLastError(CRYPT_E_NOT_FOUND); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + return ret; +} + +PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, PCERT_INFO pCertId) +{ + TRACE("(%p, %08lx, %p)\n", hCertStore, dwCertEncodingType, pCertId); + + if (!pCertId) + { + SetLastError(E_INVALIDARG); + return NULL; + } + return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0, + CERT_FIND_SUBJECT_CERT, pCertId, NULL); +} + +BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject, + PCCERT_CONTEXT pIssuer, DWORD *pdwFlags) +{ + static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG | + CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; + + if (*pdwFlags & ~supportedFlags) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (*pdwFlags & CERT_STORE_REVOCATION_FLAG) + { + PCCRL_CONTEXT crl = CertFindCRLInStore(pSubject->hCertStore, + pSubject->dwCertEncodingType, 0, CRL_FIND_ISSUED_BY, pSubject, NULL); + + if (crl) + { + FIXME("check CRL for subject\n"); + } + else + *pdwFlags |= CERT_STORE_NO_CRL_FLAG; + } + if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG) + { + if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo)) + *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG; + } + if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG) + { + if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject, + CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL)) + *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG; + } + return TRUE; +} + +PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore, + PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext, + DWORD *pdwFlags) +{ + PCCERT_CONTEXT ret; + + TRACE("(%p, %p, %p, %08lx)\n", hCertStore, pSubjectContext, + pPrevIssuerContext, *pdwFlags); + + if (!pSubjectContext) + { + SetLastError(E_INVALIDARG); + return NULL; + } + + ret = CertFindCertificateInStore(hCertStore, + pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF, + pSubjectContext, pPrevIssuerContext); + if (ret) + { + if (!CertVerifySubjectCertificateContext(pSubjectContext, ret, + pdwFlags)) + { + CertFreeCertificateContext(ret); + ret = NULL; + } + } + + return ret; +} + PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr, CRYPT_ATTRIBUTE rgAttr[]) { @@ -191,6 +951,41 @@ BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv, CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL); } +static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv, + DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo, + PCERT_SIGNED_CONTENT_INFO signedCert) +{ + BOOL ret; + ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId); + HCRYPTKEY key; + + /* Load the default provider if necessary */ + if (!hCryptProv) + hCryptProv = CRYPT_GetDefaultProvider(); + ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, + pubKeyInfo, algID, 0, NULL, &key); + if (ret) + { + HCRYPTHASH hash; + + /* Some key algorithms aren't hash algorithms, so map them */ + if (algID == CALG_RSA_SIGN || algID == CALG_RSA_KEYX) + algID = CALG_SHA1; + ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash); + if (ret) + { + ret = CryptHashData(hash, signedCert->ToBeSigned.pbData, + signedCert->ToBeSigned.cbData, 0); + if (ret) + ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData, + signedCert->Signature.cbData, key, NULL, 0); + CryptDestroyHash(hash); + } + CryptDestroyKey(key); + } + return ret; +} + BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject, DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved) @@ -229,7 +1024,7 @@ BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv, break; } default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } @@ -247,65 +1042,35 @@ BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv, switch (dwIssuerType) { case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY: - { - PCERT_PUBLIC_KEY_INFO pubKeyInfo = - (PCERT_PUBLIC_KEY_INFO)pvIssuer; - ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId); - - if (algID) - { - HCRYPTKEY key; - - ret = CryptImportPublicKeyInfoEx(hCryptProv, - dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key); - if (ret) - { - HCRYPTHASH hash; - - ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash); - if (ret) - { - ret = CryptHashData(hash, - signedCert->ToBeSigned.pbData, - signedCert->ToBeSigned.cbData, 0); - if (ret) - { - ret = CryptVerifySignatureW(hash, - signedCert->Signature.pbData, - signedCert->Signature.cbData, key, NULL, 0); - } - CryptDestroyHash(hash); - } - CryptDestroyKey(key); - } - } - else - { - SetLastError(NTE_BAD_ALGID); - ret = FALSE; - } + ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv, + dwCertEncodingType, (PCERT_PUBLIC_KEY_INFO)pvIssuer, + signedCert); break; - } case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT: + ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv, + dwCertEncodingType, + &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo, + signedCert); + break; case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: - FIXME("issuer type %ld: stub\n", dwIssuerType); + FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n"); ret = FALSE; break; case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL: if (pvIssuer) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } else { FIXME("unimplemented for NULL signer\n"); - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } break; default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } LocalFree(signedCert); @@ -321,14 +1086,14 @@ BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags, DWORD bytesNeeded; BOOL ret = TRUE; - TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage); - if (!pCertContext || !pcbUsage) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } + TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage); + if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG)) { DWORD propSize = 0; @@ -713,3 +1478,314 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, CryptMemFree(validUsages.rgpszUsageIdentifier); return ret; } + +/* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if + * pInfo is NULL, from the attributes of hProv. + */ +static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context, + PCRYPT_KEY_PROV_INFO pInfo, HCRYPTPROV hProv) +{ + CRYPT_KEY_PROV_INFO info = { 0 }; + BOOL ret; + + if (!pInfo) + { + DWORD size; + int len; + + ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0); + if (ret) + { + LPSTR szContainer = CryptMemAlloc(size); + + if (szContainer) + { + ret = CryptGetProvParam(hProv, PP_CONTAINER, + (BYTE *)szContainer, &size, 0); + if (ret) + { + len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1, + NULL, 0); + if (len) + { + info.pwszContainerName = CryptMemAlloc(len * + sizeof(WCHAR)); + len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1, + info.pwszContainerName, len); + } + } + CryptMemFree(szContainer); + } + } + ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0); + if (ret) + { + LPSTR szProvider = CryptMemAlloc(size); + + if (szProvider) + { + ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider, + &size, 0); + if (ret) + { + len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1, + NULL, 0); + if (len) + { + info.pwszProvName = CryptMemAlloc(len * + sizeof(WCHAR)); + len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1, + info.pwszProvName, len); + } + } + CryptMemFree(szProvider); + } + } + size = sizeof(info.dwKeySpec); + ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec, + &size, 0); + if (!ret) + info.dwKeySpec = AT_SIGNATURE; + size = sizeof(info.dwProvType); + ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType, + &size, 0); + if (!ret) + info.dwProvType = PROV_RSA_FULL; + pInfo = &info; + } + + ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID, + 0, pInfo); + + if (pInfo == &info) + { + CryptMemFree(info.pwszContainerName); + CryptMemFree(info.pwszProvName); + } +} + +/* Creates a signed certificate context from the unsigned, encoded certificate + * in blob, using the crypto provider hProv and the signature algorithm sigAlgo. + */ +static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob, + HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo) +{ + PCCERT_CONTEXT context = NULL; + BOOL ret; + DWORD sigSize = 0; + + ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING, + blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize); + if (ret) + { + LPBYTE sig = CryptMemAlloc(sigSize); + + ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING, + blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize); + if (ret) + { + CERT_SIGNED_CONTENT_INFO signedInfo; + BYTE *encodedSignedCert = NULL; + DWORD encodedSignedCertSize = 0; + + signedInfo.ToBeSigned.cbData = blob->cbData; + signedInfo.ToBeSigned.pbData = blob->pbData; + memcpy(&signedInfo.SignatureAlgorithm, sigAlgo, + sizeof(signedInfo.SignatureAlgorithm)); + signedInfo.Signature.cbData = sigSize; + signedInfo.Signature.pbData = sig; + signedInfo.Signature.cUnusedBits = 0; + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, + &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, + (BYTE *)&encodedSignedCert, &encodedSignedCertSize); + if (ret) + { + context = CertCreateCertificateContext(X509_ASN_ENCODING, + encodedSignedCert, encodedSignedCertSize); + LocalFree(encodedSignedCert); + } + } + CryptMemFree(sig); + } + return context; +} + +/* Copies data from the parameters into info, where: + * pSubjectIssuerBlob: Specifies both the subject and issuer for info. + * Must not be NULL + * pSignatureAlgorithm: Optional. + * pStartTime: The starting time of the certificate. If NULL, the current + * system time is used. + * pEndTime: The ending time of the certificate. If NULL, one year past the + * starting time is used. + * pubKey: The public key of the certificate. Must not be NULL. + * pExtensions: Extensions to be included with the certificate. Optional. + */ +static void CRYPT_MakeCertInfo(PCERT_INFO info, + PCERT_NAME_BLOB pSubjectIssuerBlob, + PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime, + PSYSTEMTIME pEndTime, PCERT_PUBLIC_KEY_INFO pubKey, + PCERT_EXTENSIONS pExtensions) +{ + /* FIXME: what serial number to use? */ + static const BYTE serialNum[] = { 1 }; + static CHAR oid[] = szOID_RSA_SHA1RSA; + + assert(info); + assert(pSubjectIssuerBlob); + assert(pubKey); + + info->dwVersion = CERT_V3; + info->SerialNumber.cbData = sizeof(serialNum); + info->SerialNumber.pbData = (LPBYTE)serialNum; + if (pSignatureAlgorithm) + memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm, + sizeof(info->SignatureAlgorithm)); + else + { + info->SignatureAlgorithm.pszObjId = oid; + info->SignatureAlgorithm.Parameters.cbData = 0; + info->SignatureAlgorithm.Parameters.pbData = NULL; + } + info->Issuer.cbData = pSubjectIssuerBlob->cbData; + info->Issuer.pbData = pSubjectIssuerBlob->pbData; + if (pStartTime) + SystemTimeToFileTime(pStartTime, &info->NotBefore); + else + GetSystemTimeAsFileTime(&info->NotBefore); + if (pEndTime) + SystemTimeToFileTime(pStartTime, &info->NotAfter); + else + { + SYSTEMTIME endTime; + + if (FileTimeToSystemTime(&info->NotBefore, &endTime)) + { + endTime.wYear++; + SystemTimeToFileTime(&endTime, &info->NotAfter); + } + } + info->Subject.cbData = pSubjectIssuerBlob->cbData; + info->Subject.pbData = pSubjectIssuerBlob->pbData; + memcpy(&info->SubjectPublicKeyInfo, pubKey, + sizeof(info->SubjectPublicKeyInfo)); + if (pExtensions) + { + info->cExtension = pExtensions->cExtension; + info->rgExtension = pExtensions->rgExtension; + } + else + { + info->cExtension = 0; + info->rgExtension = NULL; + } +} + +typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *); +typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **); +typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **); + +static HCRYPTPROV CRYPT_CreateKeyProv(void) +{ + HCRYPTPROV hProv = 0; + HMODULE rpcrt = LoadLibraryA("rpcrt4"); + + if (rpcrt) + { + UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt, + "UuidCreate"); + UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt, + "UuidToString"); + RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress( + rpcrt, "RpcStringFree"); + + if (uuidCreate && uuidToString && rpcStringFree) + { + UUID uuid; + RPC_STATUS status = uuidCreate(&uuid); + + if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) + { + unsigned char *uuidStr; + + status = uuidToString(&uuid, &uuidStr); + if (status == RPC_S_OK) + { + BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr, + MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET); + + if (ret) + { + HCRYPTKEY key; + + ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key); + if (ret) + CryptDestroyKey(key); + } + rpcStringFree(&uuidStr); + } + } + } + FreeLibrary(rpcrt); + } + return hProv; +} + +PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv, + PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags, + PCRYPT_KEY_PROV_INFO pKeyProvInfo, + PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime, + PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions) +{ + PCCERT_CONTEXT context = NULL; + BOOL ret, releaseContext = FALSE; + PCERT_PUBLIC_KEY_INFO pubKey = NULL; + DWORD pubKeySize = 0; + + TRACE("(0x%08lx, %p, %08lx, %p, %p, %p, %p, %p)\n", hProv, + pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime, + pExtensions, pExtensions); + + if (!hProv) + { + hProv = CRYPT_CreateKeyProv(); + releaseContext = TRUE; + } + + CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL, + &pubKeySize); + pubKey = CryptMemAlloc(pubKeySize); + if (pubKey) + { + ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, + pubKey, &pubKeySize); + if (ret) + { + CERT_INFO info = { 0 }; + CRYPT_DER_BLOB blob = { 0, NULL }; + BOOL ret; + + CRYPT_MakeCertInfo(&info, pSubjectIssuerBlob, pSignatureAlgorithm, + pStartTime, pEndTime, pubKey, pExtensions); + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData, + &blob.cbData); + if (ret) + { + if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN)) + context = CRYPT_CreateSignedCert(&blob, hProv, + &info.SignatureAlgorithm); + else + context = CertCreateCertificateContext(X509_ASN_ENCODING, + blob.pbData, blob.cbData); + if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO)) + CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv); + LocalFree(blob.pbData); + } + } + CryptMemFree(pubKey); + } + if (releaseContext) + CryptReleaseContext(hProv, 0); + return context; +} diff --git a/reactos/dll/win32/crypt32/context.c b/reactos/dll/win32/crypt32/context.c new file mode 100644 index 00000000000..1b2f7d1682b --- /dev/null +++ b/reactos/dll/win32/crypt32/context.c @@ -0,0 +1,308 @@ +/* + * Copyright 2006 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 +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +typedef enum _ContextType { + ContextTypeData, + ContextTypeLink, +} ContextType; + +typedef struct _BASE_CONTEXT +{ + LONG ref; + ContextType type; +} BASE_CONTEXT, *PBASE_CONTEXT; + +typedef struct _DATA_CONTEXT +{ + LONG ref; + ContextType type; /* always ContextTypeData */ + PCONTEXT_PROPERTY_LIST properties; +} DATA_CONTEXT, *PDATA_CONTEXT; + +typedef struct _LINK_CONTEXT +{ + LONG ref; + ContextType type; /* always ContextTypeLink */ + PBASE_CONTEXT linked; +} LINK_CONTEXT, *PLINK_CONTEXT; + +#define CONTEXT_FROM_BASE_CONTEXT(p, s) ((LPBYTE)(p) - (s)) +#define BASE_CONTEXT_FROM_CONTEXT(p, s) (PBASE_CONTEXT)((LPBYTE)(p) + (s)) + +void *Context_CreateDataContext(size_t contextSize) +{ + void *ret = CryptMemAlloc(contextSize + sizeof(DATA_CONTEXT)); + + if (ret) + { + PDATA_CONTEXT context = (PDATA_CONTEXT)((LPBYTE)ret + contextSize); + + context->ref = 1; + context->type = ContextTypeData; + context->properties = ContextPropertyList_Create(); + if (!context->properties) + { + CryptMemFree(ret); + ret = NULL; + } + } + return ret; +} + +void *Context_CreateLinkContext(unsigned int contextSize, void *linked, unsigned int extra, + BOOL addRef) +{ + void *context = CryptMemAlloc(contextSize + sizeof(LINK_CONTEXT) + extra); + + TRACE("(%d, %p, %d)\n", contextSize, linked, extra); + + if (context) + { + PLINK_CONTEXT linkContext = (PLINK_CONTEXT)BASE_CONTEXT_FROM_CONTEXT( + context, contextSize); + PBASE_CONTEXT linkedBase = BASE_CONTEXT_FROM_CONTEXT(linked, + contextSize); + + memcpy(context, linked, contextSize); + linkContext->ref = 1; + linkContext->type = ContextTypeLink; + linkContext->linked = linkedBase; + if (addRef) + InterlockedIncrement(&linkedBase->ref); + TRACE("%p's ref count is %ld\n", context, linkContext->ref); + } + return context; +} + +void Context_AddRef(void *context, size_t contextSize) +{ + PBASE_CONTEXT baseContext = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); + + InterlockedIncrement(&baseContext->ref); +} + +void *Context_GetExtra(const void *context, size_t contextSize) +{ + PBASE_CONTEXT baseContext = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); + + assert(baseContext->type == ContextTypeLink); + return (LPBYTE)baseContext + sizeof(LINK_CONTEXT); +} + +void *Context_GetLinkedContext(void *context, size_t contextSize) +{ + PBASE_CONTEXT baseContext = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); + + assert(baseContext->type == ContextTypeLink); + return CONTEXT_FROM_BASE_CONTEXT(((PLINK_CONTEXT)baseContext)->linked, + contextSize); +} + +PCONTEXT_PROPERTY_LIST Context_GetProperties(void *context, size_t contextSize) +{ + PBASE_CONTEXT ptr = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); + + while (ptr && ptr->type == ContextTypeLink) + ptr = ((PLINK_CONTEXT)ptr)->linked; + return (ptr && ptr->type == ContextTypeData) ? + ((PDATA_CONTEXT)ptr)->properties : NULL; +} + +void Context_Release(void *context, size_t contextSize, + ContextFreeFunc dataContextFree) +{ + PBASE_CONTEXT base = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); + + if (InterlockedDecrement(&base->ref) == 0) + { + TRACE("freeing %p\n", context); + switch (base->type) + { + case ContextTypeData: + ContextPropertyList_Free(((PDATA_CONTEXT)base)->properties); + dataContextFree(context); + break; + case ContextTypeLink: + /* The linked context is of the same type as this, so release + * it as well, using the same offset and data free function. + */ + Context_Release(CONTEXT_FROM_BASE_CONTEXT( + ((PLINK_CONTEXT)base)->linked, contextSize), contextSize, + dataContextFree); + break; + default: + assert(0); + } + CryptMemFree(context); + } + else + TRACE("%p's ref count is %ld\n", context, base->ref); +} + +void Context_CopyProperties(const void *to, const void *from, + size_t contextSize) +{ + PCONTEXT_PROPERTY_LIST toProperties, fromProperties; + + toProperties = Context_GetProperties((void *)to, contextSize); + fromProperties = Context_GetProperties((void *)from, contextSize); + ContextPropertyList_Copy(toProperties, fromProperties); +} + +struct ContextList +{ + PCWINE_CONTEXT_INTERFACE contextInterface; + size_t contextSize; + CRITICAL_SECTION cs; + struct list contexts; +}; + +struct ContextList *ContextList_Create( + PCWINE_CONTEXT_INTERFACE contextInterface, size_t contextSize) +{ + struct ContextList *list = CryptMemAlloc(sizeof(struct ContextList)); + + if (list) + { + list->contextInterface = contextInterface; + list->contextSize = contextSize; + InitializeCriticalSection(&list->cs); + list_init(&list->contexts); + } + return list; +} + +static inline struct list *ContextList_ContextToEntry(struct ContextList *list, + const void *context) +{ + struct list *ret; + + if (context) + ret = (struct list *)Context_GetExtra(context, list->contextSize); + else + ret = NULL; + return ret; +} + +static inline void *ContextList_EntryToContext(struct ContextList *list, + struct list *entry) +{ + return (LPBYTE)entry - sizeof(LINK_CONTEXT) - list->contextSize; +} + +void *ContextList_Add(struct ContextList *list, void *toLink, void *toReplace) +{ + void *context; + + TRACE("(%p, %p, %p)\n", list, toLink, toReplace); + + context = Context_CreateLinkContext(list->contextSize, toLink, + sizeof(struct list), TRUE); + if (context) + { + struct list *entry = ContextList_ContextToEntry(list, context); + + TRACE("adding %p\n", context); + EnterCriticalSection(&list->cs); + if (toReplace) + { + struct list *existing = ContextList_ContextToEntry(list, toReplace); + + entry->prev = existing->prev; + entry->next = existing->next; + entry->prev->next = entry; + entry->next->prev = entry; + existing->prev = existing->next = existing; + list->contextInterface->free(toReplace); + } + else + list_add_tail(&list->contexts, entry); + LeaveCriticalSection(&list->cs); + } + return context; +} + +void *ContextList_Enum(struct ContextList *list, void *pPrev) +{ + struct list *listNext; + void *ret; + + EnterCriticalSection(&list->cs); + if (pPrev) + { + struct list *prevEntry = ContextList_ContextToEntry(list, pPrev); + + listNext = list_next(&list->contexts, prevEntry); + list->contextInterface->free(pPrev); + } + else + listNext = list_next(&list->contexts, &list->contexts); + LeaveCriticalSection(&list->cs); + + if (listNext) + { + ret = ContextList_EntryToContext(list, listNext); + list->contextInterface->duplicate(ret); + } + else + ret = NULL; + return ret; +} + +void ContextList_Delete(struct ContextList *list, void *context) +{ + struct list *entry = ContextList_ContextToEntry(list, context); + + EnterCriticalSection(&list->cs); + list_remove(entry); + LeaveCriticalSection(&list->cs); + list->contextInterface->free(context); +} + +void ContextList_Empty(struct ContextList *list) +{ + struct list *entry, *next; + + EnterCriticalSection(&list->cs); + LIST_FOR_EACH_SAFE(entry, next, &list->contexts) + { + const void *context = ContextList_EntryToContext(list, entry); + + TRACE("removing %p\n", context); + list_remove(entry); + list->contextInterface->free(context); + } + LeaveCriticalSection(&list->cs); +} + +void ContextList_Free(struct ContextList *list) +{ + ContextList_Empty(list); + DeleteCriticalSection(&list->cs); + CryptMemFree(list); +} diff --git a/reactos/dll/win32/crypt32/crl.c b/reactos/dll/win32/crypt32/crl.c new file mode 100644 index 00000000000..bd0136a7555 --- /dev/null +++ b/reactos/dll/win32/crypt32/crl.c @@ -0,0 +1,535 @@ +/* + * Copyright 2006 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 +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +PCCRL_CONTEXT WINAPI CertCreateCRLContext(DWORD dwCertEncodingType, + const BYTE* pbCrlEncoded, DWORD cbCrlEncoded) +{ + PCRL_CONTEXT crl = NULL; + BOOL ret; + PCRL_INFO crlInfo = NULL; + DWORD size = 0; + + TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCrlEncoded, + cbCrlEncoded); + + if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING) + { + SetLastError(E_INVALIDARG); + return NULL; + } + ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_CRL_TO_BE_SIGNED, + pbCrlEncoded, cbCrlEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&crlInfo, &size); + if (ret) + { + BYTE *data = NULL; + + crl = (PCRL_CONTEXT)Context_CreateDataContext(sizeof(CRL_CONTEXT)); + if (!crl) + goto end; + data = CryptMemAlloc(cbCrlEncoded); + if (!data) + { + CryptMemFree(crl); + crl = NULL; + goto end; + } + memcpy(data, pbCrlEncoded, cbCrlEncoded); + crl->dwCertEncodingType = dwCertEncodingType; + crl->pbCrlEncoded = data; + crl->cbCrlEncoded = cbCrlEncoded; + crl->pCrlInfo = crlInfo; + crl->hCertStore = 0; + } + +end: + return (PCCRL_CONTEXT)crl; +} + +BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded, + DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext) +{ + PCCRL_CONTEXT crl = CertCreateCRLContext(dwCertEncodingType, + pbCrlEncoded, cbCrlEncoded); + BOOL ret; + + TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType, + pbCrlEncoded, cbCrlEncoded, dwAddDisposition, ppCrlContext); + + if (crl) + { + ret = CertAddCRLContextToStore(hCertStore, crl, dwAddDisposition, + ppCrlContext); + CertFreeCRLContext(crl); + } + else + ret = FALSE; + return ret; +} + +typedef BOOL (*CrlCompareFunc)(PCCRL_CONTEXT pCrlContext, DWORD dwType, + DWORD dwFlags, const void *pvPara); + +static BOOL compare_crl_any(PCCRL_CONTEXT pCrlContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + return TRUE; +} + +static BOOL compare_crl_issued_by(PCCRL_CONTEXT pCrlContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + + if (pvPara) + { + PCCERT_CONTEXT issuer = (PCCERT_CONTEXT)pvPara; + + ret = CertCompareCertificateName(issuer->dwCertEncodingType, + &issuer->pCertInfo->Issuer, &pCrlContext->pCrlInfo->Issuer); + } + else + ret = TRUE; + return ret; +} + +static BOOL compare_crl_existing(PCCRL_CONTEXT pCrlContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + + if (pvPara) + { + PCCRL_CONTEXT crl = (PCCRL_CONTEXT)pvPara; + + ret = CertCompareCertificateName(pCrlContext->dwCertEncodingType, + &pCrlContext->pCrlInfo->Issuer, &crl->pCrlInfo->Issuer); + } + else + ret = TRUE; + return ret; +} + +PCCRL_CONTEXT WINAPI CertFindCRLInStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType, + const void *pvFindPara, PCCRL_CONTEXT pPrevCrlContext) +{ + PCCRL_CONTEXT ret; + CrlCompareFunc compare; + + TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType, + dwFindFlags, dwFindType, pvFindPara, pPrevCrlContext); + + switch (dwFindType) + { + case CRL_FIND_ANY: + compare = compare_crl_any; + break; + case CRL_FIND_ISSUED_BY: + compare = compare_crl_issued_by; + break; + case CRL_FIND_EXISTING: + compare = compare_crl_existing; + break; + default: + FIXME("find type %08lx unimplemented\n", dwFindType); + compare = NULL; + } + + if (compare) + { + BOOL matches = FALSE; + + ret = pPrevCrlContext; + do { + ret = CertEnumCRLsInStore(hCertStore, ret); + if (ret) + matches = compare(ret, dwFindType, dwFindFlags, pvFindPara); + } while (ret != NULL && !matches); + if (!ret) + SetLastError(CRYPT_E_NOT_FOUND); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + return ret; +} + +PCCRL_CONTEXT WINAPI CertGetCRLFromStore(HCERTSTORE hCertStore, + PCCERT_CONTEXT pIssuerContext, PCCRL_CONTEXT pPrevCrlContext, DWORD *pdwFlags) +{ + static const DWORD supportedFlags = CERT_STORE_SIGNATURE_FLAG | + CERT_STORE_TIME_VALIDITY_FLAG | CERT_STORE_BASE_CRL_FLAG | + CERT_STORE_DELTA_CRL_FLAG; + PCCRL_CONTEXT ret; + + TRACE("(%p, %p, %p, %08lx)\n", hCertStore, pIssuerContext, pPrevCrlContext, + *pdwFlags); + + if (*pdwFlags & ~supportedFlags) + { + SetLastError(E_INVALIDARG); + return NULL; + } + if (pIssuerContext) + ret = CertFindCRLInStore(hCertStore, pIssuerContext->dwCertEncodingType, + 0, CRL_FIND_ISSUED_BY, pIssuerContext, pPrevCrlContext); + else + ret = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_ANY, NULL, + pPrevCrlContext); + if (ret) + { + if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG) + { + if (0 == CertVerifyCRLTimeValidity(NULL, ret->pCrlInfo)) + *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG; + } + if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG) + { + if (CryptVerifyCertificateSignatureEx(0, ret->dwCertEncodingType, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL, (void *)ret, + CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuerContext, 0, + NULL)) + *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG; + } + } + return ret; +} + +PCCRL_CONTEXT WINAPI CertDuplicateCRLContext(PCCRL_CONTEXT pCrlContext) +{ + TRACE("(%p)\n", pCrlContext); + Context_AddRef((void *)pCrlContext, sizeof(CRL_CONTEXT)); + return pCrlContext; +} + +static void CrlDataContext_Free(void *context) +{ + PCRL_CONTEXT crlContext = (PCRL_CONTEXT)context; + + CryptMemFree(crlContext->pbCrlEncoded); + LocalFree(crlContext->pCrlInfo); +} + +BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext) +{ + TRACE("(%p)\n", pCrlContext); + + if (pCrlContext) + Context_Release((void *)pCrlContext, sizeof(CRL_CONTEXT), + CrlDataContext_Free); + return TRUE; +} + +DWORD WINAPI CertEnumCRLContextProperties(PCCRL_CONTEXT pCRLContext, + DWORD dwPropId) +{ + PCONTEXT_PROPERTY_LIST properties = Context_GetProperties( + (void *)pCRLContext, sizeof(CRL_CONTEXT)); + DWORD ret; + + TRACE("(%p, %ld)\n", pCRLContext, dwPropId); + + if (properties) + ret = ContextPropertyList_EnumPropIDs(properties, dwPropId); + else + ret = 0; + return ret; +} + +static BOOL WINAPI CRLContext_SetProperty(void *context, DWORD dwPropId, + DWORD dwFlags, const void *pvData); + +static BOOL CRLContext_GetHashProp(void *context, DWORD dwPropId, + ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, + DWORD *pcbData) +{ + BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, + pcbData); + if (ret) + { + CRYPT_DATA_BLOB blob = { *pcbData, pvData }; + + ret = CRLContext_SetProperty(context, dwPropId, 0, &blob); + } + return ret; +} + +static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId, + void *pvData, DWORD *pcbData) +{ + PCCRL_CONTEXT pCRLContext = (PCCRL_CONTEXT)context; + PCONTEXT_PROPERTY_LIST properties = + Context_GetProperties(context, sizeof(CRL_CONTEXT)); + BOOL ret; + CRYPT_DATA_BLOB blob; + + TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData); + + if (properties) + ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob); + else + ret = FALSE; + if (ret) + { + if (!pvData) + { + *pcbData = blob.cbData; + ret = TRUE; + } + else if (*pcbData < blob.cbData) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = blob.cbData; + } + else + { + memcpy(pvData, blob.pbData, blob.cbData); + *pcbData = blob.cbData; + ret = TRUE; + } + } + else + { + /* Implicit properties */ + switch (dwPropId) + { + case CERT_SHA1_HASH_PROP_ID: + ret = CRLContext_GetHashProp(context, dwPropId, CALG_SHA1, + pCRLContext->pbCrlEncoded, pCRLContext->cbCrlEncoded, pvData, + pcbData); + break; + case CERT_MD5_HASH_PROP_ID: + ret = CRLContext_GetHashProp(context, dwPropId, CALG_MD5, + pCRLContext->pbCrlEncoded, pCRLContext->cbCrlEncoded, pvData, + pcbData); + break; + default: + SetLastError(CRYPT_E_NOT_FOUND); + } + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext, + DWORD dwPropId, void *pvData, DWORD *pcbData) +{ + BOOL ret; + + TRACE("(%p, %ld, %p, %p)\n", pCRLContext, dwPropId, pvData, pcbData); + + switch (dwPropId) + { + case 0: + case CERT_CERT_PROP_ID: + case CERT_CRL_PROP_ID: + case CERT_CTL_PROP_ID: + SetLastError(E_INVALIDARG); + ret = FALSE; + break; + case CERT_ACCESS_STATE_PROP_ID: + if (!pvData) + { + *pcbData = sizeof(DWORD); + ret = TRUE; + } + else if (*pcbData < sizeof(DWORD)) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = sizeof(DWORD); + ret = FALSE; + } + else + { + *(DWORD *)pvData = + CertStore_GetAccessState(pCRLContext->hCertStore); + ret = TRUE; + } + break; + default: + ret = CRLContext_GetProperty((void *)pCRLContext, dwPropId, pvData, + pcbData); + } + return ret; +} + +static BOOL WINAPI CRLContext_SetProperty(void *context, DWORD dwPropId, + DWORD dwFlags, const void *pvData) +{ + PCONTEXT_PROPERTY_LIST properties = + Context_GetProperties(context, sizeof(CERT_CONTEXT)); + BOOL ret; + + TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData); + + if (!properties) + ret = FALSE; + else if (!pvData) + { + ContextPropertyList_RemoveProperty(properties, dwPropId); + ret = TRUE; + } + else + { + switch (dwPropId) + { + case CERT_AUTO_ENROLL_PROP_ID: + case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ + case CERT_DESCRIPTION_PROP_ID: + case CERT_FRIENDLY_NAME_PROP_ID: + case CERT_HASH_PROP_ID: + case CERT_KEY_IDENTIFIER_PROP_ID: + case CERT_MD5_HASH_PROP_ID: + case CERT_NEXT_UPDATE_LOCATION_PROP_ID: + case CERT_PUBKEY_ALG_PARA_PROP_ID: + case CERT_PVK_FILE_PROP_ID: + case CERT_SIGNATURE_HASH_PROP_ID: + case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: + case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_ENROLLMENT_PROP_ID: + case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: + case CERT_RENEWAL_PROP_ID: + { + PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData; + + ret = ContextPropertyList_SetProperty(properties, dwPropId, + blob->pbData, blob->cbData); + break; + } + case CERT_DATE_STAMP_PROP_ID: + ret = ContextPropertyList_SetProperty(properties, dwPropId, + (LPBYTE)pvData, sizeof(FILETIME)); + break; + default: + FIXME("%ld: stub\n", dwPropId); + ret = FALSE; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext, + DWORD dwPropId, DWORD dwFlags, const void *pvData) +{ + BOOL ret; + + TRACE("(%p, %ld, %08lx, %p)\n", pCRLContext, dwPropId, dwFlags, pvData); + + /* Handle special cases for "read-only"/invalid prop IDs. Windows just + * crashes on most of these, I'll be safer. + */ + switch (dwPropId) + { + case 0: + case CERT_ACCESS_STATE_PROP_ID: + case CERT_CERT_PROP_ID: + case CERT_CRL_PROP_ID: + case CERT_CTL_PROP_ID: + SetLastError(E_INVALIDARG); + return FALSE; + } + ret = CRLContext_SetProperty((void *)pCRLContext, dwPropId, dwFlags, + pvData); + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertIsValidCRLForCertificate(PCCERT_CONTEXT pCert, + PCCRL_CONTEXT pCrl, DWORD dwFlags, void *pvReserved) +{ + TRACE("(%p, %p, %08lx, %p)\n", pCert, pCrl, dwFlags, pvReserved); + return TRUE; +} + +static PCRL_ENTRY CRYPT_FindCertificateInCRL(PCERT_INFO cert, PCRL_INFO crl) +{ + DWORD i; + PCRL_ENTRY entry = NULL; + + for (i = 0; !entry && i < crl->cCRLEntry; i++) + if (CertCompareIntegerBlob(&crl->rgCRLEntry[i].SerialNumber, + &cert->SerialNumber)) + entry = &crl->rgCRLEntry[i]; + return entry; +} + +BOOL WINAPI CertFindCertificateInCRL(PCCERT_CONTEXT pCert, + PCCRL_CONTEXT pCrlContext, DWORD dwFlags, void *pvReserved, + PCRL_ENTRY *ppCrlEntry) +{ + TRACE("(%p, %p, %08lx, %p, %p)\n", pCert, pCrlContext, dwFlags, pvReserved, + ppCrlEntry); + + *ppCrlEntry = CRYPT_FindCertificateInCRL(pCert->pCertInfo, + pCrlContext->pCrlInfo); + return TRUE; +} + +BOOL WINAPI CertVerifyCRLRevocation(DWORD dwCertEncodingType, + PCERT_INFO pCertId, DWORD cCrlInfo, PCRL_INFO rgpCrlInfo[]) +{ + DWORD i; + PCRL_ENTRY entry = NULL; + + TRACE("(%08lx, %p, %ld, %p)\n", dwCertEncodingType, pCertId, cCrlInfo, + rgpCrlInfo); + + for (i = 0; !entry && i < cCrlInfo; i++) + entry = CRYPT_FindCertificateInCRL(pCertId, rgpCrlInfo[i]); + return entry == NULL; +} + +LONG WINAPI CertVerifyCRLTimeValidity(LPFILETIME pTimeToVerify, + PCRL_INFO pCrlInfo) +{ + FILETIME fileTime; + LONG ret; + + if (!pTimeToVerify) + { + SYSTEMTIME sysTime; + + GetSystemTime(&sysTime); + SystemTimeToFileTime(&sysTime, &fileTime); + pTimeToVerify = &fileTime; + } + if ((ret = CompareFileTime(pTimeToVerify, &pCrlInfo->ThisUpdate)) >= 0) + { + ret = CompareFileTime(pTimeToVerify, &pCrlInfo->NextUpdate); + if (ret < 0) + ret = 0; + } + return ret; +} diff --git a/reactos/dll/win32/crypt32/crypt32.rbuild b/reactos/dll/win32/crypt32/crypt32.rbuild index 26b946fd592..c7abccf7416 100644 --- a/reactos/dll/win32/crypt32/crypt32.rbuild +++ b/reactos/dll/win32/crypt32/crypt32.rbuild @@ -1,22 +1,31 @@ - + . include/reactos/wine + + + 0x600 0x501 - ntdll - kernel32 + 0x501 wine + user32 advapi32 - main.c - encode.c + kernel32 + ntdll + base64.c cert.c + crl.c + context.c + decode.c + encode.c oid.c proplist.c protectdata.c serialize.c store.c str.c + main.c crypt32.rc crypt32.spec diff --git a/reactos/dll/win32/crypt32/crypt32.rc b/reactos/dll/win32/crypt32/crypt32.rc index 412579b9cb7..1fe23cdf33a 100644 --- a/reactos/dll/win32/crypt32/crypt32.rc +++ b/reactos/dll/win32/crypt32/crypt32.rc @@ -15,7 +15,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define REACTOS_VERSION_DLL diff --git a/reactos/dll/win32/crypt32/crypt32.spec b/reactos/dll/win32/crypt32/crypt32.spec index 1273062d3cc..120061b782e 100644 --- a/reactos/dll/win32/crypt32/crypt32.spec +++ b/reactos/dll/win32/crypt32/crypt32.spec @@ -11,31 +11,34 @@ @ stdcall CertAddStoreToCollection(ptr ptr long long) @ stdcall CertAlgIdToOID(long) @ stdcall CertCloseStore(ptr long) -@ stub CertCompareCertificate -@ stub CertCompareCertificateName -@ stub CertCompareIntegerBlob -@ stub CertComparePublicKeyInfo +@ stdcall CertCompareCertificate(long ptr ptr) +@ stdcall CertCompareCertificateName(long ptr ptr) +@ stdcall CertCompareIntegerBlob(ptr ptr) +@ stdcall CertComparePublicKeyInfo(long ptr ptr) @ stdcall CertControlStore(long long long ptr) @ stdcall CertCreateCRLContext(long ptr long) @ stdcall CertCreateCTLContext(long ptr long) @ stub CertCreateCertificateChainEngine @ stdcall CertCreateCertificateContext(long ptr long) +@ stdcall CertCreateSelfSignCertificate(long ptr long ptr ptr ptr ptr ptr) @ stdcall CertDeleteCRLFromStore(ptr) @ stdcall CertDeleteCTLFromStore(ptr) @ stdcall CertDeleteCertificateFromStore(ptr) -@ stub CertDuplicateCRLContext -@ stub CertDuplicateCTLContext +@ stdcall CertDuplicateCRLContext(ptr) +@ stdcall CertDuplicateCTLContext(ptr) @ stdcall CertDuplicateCertificateContext(ptr) @ stdcall CertDuplicateStore(ptr) -@ stub CertEnumCRLContextProperties +@ stdcall CertEnumCRLContextProperties(ptr long) @ stdcall CertEnumCRLsInStore(ptr ptr) -@ stub CertEnumCTLContextProperties +@ stdcall CertEnumCTLContextProperties(ptr long) @ stdcall CertEnumCTLsInStore(ptr ptr) @ stdcall CertEnumCertificateContextProperties(ptr long) @ stdcall CertEnumCertificatesInStore(long ptr) @ stdcall CertFindAttribute(str long ptr) +@ stdcall CertFindCRLInStore(long long long long ptr ptr) @ stub CertFindCTLInStore @ stdcall CertFindCertificateInStore(long long long long ptr ptr) +@ stdcall CertFindCertificateInCRL(ptr ptr long ptr ptr) @ stdcall CertFindExtension(str long ptr) @ stdcall CertFindRDNAttr(str ptr) @ stub CertFindSubjectInCTL @@ -45,19 +48,20 @@ @ stub CertFreeCertificateChainEngine @ stdcall CertFreeCertificateContext(ptr) @ stdcall CertGetCRLContextProperty(ptr long ptr ptr) -@ stub CertGetCRLFromStore +@ stdcall CertGetCRLFromStore(ptr ptr ptr ptr) @ stdcall CertGetCTLContextProperty(ptr long ptr ptr) @ stub CertGetCertificateChain @ stdcall CertGetCertificateContextProperty(ptr long ptr ptr) @ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr) @ stub CertGetIntendedKeyUsage -@ stub CertGetIssuerCertificateFromStore +@ stdcall CertGetIssuerCertificateFromStore(long ptr ptr ptr) @ stdcall CertGetNameStringA(ptr long long ptr ptr long) @ stdcall CertGetNameStringW(ptr long long ptr ptr long) @ stub CertGetPublicKeyLength -@ stub CertGetSubjectCertificateFromStore +@ stdcall CertGetSubjectCertificateFromStore(ptr long ptr) @ stdcall CertGetValidUsages(long ptr ptr ptr ptr) @ stub CertIsRDNAttrsInCertificateName +@ stdcall CertIsValidCRLForCertificate(ptr ptr long ptr) @ stdcall CertNameToStrA(long ptr long ptr long) @ stdcall CertNameToStrW(long ptr long ptr long) @ stdcall CertOIDToAlgId(str) @@ -78,15 +82,18 @@ @ stdcall CertSetEnhancedKeyUsage(ptr ptr) @ stub CertStrToNameA @ stub CertStrToNameW -@ stub CertVerifyCertificateChainPolicy -@ stub CertVerifyCRLRevocation -@ stub CertVerifyCRLTimeValidity +@ stdcall CertVerifyCRLRevocation(long ptr long ptr) +@ stdcall CertVerifyCRLTimeValidity(ptr ptr) @ stub CertVerifyCTLUsage @ stub CertVerifyRevocation -@ stub CertVerifySubjectCertificateContext +@ stdcall CertVerifySubjectCertificateContext(ptr ptr ptr) @ stdcall CertVerifyTimeValidity(ptr ptr) @ stub CertVerifyValidityNesting @ stub CreateFileU +@ stdcall CryptBinaryToStringA(ptr long long ptr ptr) +@ stub CryptBinaryToStringW # (ptr long long ptr ptr) +@ stdcall CryptStringToBinaryA(str long long ptr ptr ptr ptr) +@ stub CryptStringToBinaryW # (wstr long long ptr ptr ptr ptr) @ stub CryptAcquireContextU @ stub CryptCloseAsyncHandle @ stub CryptCreateAsyncHandle diff --git a/reactos/dll/win32/crypt32/crypt32_De.rc b/reactos/dll/win32/crypt32/crypt32_De.rc index a8e98fcf48f..272210ab82b 100644 --- a/reactos/dll/win32/crypt32/crypt32_De.rc +++ b/reactos/dll/win32/crypt32/crypt32_De.rc @@ -15,7 +15,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT @@ -117,7 +117,7 @@ STRINGTABLE DISCARDABLE IDS_KEY_RECOVERY_AGENT "Agent zur Schlüsselwiederherstellung" IDS_CERTIFICATE_TEMPLATE "Zertifikatsvorlageninformation" IDS_ENTERPRISE_ROOT_OID "Unternehmensstamm-OID" - IDS_RDN_DUMMY_SIGNER "Atrappenunterzeichner" + IDS_RDN_DUMMY_SIGNER "Attrapenunterzeichner" IDS_ARCHIVED_KEY_ATTR "Verschlüsselter, privater Schlüssel" IDS_CRL_SELF_CDP "Veröffentlichte CRL Standorte" IDS_REQUIRE_CERT_CHAIN_POLICY "Erzwinge Zertifikatskettenrichtlinie" diff --git a/reactos/dll/win32/crypt32/crypt32_En.rc b/reactos/dll/win32/crypt32/crypt32_En.rc index 62f3f19d9a7..08bf3854403 100644 --- a/reactos/dll/win32/crypt32/crypt32_En.rc +++ b/reactos/dll/win32/crypt32/crypt32_En.rc @@ -15,7 +15,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT diff --git a/reactos/dll/win32/crypt32/crypt32_Ko.rc b/reactos/dll/win32/crypt32/crypt32_Ko.rc index e0df4a5c093..418e04514b7 100644 --- a/reactos/dll/win32/crypt32/crypt32_Ko.rc +++ b/reactos/dll/win32/crypt32/crypt32_Ko.rc @@ -16,7 +16,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT diff --git a/reactos/dll/win32/crypt32/crypt32_No.rc b/reactos/dll/win32/crypt32/crypt32_No.rc index 9687163bd29..6d5bb8261fe 100644 --- a/reactos/dll/win32/crypt32/crypt32_No.rc +++ b/reactos/dll/win32/crypt32/crypt32_No.rc @@ -15,7 +15,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL diff --git a/reactos/dll/win32/crypt32/crypt32_private.h b/reactos/dll/win32/crypt32/crypt32_private.h index 25c41e4611b..3ef44b4fb90 100644 --- a/reactos/dll/win32/crypt32/crypt32_private.h +++ b/reactos/dll/win32/crypt32/crypt32_private.h @@ -13,12 +13,24 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CRYPT32_PRIVATE_H__ #define __CRYPT32_PRIVATE_H__ +/* a few asn.1 tags we need */ +#define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01) +#define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03) +#define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a) +#define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11) +#define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12) +#define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13) +#define ASN_T61STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x14) +#define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16) +#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17) +#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18) + /* The following aren't defined in wincrypt.h, as they're "reserved" */ #define CERT_CERT_PROP_ID 32 #define CERT_CRL_PROP_ID 33 @@ -32,6 +44,50 @@ HCRYPTPROV CRYPT_GetDefaultProvider(void); void crypt_oid_init(HINSTANCE hinst); void crypt_oid_free(void); +/* Some typedefs that make it easier to abstract which type of context we're + * working with. + */ +typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType, + const BYTE *pbCertEncoded, DWORD cbCertEncoded); +typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore, + const void *context, DWORD dwAddDisposition, const void **ppStoreContext); +typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwAddDisposition, const void **ppContext); +typedef const void *(WINAPI *DuplicateContextFunc)(const void *context); +typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore, + const void *pPrevContext); +typedef DWORD (WINAPI *EnumPropertiesFunc)(const void *context, DWORD dwPropId); +typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context, + DWORD dwPropID, void *pvData, DWORD *pcbData); +typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context, + DWORD dwPropID, DWORD dwFlags, const void *pvData); +typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags, + BYTE *pbElement, DWORD *pcbElement); +typedef BOOL (WINAPI *FreeContextFunc)(const void *context); +typedef BOOL (WINAPI *DeleteContextFunc)(const void *context); + +/* An abstract context (certificate, CRL, or CTL) interface */ +typedef struct _WINE_CONTEXT_INTERFACE +{ + CreateContextFunc create; + AddContextToStoreFunc addContextToStore; + AddEncodedContextToStoreFunc addEncodedToStore; + DuplicateContextFunc duplicate; + EnumContextsInStoreFunc enumContextsInStore; + EnumPropertiesFunc enumProps; + GetContextPropertyFunc getProp; + SetContextPropertyFunc setProp; + SerializeElementFunc serialize; + FreeContextFunc free; + DeleteContextFunc deleteFromStore; +} WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE; +typedef const WINE_CONTEXT_INTERFACE *PCWINE_CONTEXT_INTERFACE; + +extern PCWINE_CONTEXT_INTERFACE pCertInterface; +extern PCWINE_CONTEXT_INTERFACE pCRLInterface; +extern PCWINE_CONTEXT_INTERFACE pCTLInterface; + /* Helper function for store reading functions and * CertAddSerializedElementToStore. Returns a context of the appropriate type * if it can, or NULL otherwise. Doesn't validate any of the properties in @@ -41,11 +97,61 @@ void crypt_oid_free(void); const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType); +DWORD CertStore_GetAccessState(HCERTSTORE hCertStore); + +/** + * Context functions + */ + +/* Allocates a new data context, a context which owns properties directly. + * contextSize is the size of the public data type associated with context, + * which should be one of CERT_CONTEXT, CRL_CONTEXT, or CTL_CONTEXT. + * Free with Context_Release. + */ +void *Context_CreateDataContext(size_t contextSize); + +/* Creates a new link context with extra bytes. The context refers to linked + * rather than owning its own properties. If addRef is TRUE (which ordinarily + * it should be) linked is addref'd. + * Free with Context_Release. + */ +void *Context_CreateLinkContext(unsigned int contextSize, void *linked, unsigned int extra, + BOOL addRef); + +/* Returns a pointer to the extra bytes allocated with context, which must be + * a link context. + */ +void *Context_GetExtra(const void *context, size_t contextSize); + +/* Gets the context linked to by context, which must be a link context. */ +void *Context_GetLinkedContext(void *context, size_t contextSize); + +/* Copies properties from fromContext to toContext. */ +void Context_CopyProperties(const void *to, const void *from, + size_t contextSize); + +struct _CONTEXT_PROPERTY_LIST; +typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST; + +/* Returns context's properties, or the linked context's properties if context + * is a link context. + */ +PCONTEXT_PROPERTY_LIST Context_GetProperties(void *context, size_t contextSize); + +void Context_AddRef(void *context, size_t contextSize); + +typedef void (*ContextFreeFunc)(void *context); + +/* Decrements context's ref count. If context is a link context, releases its + * linked context as well. + * If a data context has its ref count reach 0, calls dataContextFree on it. + */ +void Context_Release(void *context, size_t contextSize, + ContextFreeFunc dataContextFree); + /** * Context property list functions */ -struct _CONTEXT_PROPERTY_LIST; -typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST; PCONTEXT_PROPERTY_LIST ContextPropertyList_Create(void); @@ -68,4 +174,22 @@ void ContextPropertyList_Copy(PCONTEXT_PROPERTY_LIST to, void ContextPropertyList_Free(PCONTEXT_PROPERTY_LIST list); +/** + * Context list functions. A context list is a simple list of link contexts. + */ +struct ContextList; + +struct ContextList *ContextList_Create( + PCWINE_CONTEXT_INTERFACE contextInterface, size_t contextSize); + +void *ContextList_Add(struct ContextList *list, void *toLink, void *toReplace); + +void *ContextList_Enum(struct ContextList *list, void *pPrev); + +void ContextList_Delete(struct ContextList *list, void *context); + +void ContextList_Empty(struct ContextList *list); + +void ContextList_Free(struct ContextList *list); + #endif diff --git a/reactos/dll/win32/crypt32/crypt32_ros.diff b/reactos/dll/win32/crypt32/crypt32_ros.diff index 809eb6429da..319e798f672 100644 --- a/reactos/dll/win32/crypt32/crypt32_ros.diff +++ b/reactos/dll/win32/crypt32/crypt32_ros.diff @@ -1,7 +1,7 @@ Index: crypt32.rc =================================================================== --- crypt32.rc (revision 22838) -+++ crypt32.rc (working copy) ++++ crypt32.rc (working copy) @@ -17,12 +17,18 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -22,16 +22,3 @@ Index: crypt32.rc #include "crypt32_De.rc" #include "crypt32_En.rc" -Index: main.c -=================================================================== ---- main.c (revision 22838) -+++ main.c (working copy) -@@ -294,7 +294,7 @@ - return FALSE; - } - --BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara, -+BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, - DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, - BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert) - { diff --git a/reactos/dll/win32/crypt32/cryptres.h b/reactos/dll/win32/crypt32/cryptres.h index 4bcd233fdf2..1f0a95ea43d 100644 --- a/reactos/dll/win32/crypt32/cryptres.h +++ b/reactos/dll/win32/crypt32/cryptres.h @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_CRYPTRES_H__ #define __WINE_CRYPTRES_H__ diff --git a/reactos/dll/win32/crypt32/decode.c b/reactos/dll/win32/crypt32/decode.c new file mode 100644 index 00000000000..c3b2a7a9566 --- /dev/null +++ b/reactos/dll/win32/crypt32/decode.c @@ -0,0 +1,3281 @@ +/* + * Copyright 2005 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 + * + * This file implements ASN.1 DER decoding of a limited set of types. + * It isn't a full ASN.1 implementation. Microsoft implements BER + * encoding of many of the basic types in msasn1.dll, but that interface is + * undocumented, so I implement them here. + * + * References: + * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski + * (available online, look for a PDF copy as the HTML versions tend to have + * translation errors.) + * + * RFC3280, http://www.faqs.org/rfcs/rfc3280.html + * + * MSDN, especially: + * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp + */ + +#include +#include +#include +#include + +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "excpt.h" +#include "wincrypt.h" +#include "winreg.h" +#include "snmp.h" +#include "wine/debug.h" +#include "wine/exception.h" +#include "crypt32_private.h" + +/* This is a bit arbitrary, but to set some limit: */ +#define MAX_ENCODED_LEN 0x02000000 + +#define ASN_FLAGS_MASK 0xe0 +#define ASN_TYPE_MASK 0x1f + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +struct GenericArray +{ + DWORD cItems; + BYTE *rgItems; +}; + +typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, + DWORD, DWORD, void *, DWORD *); +typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *, + DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *); + +/* Prototypes for built-in decoders. They follow the Ex style prototypes. + * The dwCertEncodingType and lpszStructType are ignored by the built-in + * functions, but the parameters are retained to simplify CryptDecodeObjectEx, + * since it must call functions in external DLLs that follow these signatures. + */ +static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of + * time, doesn't do memory allocation, and doesn't do exception handling. + * (This isn't intended to be the externally-called one.) + */ +static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Assumes algo->Parameters.pbData is set ahead of time. Internal func. */ +static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Internal function */ +static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */ +static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData + * member has been initialized, doesn't do exception handling, and doesn't do + * memory allocation. + */ +static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData + * member has been initialized, doesn't do exception handling, and doesn't do + * memory allocation. + */ +static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +/* Like CRYPT_AsnDecodeInteger, but unsigned. */ +static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( + DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + void *pvStructInfo, DWORD *pcbStructInfo); + +BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, + const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, + DWORD *pcbStructInfo) +{ + static HCRYPTOIDFUNCSET set = NULL; + BOOL ret = FALSE; + CryptDecodeObjectFunc pCryptDecodeObject; + HCRYPTOIDFUNCADDR hFunc; + + TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType, + debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pcbStructInfo); + + if (!pvStructInfo && !pcbStructInfo) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* Try registered DLL first.. */ + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, + (void **)&pCryptDecodeObject, &hFunc); + if (pCryptDecodeObject) + { + ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo); + CryptFreeOIDFunctionAddress(hFunc, 0); + } + else + { + /* If not, use CryptDecodeObjectEx */ + ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded, + cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo); + } + return ret; +} + +/* Gets the number of length bytes from the given (leading) length byte */ +#define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f)) + +/* Helper function to get the encoded length of the data starting at pbEncoded, + * where pbEncoded[0] is the tag. If the data are too short to contain a + * length or if the length is too large for cbEncoded, sets an appropriate + * error code and returns FALSE. + */ +static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD *len) +{ + BOOL ret; + + if (cbEncoded <= 1) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (pbEncoded[1] <= 0x7f) + { + if (pbEncoded[1] + 1 > cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + else + { + *len = pbEncoded[1]; + ret = TRUE; + } + } + else + { + BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]); + + if (lenLen > sizeof(DWORD) + 1) + { + SetLastError(CRYPT_E_ASN1_LARGE); + ret = FALSE; + } + else if (lenLen + 2 > cbEncoded) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + DWORD out = 0; + + pbEncoded += 2; + while (--lenLen) + { + out <<= 8; + out |= *pbEncoded++; + } + if (out + lenLen + 1 > cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + else + { + *len = out; + ret = TRUE; + } + } + } + return ret; +} + +/* Helper function to check *pcbStructInfo, set it to the required size, and + * optionally to allocate memory. Assumes pvStructInfo is not NULL. + * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a + * pointer to the newly allocated memory. + */ +static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD bytesNeeded) +{ + BOOL ret = TRUE; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + { + if (pDecodePara && pDecodePara->pfnAlloc) + *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded); + else + *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded); + if (!*(BYTE **)pvStructInfo) + ret = FALSE; + else + *pcbStructInfo = bytesNeeded; + } + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + return ret; +} + +/* tag: + * The expected tag of the item. If tag is 0, decodeFunc is called + * regardless of the tag value seen. + * offset: + * A sequence is decoded into a struct. The offset member is the + * offset of this item within that struct. + * decodeFunc: + * The decoder function to use. If this is NULL, then the member isn't + * decoded, but minSize space is reserved for it. + * minSize: + * The minimum amount of space occupied after decoding. You must set this. + * optional: + * If true, and the tag doesn't match the expected tag for this item, + * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is + * filled with 0 for this member. + * hasPointer, pointerOffset, minSize: + * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to + * the offset within the (outer) struct of the data pointer (or to the + * first data pointer, if more than one exist). + * size: + * Used by CRYPT_AsnDecodeSequence, not for your use. + */ +struct AsnDecodeSequenceItem +{ + BYTE tag; + DWORD offset; + CryptDecodeObjectExFunc decodeFunc; + DWORD minSize; + BOOL optional; + BOOL hasPointer; + DWORD pointerOffset; + DWORD size; +}; + +static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, + struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData) +{ + BOOL ret; + DWORD i; + const BYTE *ptr; + + ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]); + for (i = 0, ret = TRUE; ret && i < cItem; i++) + { + if (cbEncoded - (ptr - pbEncoded) != 0) + { + DWORD nextItemLen; + + if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), + &nextItemLen))) + { + BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]); + + if (ptr[0] == items[i].tag || !items[i].tag) + { + if (nextData && pvStructInfo && items[i].hasPointer) + { + TRACE("Setting next pointer to %p\n", + nextData); + *(BYTE **)((BYTE *)pvStructInfo + + items[i].pointerOffset) = nextData; + } + if (items[i].decodeFunc) + { + if (pvStructInfo) + TRACE("decoding item %ld\n", i); + else + TRACE("sizing item %ld\n", i); + ret = items[i].decodeFunc(dwCertEncodingType, + NULL, ptr, 1 + nextItemLenBytes + nextItemLen, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, + pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset + : NULL, &items[i].size); + if (ret) + { + if (nextData && items[i].hasPointer && + items[i].size > items[i].minSize) + { + nextData += items[i].size - items[i].minSize; + /* align nextData to DWORD boundaries */ + if (items[i].size % sizeof(DWORD)) + nextData += sizeof(DWORD) - items[i].size % + sizeof(DWORD); + } + /* Account for alignment padding */ + if (items[i].size % sizeof(DWORD)) + items[i].size += sizeof(DWORD) - + items[i].size % sizeof(DWORD); + ptr += 1 + nextItemLenBytes + nextItemLen; + } + else if (items[i].optional && + GetLastError() == CRYPT_E_ASN1_BADTAG) + { + TRACE("skipping optional item %ld\n", i); + items[i].size = items[i].minSize; + SetLastError(NOERROR); + ret = TRUE; + } + else + TRACE("item %ld failed: %08lx\n", i, + GetLastError()); + } + else + items[i].size = items[i].minSize; + } + else if (items[i].optional) + { + TRACE("skipping optional item %ld\n", i); + items[i].size = items[i].minSize; + } + else + { + TRACE("tag %02x doesn't match expected %02x\n", + ptr[0], items[i].tag); + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + } + else if (items[i].optional) + { + TRACE("missing optional item %ld, skipping\n", i); + items[i].size = items[i].minSize; + } + else + { + TRACE("not enough bytes for item %ld, failing\n", i); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + } + if (cbEncoded - (ptr - pbEncoded) != 0) + { + TRACE("%ld remaining bytes, failing\n", cbEncoded - + (ptr - pbEncoded)); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + return ret; +} + +/* This decodes an arbitrary sequence into a contiguous block of memory + * (basically, a struct.) Each element being decoded is described by a struct + * AsnDecodeSequenceItem, see above. + * startingPointer is an optional pointer to the first place where dynamic + * data will be stored. If you know the starting offset, you may pass it + * here. Otherwise, pass NULL, and one will be inferred from the items. + * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set. + * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT. + */ +static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, + struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer) +{ + BOOL ret; + + TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded, + cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, + startingPointer); + + if (pbEncoded[0] == ASN_SEQUENCE) + { + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + DWORD i; + + ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded, + cbEncoded, dwFlags, NULL, NULL); + if (ret) + { + DWORD bytesNeeded = 0, structSize = 0; + + for (i = 0; i < cItem; i++) + { + bytesNeeded += items[i].size; + structSize += items[i].minSize; + } + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded))) + { + BYTE *nextData; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + if (startingPointer) + nextData = (BYTE *)startingPointer; + else + nextData = (BYTE *)pvStructInfo + structSize; + memset(pvStructInfo, 0, structSize); + ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, + pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData); + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +/* tag: + * The expected tag of the entire encoded array (usually a variant + * of ASN_SETOF or ASN_SEQUENCEOF.) + * decodeFunc: + * used to decode each item in the array + * itemSize: + * is the minimum size of each decoded item + * hasPointer: + * indicates whether each item has a dynamic pointer + * pointerOffset: + * indicates the offset within itemSize at which the pointer exists + */ +struct AsnArrayDescriptor +{ + BYTE tag; + CryptDecodeObjectExFunc decodeFunc; + DWORD itemSize; + BOOL hasPointer; + DWORD pointerOffset; +}; + +struct AsnArrayItemSize +{ + DWORD encodedLen; + DWORD size; +}; + +/* Decodes an array of like types into a struct GenericArray. + * The layout and decoding of the array are described by a struct + * AsnArrayDescriptor. + */ +static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, + const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, + void *startingPointer) +{ + BOOL ret = TRUE; + + TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc, pbEncoded, + cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, + startingPointer); + + if (pbEncoded[0] == arrayDesc->tag) + { + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + DWORD bytesNeeded, cItems = 0; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + /* There can be arbitrarily many items, but there is often only one. + */ + struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize; + + bytesNeeded = sizeof(struct GenericArray); + if (dataLen) + { + const BYTE *ptr; + + for (ptr = pbEncoded + 1 + lenBytes; ret && + ptr - pbEncoded - 1 - lenBytes < dataLen; ) + { + DWORD itemLenBytes, itemDataLen, size; + + itemLenBytes = GET_LEN_BYTES(ptr[1]); + /* Each item decoded may not tolerate extraneous bytes, so + * get the length of the next element and pass it directly. + */ + ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), + &itemDataLen); + if (ret) + ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr, + 1 + itemLenBytes + itemDataLen, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, + &size); + if (ret) + { + DWORD nextLen; + + cItems++; + if (itemSizes != &itemSize) + itemSizes = CryptMemRealloc(itemSizes, + cItems * sizeof(struct AsnArrayItemSize)); + else + { + itemSizes = + CryptMemAlloc( + cItems * sizeof(struct AsnArrayItemSize)); + memcpy(itemSizes, &itemSize, sizeof(itemSize)); + } + if (itemSizes) + { + itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes + + itemDataLen; + itemSizes[cItems - 1].size = size; + bytesNeeded += size; + ret = CRYPT_GetLen(ptr, + cbEncoded - (ptr - pbEncoded), &nextLen); + if (ret) + ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]); + } + else + ret = FALSE; + } + } + } + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded))) + { + DWORD i; + BYTE *nextData; + const BYTE *ptr; + struct GenericArray *array; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + array = (struct GenericArray *)pvStructInfo; + array->cItems = cItems; + if (startingPointer) + array->rgItems = startingPointer; + else + array->rgItems = (BYTE *)array + + sizeof(struct GenericArray); + nextData = (BYTE *)array->rgItems + + array->cItems * arrayDesc->itemSize; + for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && + i < cItems && ptr - pbEncoded - 1 - lenBytes < + dataLen; i++) + { + if (arrayDesc->hasPointer) + *(BYTE **)(array->rgItems + i * arrayDesc->itemSize + + arrayDesc->pointerOffset) = nextData; + ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr, + itemSizes[i].encodedLen, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, + array->rgItems + i * arrayDesc->itemSize, + &itemSizes[i].size); + if (ret) + { + DWORD nextLen; + + nextData += itemSizes[i].size - arrayDesc->itemSize; + ret = CRYPT_GetLen(ptr, + cbEncoded - (ptr - pbEncoded), &nextLen); + if (ret) + ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]); + } + } + } + } + if (itemSizes != &itemSize) + CryptMemFree(itemSizes); + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + return ret; +} + +/* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by + * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set + * to CRYPT_E_ASN1_CORRUPT. + * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData + * set! + */ +static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB); + + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += 1 + lenBytes + dataLen; + + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CRYPT_DER_BLOB *blob; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + blob = (CRYPT_DER_BLOB *)pvStructInfo; + blob->cbData = 1 + lenBytes + dataLen; + if (blob->cbData) + { + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + blob->pbData = (BYTE *)pbEncoded; + else + { + assert(blob->pbData); + memcpy(blob->pbData, pbEncoded, blob->cbData); + } + } + else + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + } + } + return ret; +} + +/* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */ +static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in- + * place. + */ + ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara, + pvStructInfo, pcbStructInfo); + if (ret && pvStructInfo) + { + CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo; + + if (blob->cbData) + { + DWORD i; + BYTE temp; + + for (i = 0; i < blob->cbData / 2; i++) + { + temp = blob->pbData[i]; + blob->pbData[i] = blob->pbData[blob->cbData - i - 1]; + blob->pbData[blob->cbData - i - 1] = temp; + } + } + } + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCertSignedContent(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned), + CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, + offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 }, + { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO, + SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId, + sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, + offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 }, + { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature), + CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, + offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 }, + }; + + if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG) + items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal; + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +/* Internal function */ +static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, + pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + struct AsnDecodeSequenceItem items[] = { + { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore), + CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, + { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter), + CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + return ret; +} + +/* Internal function */ +static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, + X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo); + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion), + CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 }, + { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber), + CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, + TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 }, + { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 }, + { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob, + sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, + Issuer.pbData) }, + { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore), + CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, + FALSE, 0 }, + { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob, + sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, + Subject.pbData) }, + { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo), + CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO), + FALSE, TRUE, offsetof(CERT_INFO, + SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 }, + { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, + offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 }, + { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, + offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension), + CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, + offsetof(CERT_INFO, rgExtension), 0 }, + }; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + PCERT_SIGNED_CONTENT_INFO signedCert = NULL; + DWORD size = 0; + + /* First try to decode it as a signed cert. */ + ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, X509_CERT, + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&signedCert, &size); + if (ret) + { + size = 0; + ret = CRYPT_AsnDecodeCertInfo(dwCertEncodingType, + X509_CERT_TO_BE_SIGNED, signedCert->ToBeSigned.pbData, + signedCert->ToBeSigned.cbData, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo); + LocalFree(signedCert); + } + /* Failing that, try it as an unsigned cert */ + if (!ret) + { + size = 0; + ret = CRYPT_AsnDecodeCertInfo(dwCertEncodingType, + X509_CERT_TO_BE_SIGNED, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber), + CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, + offsetof(CRL_ENTRY, SerialNumber.pbData), 0 }, + { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime, + sizeof(FILETIME), FALSE, FALSE, 0 }, + { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension), + CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE, + offsetof(CRL_ENTRY, rgExtension), 0 }, + }; + PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry, + *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL); + return ret; +} + +/* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has + * been set prior to calling. + */ +static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE, + offsetof(CRL_ENTRY, SerialNumber.pbData) }; + struct GenericArray *entries = (struct GenericArray *)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, + entries ? entries->rgItems : NULL); + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(CRL_INFO, dwVersion), + CRYPT_AsnDecodeInt, sizeof(DWORD), TRUE, FALSE, 0, 0 }, + { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 }, + { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob, + sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO, + Issuer.pbData) }, + { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime, + sizeof(FILETIME), FALSE, FALSE, 0 }, + { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime, + sizeof(FILETIME), TRUE, FALSE, 0 }, + { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry), + CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CRL_INFO, rgCRLEntry), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_INFO, cExtension), + CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, + offsetof(CRL_INFO, rgExtension), 0 }, + }; + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + PCERT_SIGNED_CONTENT_INFO signedCrl = NULL; + DWORD size = 0; + + /* First try to decode it as a signed crl. */ + ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, X509_CERT, + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&signedCrl, &size); + if (ret) + { + size = 0; + ret = CRYPT_AsnDecodeCRLInfo(dwCertEncodingType, + X509_CERT_CRL_TO_BE_SIGNED, signedCrl->ToBeSigned.pbData, + signedCrl->ToBeSigned.cbData, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); + LocalFree(signedCrl); + } + /* Failing that, try it as an unsigned crl */ + if (!ret) + { + size = 0; + ret = CRYPT_AsnDecodeCRLInfo(dwCertEncodingType, + X509_CERT_CRL_TO_BE_SIGNED, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if (pbEncoded[0] == ASN_OBJECTIDENTIFIER) + { + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + DWORD bytesNeeded = sizeof(LPSTR); + + if (dataLen) + { + /* The largest possible string for the first two components + * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough. + */ + char firstTwo[6]; + const BYTE *ptr; + + snprintf(firstTwo, sizeof(firstTwo), "%d.%d", + pbEncoded[1 + lenBytes] / 40, + pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) + * 40); + bytesNeeded += strlen(firstTwo) + 1; + for (ptr = pbEncoded + 2 + lenBytes; ret && + ptr - pbEncoded - 1 - lenBytes < dataLen; ) + { + /* large enough for ".4000000" */ + char str[9]; + int val = 0; + + while (ptr - pbEncoded - 1 - lenBytes < dataLen && + (*ptr & 0x80)) + { + val <<= 7; + val |= *ptr & 0x7f; + ptr++; + } + if (ptr - pbEncoded - 1 - lenBytes >= dataLen || + (*ptr & 0x80)) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + val <<= 7; + val |= *ptr++; + snprintf(str, sizeof(str), ".%d", val); + bytesNeeded += strlen(str); + } + } + } + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + if (dataLen) + { + const BYTE *ptr; + LPSTR pszObjId = *(LPSTR *)pvStructInfo; + + *pszObjId = 0; + sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40, + pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / + 40) * 40); + pszObjId += strlen(pszObjId); + for (ptr = pbEncoded + 2 + lenBytes; ret && + ptr - pbEncoded - 1 - lenBytes < dataLen; ) + { + int val = 0; + + while (ptr - pbEncoded - 1 - lenBytes < dataLen && + (*ptr & 0x80)) + { + val <<= 7; + val |= *ptr & 0x7f; + ptr++; + } + val <<= 7; + val |= *ptr++; + sprintf(pszObjId, ".%d", val); + pszObjId += strlen(pszObjId); + } + } + else + *(LPSTR *)pvStructInfo = NULL; + *pcbStructInfo = bytesNeeded; + } + } + } + return ret; +} + +/* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set + * ahead of time! + */ +static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId), + CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + offsetof(CERT_EXTENSION, pszObjId), 0 }, + { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool, + sizeof(BOOL), TRUE, FALSE, 0, 0 }, + { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value), + CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, + offsetof(CERT_EXTENSION, Value.pbData) }, + }; + BOOL ret = TRUE; + PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext, + *pcbStructInfo); + + if (ext) + TRACE("ext->pszObjId is %p\n", ext->pszObjId); + ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, + ext, pcbStructInfo, ext ? ext->pszObjId : NULL); + if (ext) + TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId, + debugstr_a(ext->pszObjId)); + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, + offsetof(CERT_EXTENSION, pszObjId) }; + PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + __TRY + { + ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo); + if (ret && pvStructInfo) + { + ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, *pcbStructInfo); + if (ret) + { + CERT_EXTENSIONS *exts; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + exts = (CERT_EXTENSIONS *)pvStructInfo; + exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts + + sizeof(CERT_EXTENSIONS)); + ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + pcbStructInfo); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +/* Warning: this assumes the address of value->Value.pbData is already set, in + * order to avoid overwriting memory. (In some cases, it may change it, if it + * doesn't copy anything to memory.) Be sure to set it correctly! + */ +static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + DWORD dataLen; + CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + switch (pbEncoded[0]) + { + case ASN_NUMERICSTRING: + case ASN_PRINTABLESTRING: + case ASN_IA5STRING: + case ASN_T61STRING: + break; + default: + FIXME("Unimplemented string type %02x\n", pbEncoded[0]); + SetLastError(OSS_UNIMPLEMENTED); + ret = FALSE; + } + if (ret) + { + DWORD bytesNeeded = sizeof(CERT_NAME_VALUE); + + switch (pbEncoded[0]) + { + case ASN_NUMERICSTRING: + case ASN_PRINTABLESTRING: + case ASN_IA5STRING: + case ASN_T61STRING: + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; + } + if (!value) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbStructInfo = bytesNeeded; + switch (pbEncoded[0]) + { + case ASN_NUMERICSTRING: + value->dwValueType = CERT_RDN_NUMERIC_STRING; + break; + case ASN_PRINTABLESTRING: + value->dwValueType = CERT_RDN_PRINTABLE_STRING; + break; + case ASN_IA5STRING: + value->dwValueType = CERT_RDN_IA5_STRING; + break; + case ASN_T61STRING: + value->dwValueType = CERT_RDN_T61_STRING; + break; + } + if (dataLen) + { + switch (pbEncoded[0]) + { + case ASN_NUMERICSTRING: + case ASN_PRINTABLESTRING: + case ASN_IA5STRING: + case ASN_T61STRING: + value->Value.cbData = dataLen; + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + value->Value.pbData = (BYTE *)pbEncoded + 1 + + lenBytes; + else + { + assert(value->Value.pbData); + memcpy(value->Value.pbData, + pbEncoded + 1 + lenBytes, dataLen); + } + break; + } + } + else + { + value->Value.cbData = 0; + value->Value.pbData = NULL; + } + } + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + __TRY + { + ret = CRYPT_AsnDecodeNameValueInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo); + if (ret && pvStructInfo) + { + ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, *pcbStructInfo); + if (ret) + { + CERT_NAME_VALUE *value; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + value = (CERT_NAME_VALUE *)pvStructInfo; + value->Value.pbData = ((BYTE *)value + sizeof(CERT_NAME_VALUE)); + ret = CRYPT_AsnDecodeNameValueInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + pcbStructInfo); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId), + CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + offsetof(CERT_RDN_ATTR, pszObjId), 0 }, + { 0, offsetof(CERT_RDN_ATTR, dwValueType), + CRYPT_AsnDecodeNameValueInternal, sizeof(CERT_NAME_VALUE), + FALSE, TRUE, offsetof(CERT_RDN_ATTR, Value.pbData), 0 }, + }; + CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + if (attr) + TRACE("attr->pszObjId is %p\n", attr->pszObjId); + ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, + attr, pcbStructInfo, attr ? attr->pszObjId : NULL); + if (attr) + { + TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId, + debugstr_a(attr->pszObjId)); + TRACE("attr->dwValueType is %ld\n", attr->dwValueType); + } + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, + CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE, + offsetof(CERT_RDN_ATTR, pszObjId) }; + PCERT_RDN rdn = (PCERT_RDN)pvStructInfo; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE, + offsetof(CERT_RDN, rgRDNAttr) }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB); + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += cbEncoded; + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbStructInfo = bytesNeeded; + ret = FALSE; + } + else + { + PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo; + + *pcbStructInfo = bytesNeeded; + blob->cbData = cbEncoded; + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + blob->pbData = (LPBYTE)pbEncoded; + else + { + assert(blob->pbData); + memcpy(blob->pbData, pbEncoded, blob->cbData); + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + CRYPT_ALGORITHM_IDENTIFIER *algo = + (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo; + BOOL ret = TRUE; + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), + CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 }, + { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters), + CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, + offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 }, + }; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL); + if (ret && pvStructInfo) + { + TRACE("pszObjId is %p (%s)\n", algo->pszObjId, + debugstr_a(algo->pszObjId)); + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnDecodeSequenceItem items[] = { + { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO, + Algorithm.pszObjId) }, + { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, + offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) }, + }; + PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, info ? + info->Algorithm.Parameters.pbData : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + __TRY + { + DWORD bytesNeeded; + + if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + PCERT_PUBLIC_KEY_INFO info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; + info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo + + sizeof(CERT_PUBLIC_KEY_INFO); + ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (cbEncoded < 3) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + return FALSE; + } + if (GET_LEN_BYTES(pbEncoded[1]) > 1) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + return FALSE; + } + if (pbEncoded[1] > 1) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + return FALSE; + } + if (!pvStructInfo) + { + *pcbStructInfo = sizeof(BOOL); + ret = TRUE; + } + else if (*pcbStructInfo < sizeof(BOOL)) + { + *pcbStructInfo = sizeof(BOOL); + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE; + ret = TRUE; + } + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo; + DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY); + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if (cbEncoded < 2) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + return FALSE; + } + if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT) + { + SetLastError(CRYPT_E_ASN1_BADTAG); + return FALSE; + } + lenBytes = GET_LEN_BYTES(pbEncoded[1]); + if (1 + lenBytes > cbEncoded) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + return FALSE; + } + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + switch (pbEncoded[0] & ASN_TYPE_MASK) + { + case 1: /* rfc822Name */ + case 2: /* dNSName */ + case 6: /* uniformResourceIdentifier */ + bytesNeeded += (dataLen + 1) * sizeof(WCHAR); + break; + case 7: /* iPAddress */ + bytesNeeded += dataLen; + break; + case 8: /* registeredID */ + /* FIXME: decode as OID */ + case 0: /* otherName */ + case 4: /* directoryName */ + FIXME("stub\n"); + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + break; + case 3: /* x400Address, unimplemented */ + case 5: /* ediPartyName, unimplemented */ + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + break; + default: + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + if (ret) + { + if (!entry) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbStructInfo = bytesNeeded; + /* MS used values one greater than the asn1 ones.. sigh */ + entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1; + switch (pbEncoded[0] & ASN_TYPE_MASK) + { + case 1: /* rfc822Name */ + case 2: /* dNSName */ + case 6: /* uniformResourceIdentifier */ + { + DWORD i; + + for (i = 0; i < dataLen; i++) + entry->u.pwszURL[i] = + (WCHAR)pbEncoded[1 + lenBytes + i]; + entry->u.pwszURL[i] = 0; + TRACE("URL is %p (%s)\n", entry->u.pwszURL, + debugstr_w(entry->u.pwszURL)); + break; + } + case 7: /* iPAddress */ + /* The next data pointer is in the pwszURL spot, that is, + * the first 4 bytes. Need to move it to the next spot. + */ + entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL; + entry->u.IPAddress.cbData = dataLen; + memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes, + dataLen); + break; + } + } + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, + offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; + PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if (info) + TRACE("info->rgAltEntry is %p\n", info->rgAltEntry); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, + offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +struct PATH_LEN_CONSTRAINT +{ + BOOL fPathLenConstraint; + DWORD dwPathLenConstraint; +}; + +static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + if (cbEncoded) + { + if (pbEncoded[0] == ASN_INTEGER) + { + DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT); + + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbStructInfo = bytesNeeded; + ret = FALSE; + } + else + { + struct PATH_LEN_CONSTRAINT *constraint = + (struct PATH_LEN_CONSTRAINT *)pvStructInfo; + DWORD size = sizeof(constraint->dwPathLenConstraint); + + ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, + pbEncoded, cbEncoded, 0, NULL, + &constraint->dwPathLenConstraint, &size); + if (ret) + constraint->fPathLenConstraint = TRUE; + TRACE("got an int, dwPathLenConstraint is %ld\n", + constraint->dwPathLenConstraint); + } + } + else + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + } + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE, + offsetof(CERT_NAME_BLOB, pbData) }; + struct GenericArray *entries = (struct GenericArray *)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, + entries ? entries->rgItems : NULL); + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, + offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 }, + { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO, + fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, + sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, + { ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO, + cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints, + sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), + CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 }, + { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, + fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, + sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +#define RSA1_MAGIC 0x31415352 + +struct DECODED_RSA_PUB_KEY +{ + DWORD pubexp; + CRYPT_INTEGER_BLOB modulus; +}; + +static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp), + CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + }; + struct DECODED_RSA_PUB_KEY *decodedKey = NULL; + DWORD size = 0; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, + CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL); + if (ret) + { + DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + + decodedKey->modulus.cbData; + + if (!pvStructInfo) + { + *pcbStructInfo = bytesNeeded; + ret = TRUE; + } + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + BLOBHEADER *hdr; + RSAPUBKEY *rsaPubKey; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + hdr = (BLOBHEADER *)pvStructInfo; + hdr->bType = PUBLICKEYBLOB; + hdr->bVersion = CUR_BLOB_VERSION; + hdr->reserved = 0; + hdr->aiKeyAlg = CALG_RSA_KEYX; + rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo + + sizeof(BLOBHEADER)); + rsaPubKey->magic = RSA1_MAGIC; + rsaPubKey->pubexp = decodedKey->pubexp; + rsaPubKey->bitlen = decodedKey->modulus.cbData * 8; + memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) + + sizeof(RSAPUBKEY), decodedKey->modulus.pbData, + decodedKey->modulus.cbData); + } + LocalFree(decodedKey); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + DWORD bytesNeeded, dataLen; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + bytesNeeded = sizeof(CRYPT_DATA_BLOB); + else + bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB); + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbStructInfo = bytesNeeded; + ret = FALSE; + } + else + { + CRYPT_DATA_BLOB *blob; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + blob = (CRYPT_DATA_BLOB *)pvStructInfo; + blob->cbData = dataLen; + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes; + else + { + assert(blob->pbData); + if (blob->cbData) + memcpy(blob->pbData, pbEncoded + 1 + lenBytes, + blob->cbData); + } + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + DWORD bytesNeeded; + + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (pbEncoded[0] != ASN_OCTETSTRING) + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CRYPT_DATA_BLOB *blob; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + blob = (CRYPT_DATA_BLOB *)pvStructInfo; + blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB); + ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if (pbEncoded[0] == ASN_BITSTRING) + { + DWORD bytesNeeded, dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + bytesNeeded = sizeof(CRYPT_BIT_BLOB); + else + bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB); + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CRYPT_BIT_BLOB *blob; + + blob = (CRYPT_BIT_BLOB *)pvStructInfo; + blob->cbData = dataLen - 1; + blob->cUnusedBits = *(pbEncoded + 1 + + GET_LEN_BYTES(pbEncoded[1])); + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + { + blob->pbData = (BYTE *)pbEncoded + 2 + + GET_LEN_BYTES(pbEncoded[1]); + } + else + { + assert(blob->pbData); + if (blob->cbData) + { + BYTE mask = 0xff << blob->cUnusedBits; + + memcpy(blob->pbData, pbEncoded + 2 + + GET_LEN_BYTES(pbEncoded[1]), blob->cbData); + blob->pbData[blob->cbData - 1] &= mask; + } + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo); + + __TRY + { + DWORD bytesNeeded; + + if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CRYPT_BIT_BLOB *blob; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + blob = (CRYPT_BIT_BLOB *)pvStructInfo; + blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB); + ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + TRACE("returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (!pvStructInfo) + { + *pcbStructInfo = sizeof(int); + return TRUE; + } + __TRY + { + BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)]; + CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; + DWORD size = sizeof(buf); + + blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB); + ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, + X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size); + if (ret) + { + if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, sizeof(int)))) + { + int val, i; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + if (blob->pbData[blob->cbData - 1] & 0x80) + { + /* initialize to a negative value to sign-extend */ + val = -1; + } + else + val = 0; + for (i = 0; i < blob->cbData; i++) + { + val <<= 8; + val |= blob->pbData[blob->cbData - i - 1]; + } + memcpy(pvStructInfo, &val, sizeof(int)); + } + } + else if (GetLastError() == ERROR_MORE_DATA) + SetLastError(CRYPT_E_ASN1_LARGE); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (pbEncoded[0] == ASN_INTEGER) + { + DWORD bytesNeeded, dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB); + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; + + blob->cbData = dataLen; + assert(blob->pbData); + if (blob->cbData) + { + DWORD i; + + for (i = 0; i < blob->cbData; i++) + { + blob->pbData[i] = *(pbEncoded + 1 + lenBytes + + dataLen - i - 1); + } + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + DWORD bytesNeeded; + + if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CRYPT_INTEGER_BLOB *blob; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; + blob->pbData = (BYTE *)pvStructInfo + + sizeof(CRYPT_INTEGER_BLOB); + ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( + DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (pbEncoded[0] == ASN_INTEGER) + { + DWORD bytesNeeded, dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB); + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; + + blob->cbData = dataLen; + assert(blob->pbData); + /* remove leading zero byte if it exists */ + if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0) + { + blob->cbData--; + blob->pbData++; + } + if (blob->cbData) + { + DWORD i; + + for (i = 0; i < blob->cbData; i++) + { + blob->pbData[i] = *(pbEncoded + 1 + lenBytes + + dataLen - i - 1); + } + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + DWORD bytesNeeded; + + if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CRYPT_INTEGER_BLOB *blob; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; + blob->pbData = (BYTE *)pvStructInfo + + sizeof(CRYPT_INTEGER_BLOB); + ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (!pvStructInfo) + { + *pcbStructInfo = sizeof(int); + return TRUE; + } + __TRY + { + if (pbEncoded[0] == ASN_ENUMERATED) + { + unsigned int val = 0, i; + + if (cbEncoded <= 1) + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + else if (pbEncoded[1] == 0) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + /* A little strange looking, but we have to accept a sign byte: + * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also, + * assuming a small length is okay here, it has to be in short + * form. + */ + if (pbEncoded[1] > sizeof(unsigned int) + 1) + { + SetLastError(CRYPT_E_ASN1_LARGE); + return FALSE; + } + for (i = 0; i < pbEncoded[1]; i++) + { + val <<= 8; + val |= pbEncoded[2 + i]; + } + if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, sizeof(unsigned int)))) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + memcpy(pvStructInfo, &val, sizeof(unsigned int)); + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +/* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE + * if it fails. + */ +#define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \ + do { \ + BYTE i; \ + \ + (word) = 0; \ + for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \ + { \ + if (!isdigit(*(pbEncoded))) \ + { \ + SetLastError(CRYPT_E_ASN1_CORRUPT); \ + ret = FALSE; \ + } \ + else \ + { \ + (word) *= 10; \ + (word) += *(pbEncoded)++ - '0'; \ + } \ + } \ + } while (0) + +static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len, + SYSTEMTIME *sysTime) +{ + BOOL ret; + + __TRY + { + ret = TRUE; + if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-')) + { + WORD hours, minutes = 0; + BYTE sign = *pbEncoded++; + + len--; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours); + if (ret && hours >= 24) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (len >= 2) + { + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes); + if (ret && minutes >= 60) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + } + if (ret) + { + if (sign == '+') + { + sysTime->wHour += hours; + sysTime->wMinute += minutes; + } + else + { + if (hours > sysTime->wHour) + { + sysTime->wDay--; + sysTime->wHour = 24 - (hours - sysTime->wHour); + } + else + sysTime->wHour -= hours; + if (minutes > sysTime->wMinute) + { + sysTime->wHour--; + sysTime->wMinute = 60 - (minutes - sysTime->wMinute); + } + else + sysTime->wMinute -= minutes; + } + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +#define MIN_ENCODED_TIME_LENGTH 10 + +static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (!pvStructInfo) + { + *pcbStructInfo = sizeof(FILETIME); + return TRUE; + } + __TRY + { + ret = TRUE; + if (pbEncoded[0] == ASN_UTCTIME) + { + if (cbEncoded <= 1) + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + else if (pbEncoded[1] > 0x7f) + { + /* long-form date strings really can't be valid */ + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + SYSTEMTIME sysTime = { 0 }; + BYTE len = pbEncoded[1]; + + if (len < MIN_ENCODED_TIME_LENGTH) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + pbEncoded += 2; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear); + if (sysTime.wYear >= 50) + sysTime.wYear += 1900; + else + sysTime.wYear += 2000; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute); + if (ret && len > 0) + { + if (len >= 2 && isdigit(*pbEncoded) && + isdigit(*(pbEncoded + 1))) + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, + sysTime.wSecond); + else if (isdigit(*pbEncoded)) + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, + sysTime.wSecond); + if (ret) + ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, + &sysTime); + } + if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, + sizeof(FILETIME)))) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + ret = SystemTimeToFileTime(&sysTime, + (FILETIME *)pvStructInfo); + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (!pvStructInfo) + { + *pcbStructInfo = sizeof(FILETIME); + return TRUE; + } + __TRY + { + ret = TRUE; + if (pbEncoded[0] == ASN_GENERALTIME) + { + if (cbEncoded <= 1) + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + else if (pbEncoded[1] > 0x7f) + { + /* long-form date strings really can't be valid */ + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + BYTE len = pbEncoded[1]; + + if (len < MIN_ENCODED_TIME_LENGTH) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + SYSTEMTIME sysTime = { 0 }; + + pbEncoded += 2; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); + if (ret && len > 0) + { + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, + sysTime.wMinute); + if (ret && len > 0) + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, + sysTime.wSecond); + if (ret && len > 0 && (*pbEncoded == '.' || + *pbEncoded == ',')) + { + BYTE digits; + + pbEncoded++; + len--; + /* workaround macro weirdness */ + digits = min(len, 3); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits, + sysTime.wMilliseconds); + } + if (ret) + ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, + &sysTime); + } + if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, + sizeof(FILETIME)))) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + ret = SystemTimeToFileTime(&sysTime, + (FILETIME *)pvStructInfo); + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + if (pbEncoded[0] == ASN_UTCTIME) + ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo); + else if (pbEncoded[0] == ASN_GENERALTIME) + ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + __TRY + { + if (pbEncoded[0] == ASN_SEQUENCEOF) + { + DWORD bytesNeeded, dataLen, remainingLen, cValue; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes; + const BYTE *ptr; + + lenBytes = GET_LEN_BYTES(pbEncoded[1]); + bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY); + cValue = 0; + ptr = pbEncoded + 1 + lenBytes; + remainingLen = dataLen; + while (ret && remainingLen) + { + DWORD nextLen; + + ret = CRYPT_GetLen(ptr, remainingLen, &nextLen); + if (ret) + { + DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]); + + remainingLen -= 1 + nextLenBytes + nextLen; + ptr += 1 + nextLenBytes + nextLen; + bytesNeeded += sizeof(CRYPT_DER_BLOB); + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += 1 + nextLenBytes + nextLen; + cValue++; + } + } + if (ret) + { + CRYPT_SEQUENCE_OF_ANY *seq; + BYTE *nextPtr; + DWORD i; + + if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo; + seq->cValue = cValue; + seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq + + sizeof(*seq)); + nextPtr = (BYTE *)seq->rgValue + + cValue * sizeof(CRYPT_DER_BLOB); + ptr = pbEncoded + 1 + lenBytes; + remainingLen = dataLen; + i = 0; + while (ret && remainingLen) + { + DWORD nextLen; + + ret = CRYPT_GetLen(ptr, remainingLen, &nextLen); + if (ret) + { + DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]); + + seq->rgValue[i].cbData = 1 + nextLenBytes + + nextLen; + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + seq->rgValue[i].pbData = (BYTE *)ptr; + else + { + seq->rgValue[i].pbData = nextPtr; + memcpy(nextPtr, ptr, 1 + nextLenBytes + + nextLen); + nextPtr += 1 + nextLenBytes + nextLen; + } + remainingLen -= 1 + nextLenBytes + nextLen; + ptr += 1 + nextLenBytes + nextLen; + i++; + } + } + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeDistPointName(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)) + { + DWORD bytesNeeded, dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + struct AsnArrayDescriptor arrayDesc = { + ASN_CONTEXT | ASN_CONSTRUCTOR | 0, CRYPT_AsnDecodeAltNameEntry, + sizeof(CERT_ALT_NAME_ENTRY), TRUE, + offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + if (dataLen) + { + DWORD nameLen; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, + pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, + 0, NULL, NULL, &nameLen, NULL); + bytesNeeded = sizeof(CRL_DIST_POINT_NAME) + nameLen; + } + else + bytesNeeded = sizeof(CRL_DIST_POINT_NAME); + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CRL_DIST_POINT_NAME *name = (CRL_DIST_POINT_NAME *)pvStructInfo; + + if (dataLen) + { + name->dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + ret = CRYPT_AsnDecodeArray(&arrayDesc, + pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, + 0, NULL, &name->u.FullName, pcbStructInfo, + name->u.FullName.rgAltEntry); + } + else + name->dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME; + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT, + DistPointName), CRYPT_AsnDecodeDistPointName, + sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT, + DistPointName.u.FullName.rgAltEntry), 0 }, + { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, + offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer), + CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE, + offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 }, + }; + BOOL ret; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE, + offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeIssuingDistPoint(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_ISSUING_DIST_POINT, + DistPointName), CRYPT_AsnDecodeDistPointName, + sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, + offsetof(CRL_ISSUING_DIST_POINT, + DistPointName.u.FullName.rgAltEntry), 0 }, + { ASN_CONTEXT | 1, offsetof(CRL_ISSUING_DIST_POINT, + fOnlyContainsUserCerts), CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, + FALSE, 0 }, + { ASN_CONTEXT | 2, offsetof(CRL_ISSUING_DIST_POINT, + fOnlyContainsCACerts), CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, + FALSE, 0 }, + { ASN_CONTEXT | 3, offsetof(CRL_ISSUING_DIST_POINT, + OnlySomeReasonFlags), CRYPT_AsnDecodeBitsInternal, + sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CRL_ISSUING_DIST_POINT, + OnlySomeReasonFlags.pbData), 0 }, + { ASN_CONTEXT | 4, offsetof(CRL_ISSUING_DIST_POINT, + fIndirectCRL), CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, + const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + static HCRYPTOIDFUNCSET set = NULL; + BOOL ret = FALSE; + CryptDecodeObjectExFunc decodeFunc = NULL; + HCRYPTOIDFUNCADDR hFunc = NULL; + + TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n", + dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded, + cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); + + if (!pvStructInfo && !pcbStructInfo) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING + && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + return FALSE; + } + if (cbEncoded > MAX_ENCODED_LEN) + { + SetLastError(CRYPT_E_ASN1_LARGE); + return FALSE; + } + + SetLastError(NOERROR); + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo) + *(BYTE **)pvStructInfo = NULL; + if (!HIWORD(lpszStructType)) + { + switch (LOWORD(lpszStructType)) + { + case (WORD)X509_CERT: + decodeFunc = CRYPT_AsnDecodeCertSignedContent; + break; + case (WORD)X509_CERT_TO_BE_SIGNED: + decodeFunc = CRYPT_AsnDecodeCert; + break; + case (WORD)X509_CERT_CRL_TO_BE_SIGNED: + decodeFunc = CRYPT_AsnDecodeCRL; + break; + case (WORD)X509_EXTENSIONS: + decodeFunc = CRYPT_AsnDecodeExtensions; + break; + case (WORD)X509_NAME_VALUE: + decodeFunc = CRYPT_AsnDecodeNameValue; + break; + case (WORD)X509_NAME: + decodeFunc = CRYPT_AsnDecodeName; + break; + case (WORD)X509_PUBLIC_KEY_INFO: + decodeFunc = CRYPT_AsnDecodePubKeyInfo; + break; + case (WORD)X509_ALTERNATE_NAME: + decodeFunc = CRYPT_AsnDecodeAltName; + break; + case (WORD)X509_BASIC_CONSTRAINTS: + decodeFunc = CRYPT_AsnDecodeBasicConstraints; + break; + case (WORD)X509_BASIC_CONSTRAINTS2: + decodeFunc = CRYPT_AsnDecodeBasicConstraints2; + break; + case (WORD)RSA_CSP_PUBLICKEYBLOB: + decodeFunc = CRYPT_AsnDecodeRsaPubKey; + break; + case (WORD)X509_OCTET_STRING: + decodeFunc = CRYPT_AsnDecodeOctets; + break; + case (WORD)X509_BITS: + case (WORD)X509_KEY_USAGE: + decodeFunc = CRYPT_AsnDecodeBits; + break; + case (WORD)X509_INTEGER: + decodeFunc = CRYPT_AsnDecodeInt; + break; + case (WORD)X509_MULTI_BYTE_INTEGER: + decodeFunc = CRYPT_AsnDecodeInteger; + break; + case (WORD)X509_MULTI_BYTE_UINT: + decodeFunc = CRYPT_AsnDecodeUnsignedInteger; + break; + case (WORD)X509_ENUMERATED: + decodeFunc = CRYPT_AsnDecodeEnumerated; + break; + case (WORD)X509_CHOICE_OF_TIME: + decodeFunc = CRYPT_AsnDecodeChoiceOfTime; + break; + case (WORD)X509_SEQUENCE_OF_ANY: + decodeFunc = CRYPT_AsnDecodeSequenceOfAny; + break; + case (WORD)PKCS_UTC_TIME: + decodeFunc = CRYPT_AsnDecodeUtcTime; + break; + case (WORD)X509_CRL_DIST_POINTS: + decodeFunc = CRYPT_AsnDecodeCRLDistPoints; + break; + case (WORD)X509_ENHANCED_KEY_USAGE: + decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; + break; + case (WORD)X509_ISSUING_DIST_POINT: + decodeFunc = CRYPT_AsnDecodeIssuingDistPoint; + break; + default: + FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); + } + } + else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) + decodeFunc = CRYPT_AsnDecodeExtensions; + else if (!strcmp(lpszStructType, szOID_RSA_signingTime)) + decodeFunc = CRYPT_AsnDecodeUtcTime; + else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) + decodeFunc = CRYPT_AsnDecodeEnumerated; + else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) + decodeFunc = CRYPT_AsnDecodeBits; + else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER)) + decodeFunc = CRYPT_AsnDecodeOctets; + else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS)) + decodeFunc = CRYPT_AsnDecodeBasicConstraints; + else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) + decodeFunc = CRYPT_AsnDecodeBasicConstraints2; + else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) + decodeFunc = CRYPT_AsnDecodeAltName; + else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2)) + decodeFunc = CRYPT_AsnDecodeAltName; + else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION)) + decodeFunc = CRYPT_AsnDecodeAltName; + else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME)) + decodeFunc = CRYPT_AsnDecodeAltName; + else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) + decodeFunc = CRYPT_AsnDecodeAltName; + else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) + decodeFunc = CRYPT_AsnDecodeCRLDistPoints; + else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) + decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; + else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT)) + decodeFunc = CRYPT_AsnDecodeIssuingDistPoint; + else + TRACE("OID %s not found or unimplemented, looking for DLL\n", + debugstr_a(lpszStructType)); + if (!decodeFunc) + { + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, + (void **)&decodeFunc, &hFunc); + } + if (decodeFunc) + ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded, + cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); + else + SetLastError(ERROR_FILE_NOT_FOUND); + if (hFunc) + CryptFreeOIDFunctionAddress(hFunc, 0); + return ret; +} diff --git a/reactos/dll/win32/crypt32/encode.c b/reactos/dll/win32/crypt32/encode.c index d04f747fa2f..2f4e5310068 100644 --- a/reactos/dll/win32/crypt32/encode.c +++ b/reactos/dll/win32/crypt32/encode.c @@ -13,10 +13,10 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * This file implements ASN.1 DER encoding and decoding of a limited set of - * types. It isn't a full ASN.1 implementation. Microsoft implements BER + * This file implements ASN.1 DER encoding of a limited set of types. + * It isn't a full ASN.1 implementation. Microsoft implements BER * encoding of many of the basic types in msasn1.dll, but that interface is * undocumented, so I implement them here. * @@ -31,9 +31,6 @@ * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp */ -#include "config.h" -#include "wine/port.h" - #include #include #include @@ -51,45 +48,17 @@ #include "wine/exception.h" #include "crypt32_private.h" -/* This is a bit arbitrary, but to set some limit: */ -#define MAX_ENCODED_LEN 0x02000000 - -/* a few asn.1 tags we need */ -#define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01) -#define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03) -#define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a) -#define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11) -#define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12) -#define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13) -#define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16) -#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17) -#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18) - -#define ASN_FLAGS_MASK 0xe0 -#define ASN_TYPE_MASK 0x1f - WINE_DEFAULT_DEBUG_CHANNEL(crypt); -struct GenericArray -{ - DWORD cItems; - BYTE *rgItems; -}; - typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *, BYTE *, DWORD *); typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *, DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *); -typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, - DWORD, DWORD, void *, DWORD *); -typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *, - DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *); -/* Prototypes for built-in encoders/decoders. They follow the Ex style - * prototypes. The dwCertEncodingType and lpszStructType are ignored by the - * built-in functions, but the parameters are retained to simplify - * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in - * external DLLs that follow these signatures. +/* Prototypes for built-in encoders. They follow the Ex style prototypes. + * The dwCertEncodingType and lpszStructType are ignored by the built-in + * functions, but the parameters are retained to simplify CryptEncodeObjectEx, + * since it must call functions in external DLLs that follow these signatures. */ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, @@ -128,59 +97,6 @@ static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); -static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of - * time, doesn't do memory allocation, and doesn't do exception handling. - * (This isn't intended to be the externally-called one.) - */ -static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded, - DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId); -/* Assumes algo->Parameters.pbData is set ahead of time. Internal func. */ -static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Internal function */ -static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */ -static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData - * member has been initialized, doesn't do exception handling, and doesn't do - * memory allocation. - */ -static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData - * member has been initialized, doesn't do exception handling, and doesn't do - * memory allocation. - */ -static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Like CRYPT_AsnDecodeInteger, but unsigned. */ -static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( - DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo); - BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded) { @@ -759,7 +675,8 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType, { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 }, { 0 } }; - DWORD cItem = 4; + struct AsnConstructedItem constructed[1] = { { 0 } }; + DWORD cItem = 4, cConstructed = 0; if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime) { @@ -775,8 +692,12 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType, } if (info->cExtension) { - items[cItem].pvStructInfo = &info->cExtension; - items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions; + constructed[cConstructed].tag = 0; + constructed[cConstructed].pvStructInfo = &info->cExtension; + constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions; + items[cItem].pvStructInfo = &constructed[cConstructed]; + items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; + cConstructed++; cItem++; } @@ -990,58 +911,74 @@ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, } static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType, - CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded) + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { - BYTE tag; - DWORD bytesNeeded, lenBytes, encodedLen; BOOL ret = TRUE; - switch (value->dwValueType) + __TRY { - case CERT_RDN_NUMERIC_STRING: - tag = ASN_NUMERICSTRING; - encodedLen = value->Value.cbData; - break; - case CERT_RDN_PRINTABLE_STRING: - tag = ASN_PRINTABLESTRING; - encodedLen = value->Value.cbData; - break; - case CERT_RDN_IA5_STRING: - tag = ASN_IA5STRING; - encodedLen = value->Value.cbData; - break; - case CERT_RDN_ANY_TYPE: - /* explicitly disallowed */ - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - default: - FIXME("String type %ld unimplemented\n", value->dwValueType); - return FALSE; - } - CRYPT_EncodeLen(encodedLen, NULL, &lenBytes); - bytesNeeded = 1 + lenBytes + encodedLen; - if (pbEncoded) - { - if (*pcbEncoded < bytesNeeded) + BYTE tag; + DWORD bytesNeeded, lenBytes, encodedLen; + const CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo; + + switch (value->dwValueType) { - SetLastError(ERROR_MORE_DATA); - ret = FALSE; + case CERT_RDN_NUMERIC_STRING: + tag = ASN_NUMERICSTRING; + encodedLen = value->Value.cbData; + break; + case CERT_RDN_PRINTABLE_STRING: + tag = ASN_PRINTABLESTRING; + encodedLen = value->Value.cbData; + break; + case CERT_RDN_T61_STRING: + tag = ASN_T61STRING; + encodedLen = value->Value.cbData; + break; + case CERT_RDN_IA5_STRING: + tag = ASN_IA5STRING; + encodedLen = value->Value.cbData; + break; + case CERT_RDN_ANY_TYPE: + /* explicitly disallowed */ + SetLastError(E_INVALIDARG); + return FALSE; + default: + FIXME("String type %ld unimplemented\n", value->dwValueType); + return FALSE; } + CRYPT_EncodeLen(encodedLen, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + encodedLen; + if (!pbEncoded) + *pcbEncoded = bytesNeeded; else { - *pbEncoded++ = tag; - CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; - switch (value->dwValueType) + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, + pcbEncoded, bytesNeeded))) { - case CERT_RDN_NUMERIC_STRING: - case CERT_RDN_PRINTABLE_STRING: - case CERT_RDN_IA5_STRING: - memcpy(pbEncoded, value->Value.pbData, value->Value.cbData); + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = tag; + CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + switch (value->dwValueType) + { + case CERT_RDN_NUMERIC_STRING: + case CERT_RDN_PRINTABLE_STRING: + case CERT_RDN_T61_STRING: + case CERT_RDN_IA5_STRING: + memcpy(pbEncoded, value->Value.pbData, value->Value.cbData); + } } } } - *pcbEncoded = bytesNeeded; + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY return ret; } @@ -1059,8 +996,8 @@ static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType, /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning * with dwValueType, so "cast" it to get its encoded size */ - ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType, - (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size); + ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType, X509_NAME_VALUE, + (CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size); if (ret) { bytesNeeded += size; @@ -1087,8 +1024,8 @@ static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType, pbEncoded += size; size = bytesNeeded - 1 - lenBytes - size; ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType, - (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded, - &size); + X509_NAME_VALUE, (CERT_NAME_VALUE *)&attr->dwValueType, + 0, NULL, pbEncoded, &size); } } } @@ -1327,7 +1264,7 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice); return FALSE; default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return FALSE; } if (ret) @@ -1541,7 +1478,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType, if (hdr->bType != PUBLICKEYBLOB) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } else @@ -1957,7 +1894,7 @@ static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType, snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900, - sysTime.wDay, sysTime.wMonth, sysTime.wHour, + sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond); memcpy(pbEncoded, buf, bytesNeeded); } @@ -2007,7 +1944,7 @@ static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType, buf[0] = ASN_GENERALTIME; buf[1] = bytesNeeded - 2; snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ", - sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour, + sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond); memcpy(pbEncoded, buf, bytesNeeded); } @@ -2173,7 +2110,7 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType, if (!info->cDistPoint) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } else @@ -2304,6 +2241,96 @@ static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CRL_ISSUING_DIST_POINT *point = + (const CRL_ISSUING_DIST_POINT *)pvStructInfo; + struct AsnEncodeSequenceItem items[6] = { { 0 } }; + struct AsnConstructedItem constructed = { 0 }; + struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } }; + DWORD cItem = 0, cSwapped = 0; + + ret = TRUE; + switch (point->DistPointName.dwDistPointNameChoice) + { + case CRL_DIST_POINT_NO_NAME: + /* do nothing */ + break; + case CRL_DIST_POINT_FULL_NAME: + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0; + swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName; + constructed.tag = 0; + constructed.pvStructInfo = &swapped[cSwapped]; + constructed.encodeFunc = CRYPT_AsnEncodeSwapTag; + items[cItem].pvStructInfo = &constructed; + items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; + cSwapped++; + cItem++; + break; + default: + SetLastError(E_INVALIDARG); + ret = FALSE; + } + if (ret && point->fOnlyContainsUserCerts) + { + swapped[cSwapped].tag = ASN_CONTEXT | 1; + swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (ret && point->fOnlyContainsCACerts) + { + swapped[cSwapped].tag = ASN_CONTEXT | 2; + swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (ret && point->OnlySomeReasonFlags.cbData) + { + swapped[cSwapped].tag = ASN_CONTEXT | 3; + swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (ret && point->fIndirectCRL) + { + swapped[cSwapped].tag = ASN_CONTEXT | 4; + swapped[cSwapped].pvStructInfo = &point->fIndirectCRL; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (ret) + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, void *pvEncoded, DWORD *pcbEncoded) @@ -2348,6 +2375,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_EXTENSIONS: encodeFunc = CRYPT_AsnEncodeExtensions; break; + case (WORD)X509_NAME_VALUE: + encodeFunc = CRYPT_AsnEncodeNameValue; + break; case (WORD)X509_NAME: encodeFunc = CRYPT_AsnEncodeName; break; @@ -2400,6 +2430,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_ENHANCED_KEY_USAGE: encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; break; + case (WORD)X509_ISSUING_DIST_POINT: + encodeFunc = CRYPT_AsnEncodeIssuingDistPoint; + break; default: FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); } @@ -2432,6 +2465,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, encodeFunc = CRYPT_AsnEncodeCRLDistPoints; else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; + else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT)) + encodeFunc = CRYPT_AsnEncodeIssuingDistPoint; else TRACE("OID %s not found or unimplemented, looking for DLL\n", debugstr_a(lpszStructType)); @@ -2452,2989 +2487,6 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, return ret; } -BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, - const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, - DWORD *pcbStructInfo) -{ - static HCRYPTOIDFUNCSET set = NULL; - BOOL ret = FALSE; - CryptDecodeObjectFunc pCryptDecodeObject; - HCRYPTOIDFUNCADDR hFunc; - - TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType, - debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags, - pvStructInfo, pcbStructInfo); - - if (!pvStructInfo && !pcbStructInfo) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* Try registered DLL first.. */ - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, - (void **)&pCryptDecodeObject, &hFunc); - if (pCryptDecodeObject) - { - ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType, - pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo); - CryptFreeOIDFunctionAddress(hFunc, 0); - } - else - { - /* If not, use CryptDecodeObjectEx */ - ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded, - cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo); - } - return ret; -} - -/* Gets the number of length bytes from the given (leading) length byte */ -#define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f)) - -/* Helper function to get the encoded length of the data starting at pbEncoded, - * where pbEncoded[0] is the tag. If the data are too short to contain a - * length or if the length is too large for cbEncoded, sets an appropriate - * error code and returns FALSE. - */ -static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, - DWORD *len) -{ - BOOL ret; - - if (cbEncoded <= 1) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else if (pbEncoded[1] <= 0x7f) - { - if (pbEncoded[1] + 1 > cbEncoded) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else - { - *len = pbEncoded[1]; - ret = TRUE; - } - } - else - { - BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]); - - if (lenLen > sizeof(DWORD) + 1) - { - SetLastError(CRYPT_E_ASN1_LARGE); - ret = FALSE; - } - else if (lenLen + 2 > cbEncoded) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - DWORD out = 0; - - pbEncoded += 2; - while (--lenLen) - { - out <<= 8; - out |= *pbEncoded++; - } - if (out + lenLen + 1 > cbEncoded) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else - { - *len = out; - ret = TRUE; - } - } - } - return ret; -} - -/* Helper function to check *pcbStructInfo, set it to the required size, and - * optionally to allocate memory. Assumes pvStructInfo is not NULL. - * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a - * pointer to the newly allocated memory. - */ -static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, - DWORD bytesNeeded) -{ - BOOL ret = TRUE; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - { - if (pDecodePara && pDecodePara->pfnAlloc) - *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded); - else - *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded); - if (!*(BYTE **)pvStructInfo) - ret = FALSE; - else - *pcbStructInfo = bytesNeeded; - } - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - return ret; -} - -/* tag: - * The expected tag of the item. If tag is 0, decodeFunc is called - * regardless of the tag value seen. - * offset: - * A sequence is decoded into a struct. The offset member is the - * offset of this item within that struct. - * decodeFunc: - * The decoder function to use. If this is NULL, then the member isn't - * decoded, but minSize space is reserved for it. - * minSize: - * The minimum amount of space occupied after decoding. You must set this. - * optional: - * If true, and the tag doesn't match the expected tag for this item, - * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is - * filled with 0 for this member. - * hasPointer, pointerOffset, minSize: - * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to - * the offset within the (outer) struct of the data pointer (or to the - * first data pointer, if more than one exist). - * size: - * Used by CRYPT_AsnDecodeSequence, not for your use. - */ -struct AsnDecodeSequenceItem -{ - BYTE tag; - DWORD offset; - CryptDecodeObjectExFunc decodeFunc; - DWORD minSize; - BOOL optional; - BOOL hasPointer; - DWORD pointerOffset; - DWORD size; -}; - -static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, - struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData) -{ - BOOL ret; - DWORD i; - const BYTE *ptr; - - ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]); - for (i = 0, ret = TRUE; ret && i < cItem; i++) - { - if (cbEncoded - (ptr - pbEncoded) != 0) - { - DWORD nextItemLen; - - if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), - &nextItemLen))) - { - BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]); - - if (ptr[0] == items[i].tag || !items[i].tag) - { - if (nextData && pvStructInfo && items[i].hasPointer) - { - TRACE("Setting next pointer to %p\n", - nextData); - *(BYTE **)((BYTE *)pvStructInfo + - items[i].pointerOffset) = nextData; - } - if (items[i].decodeFunc) - { - if (pvStructInfo) - TRACE("decoding item %ld\n", i); - else - TRACE("sizing item %ld\n", i); - ret = items[i].decodeFunc(dwCertEncodingType, - NULL, ptr, 1 + nextItemLenBytes + nextItemLen, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, - pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset - : NULL, &items[i].size); - if (ret) - { - if (nextData && items[i].hasPointer && - items[i].size > items[i].minSize) - { - nextData += items[i].size - items[i].minSize; - /* align nextData to DWORD boundaries */ - if (items[i].size % sizeof(DWORD)) - nextData += sizeof(DWORD) - items[i].size % - sizeof(DWORD); - } - /* Account for alignment padding */ - if (items[i].size % sizeof(DWORD)) - items[i].size += sizeof(DWORD) - - items[i].size % sizeof(DWORD); - ptr += 1 + nextItemLenBytes + nextItemLen; - } - else if (items[i].optional && - GetLastError() == CRYPT_E_ASN1_BADTAG) - { - TRACE("skipping optional item %ld\n", i); - items[i].size = items[i].minSize; - SetLastError(NOERROR); - ret = TRUE; - } - else - TRACE("item %ld failed: %08lx\n", i, - GetLastError()); - } - else - items[i].size = items[i].minSize; - } - else if (items[i].optional) - { - TRACE("skipping optional item %ld\n", i); - items[i].size = items[i].minSize; - } - else - { - TRACE("tag %02x doesn't match expected %02x\n", - ptr[0], items[i].tag); - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - } - } - else if (items[i].optional) - { - TRACE("missing optional item %ld, skipping\n", i); - items[i].size = items[i].minSize; - } - else - { - TRACE("not enough bytes for item %ld, failing\n", i); - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - } - if (cbEncoded - (ptr - pbEncoded) != 0) - { - TRACE("%ld remaining bytes, failing\n", cbEncoded - - (ptr - pbEncoded)); - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - return ret; -} - -/* This decodes an arbitrary sequence into a contiguous block of memory - * (basically, a struct.) Each element being decoded is described by a struct - * AsnDecodeSequenceItem, see above. - * startingPointer is an optional pointer to the first place where dynamic - * data will be stored. If you know the starting offset, you may pass it - * here. Otherwise, pass NULL, and one will be inferred from the items. - * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set. - * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT. - */ -static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, - struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer) -{ - BOOL ret; - - TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded, - cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, - startingPointer); - - if (pbEncoded[0] == ASN_SEQUENCE) - { - DWORD dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - DWORD i; - - ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded, - cbEncoded, dwFlags, NULL, NULL); - if (ret) - { - DWORD bytesNeeded = 0, structSize = 0; - - for (i = 0; i < cItem; i++) - { - bytesNeeded += items[i].size; - structSize += items[i].minSize; - } - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded))) - { - BYTE *nextData; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - if (startingPointer) - nextData = (BYTE *)startingPointer; - else - nextData = (BYTE *)pvStructInfo + structSize; - memset(pvStructInfo, 0, structSize); - ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, - pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData); - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -/* tag: - * The expected tag of the entire encoded array (usually a variant - * of ASN_SETOF or ASN_SEQUENCEOF.) - * decodeFunc: - * used to decode each item in the array - * itemSize: - * is the minimum size of each decoded item - * hasPointer: - * indicates whether each item has a dynamic pointer - * pointerOffset: - * indicates the offset within itemSize at which the pointer exists - */ -struct AsnArrayDescriptor -{ - BYTE tag; - CryptDecodeObjectExFunc decodeFunc; - DWORD itemSize; - BOOL hasPointer; - DWORD pointerOffset; -}; - -struct AsnArrayItemSize -{ - DWORD encodedLen; - DWORD size; -}; - -/* Decodes an array of like types into a struct GenericArray. - * The layout and decoding of the array are described by a struct - * AsnArrayDescriptor. - */ -static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, - const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, - void *startingPointer) -{ - BOOL ret = TRUE; - - TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc, pbEncoded, - cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, - startingPointer); - - if (pbEncoded[0] == arrayDesc->tag) - { - DWORD dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - DWORD bytesNeeded, cItems = 0; - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - /* There can be arbitrarily many items, but there is often only one. - */ - struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize; - - bytesNeeded = sizeof(struct GenericArray); - if (dataLen) - { - const BYTE *ptr; - - for (ptr = pbEncoded + 1 + lenBytes; ret && - ptr - pbEncoded - 1 - lenBytes < dataLen; ) - { - DWORD itemLenBytes, itemDataLen, size; - - itemLenBytes = GET_LEN_BYTES(ptr[1]); - /* Each item decoded may not tolerate extraneous bytes, so - * get the length of the next element and pass it directly. - */ - ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), - &itemDataLen); - if (ret) - ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr, - 1 + itemLenBytes + itemDataLen, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, - &size); - if (ret) - { - DWORD nextLen; - - cItems++; - if (itemSizes != &itemSize) - itemSizes = CryptMemRealloc(itemSizes, - cItems * sizeof(struct AsnArrayItemSize)); - else - { - itemSizes = - CryptMemAlloc( - cItems * sizeof(struct AsnArrayItemSize)); - memcpy(itemSizes, &itemSize, sizeof(itemSize)); - } - if (itemSizes) - { - itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes - + itemDataLen; - itemSizes[cItems - 1].size = size; - bytesNeeded += size; - ret = CRYPT_GetLen(ptr, - cbEncoded - (ptr - pbEncoded), &nextLen); - if (ret) - ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]); - } - else - ret = FALSE; - } - } - } - if (ret) - { - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded))) - { - DWORD i; - BYTE *nextData; - const BYTE *ptr; - struct GenericArray *array; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - array = (struct GenericArray *)pvStructInfo; - array->cItems = cItems; - if (startingPointer) - array->rgItems = startingPointer; - else - array->rgItems = (BYTE *)array + - sizeof(struct GenericArray); - nextData = (BYTE *)array->rgItems + - array->cItems * arrayDesc->itemSize; - for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && - i < cItems && ptr - pbEncoded - 1 - lenBytes < - dataLen; i++) - { - if (arrayDesc->hasPointer) - *(BYTE **)(array->rgItems + i * arrayDesc->itemSize - + arrayDesc->pointerOffset) = nextData; - ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr, - itemSizes[i].encodedLen, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, - array->rgItems + i * arrayDesc->itemSize, - &itemSizes[i].size); - if (ret) - { - DWORD nextLen; - - nextData += itemSizes[i].size - arrayDesc->itemSize; - ret = CRYPT_GetLen(ptr, - cbEncoded - (ptr - pbEncoded), &nextLen); - if (ret) - ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]); - } - } - } - } - if (itemSizes != &itemSize) - CryptMemFree(itemSizes); - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - return ret; -} - -/* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by - * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set - * to CRYPT_E_ASN1_CORRUPT. - * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData - * set! - */ -static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - DWORD dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB); - - if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) - bytesNeeded += 1 + lenBytes + dataLen; - - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - CRYPT_DER_BLOB *blob; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - blob = (CRYPT_DER_BLOB *)pvStructInfo; - blob->cbData = 1 + lenBytes + dataLen; - if (blob->cbData) - { - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - blob->pbData = (BYTE *)pbEncoded; - else - { - assert(blob->pbData); - memcpy(blob->pbData, pbEncoded, blob->cbData); - } - } - else - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - } - } - return ret; -} - -/* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */ -static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in- - * place. - */ - ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType, - pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara, - pvStructInfo, pcbStructInfo); - if (ret && pvStructInfo) - { - CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo; - - if (blob->cbData) - { - DWORD i; - BYTE temp; - - for (i = 0; i < blob->cbData / 2; i++) - { - temp = blob->pbData[i]; - blob->pbData[i] = blob->pbData[blob->cbData - i - 1]; - blob->pbData[blob->cbData - i - 1] = temp; - } - } - } - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned), - CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, - offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 }, - { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO, - SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId, - sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, - offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 }, - { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature), - CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, - offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 }, - }; - - if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG) - items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -/* Internal function */ -static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - DWORD dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, - pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo); - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - struct AsnDecodeSequenceItem items[] = { - { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore), - CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, - { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter), - CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, - }; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - return ret; -} - -/* Internal function */ -static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - DWORD dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo); - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion), - CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 }, - { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber), - CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, - TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 }, - { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm), - CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), - FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 }, - { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob, - sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, - Issuer.pbData) }, - { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore), - CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, - FALSE, 0 }, - { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob, - sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, - Subject.pbData) }, - { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo), - CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO), - FALSE, TRUE, offsetof(CERT_INFO, - SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 }, - { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, - offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 }, - { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, - offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 }, - { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension), - CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, - offsetof(CERT_INFO, rgExtension), 0 }, - }; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - struct AsnDecodeSequenceItem items[] = { - { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber), - CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, - offsetof(CRL_ENTRY, SerialNumber.pbData), 0 }, - { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime, - sizeof(FILETIME), FALSE, FALSE, 0 }, - { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension), - CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE, - offsetof(CRL_ENTRY, rgExtension), 0 }, - }; - PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo; - - TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry, - *pcbStructInfo); - - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL); - return ret; -} - -/* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has - * been set prior to calling. - */ -static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE, - offsetof(CRL_ENTRY, SerialNumber.pbData) }; - struct GenericArray *entries = (struct GenericArray *)pvStructInfo; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, - entries ? entries->rgItems : NULL); - TRACE("Returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CRL_INFO, dwVersion), - CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 }, - { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm), - CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), - FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 }, - { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob, - sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO, - Issuer.pbData) }, - { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime, - sizeof(FILETIME), FALSE, FALSE, 0 }, - { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime, - sizeof(FILETIME), TRUE, FALSE, 0 }, - { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry), - CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE, - offsetof(CRL_INFO, rgCRLEntry), 0 }, - /* Note that the extensions are ignored by MS, so I'll ignore them too - */ - { 0, offsetof(CRL_INFO, cExtension), NULL, - sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 }, - }; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - - TRACE("Returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -/* Differences between this and CRYPT_AsnDecodeOid: - * - pvStructInfo is a LPSTR *, not an LPSTR - * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte - * count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this - * to - */ -static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags, - pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo); - if (ret || GetLastError() == ERROR_MORE_DATA) - *pcbStructInfo += sizeof(LPSTR); - if (ret && pvStructInfo) - TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo)); - return ret; -} - -/* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set - * ahead of time! - */ -static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - struct AsnDecodeSequenceItem items[] = { - { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId), - CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, - offsetof(CERT_EXTENSION, pszObjId), 0 }, - { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool, - sizeof(BOOL), TRUE, FALSE, 0, 0 }, - { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value), - CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, - offsetof(CERT_EXTENSION, Value.pbData) }, - }; - BOOL ret = TRUE; - PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo; - - TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext, - *pcbStructInfo); - - if (ext) - TRACE("ext->pszObjId is %p\n", ext->pszObjId); - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, - ext, pcbStructInfo, ext ? ext->pszObjId : NULL); - if (ext) - TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId, - debugstr_a(ext->pszObjId)); - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, - offsetof(CERT_EXTENSION, pszObjId) }; - PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - __TRY - { - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo); - if (ret && pvStructInfo) - { - ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, - pcbStructInfo, *pcbStructInfo); - if (ret) - { - CERT_EXTENSIONS *exts; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - exts = (CERT_EXTENSIONS *)pvStructInfo; - exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts + - sizeof(CERT_EXTENSIONS)); - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - pcbStructInfo); - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -/* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */ -static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded, - DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId) -{ - BOOL ret = TRUE; - - TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId, - *pcbObjId); - - __TRY - { - if (pbEncoded[0] == ASN_OBJECTIDENTIFIER) - { - DWORD dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - DWORD bytesNeeded; - - if (dataLen) - { - /* The largest possible string for the first two components - * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough. - */ - char firstTwo[6]; - const BYTE *ptr; - - snprintf(firstTwo, sizeof(firstTwo), "%d.%d", - pbEncoded[1 + lenBytes] / 40, - pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) - * 40); - bytesNeeded = strlen(firstTwo) + 1; - for (ptr = pbEncoded + 2 + lenBytes; ret && - ptr - pbEncoded - 1 - lenBytes < dataLen; ) - { - /* large enough for ".4000000" */ - char str[9]; - int val = 0; - - while (ptr - pbEncoded - 1 - lenBytes < dataLen && - (*ptr & 0x80)) - { - val <<= 7; - val |= *ptr & 0x7f; - ptr++; - } - if (ptr - pbEncoded - 1 - lenBytes >= dataLen || - (*ptr & 0x80)) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - val <<= 7; - val |= *ptr++; - snprintf(str, sizeof(str), ".%d", val); - bytesNeeded += strlen(str); - } - } - if (!pszObjId) - *pcbObjId = bytesNeeded; - else if (*pcbObjId < bytesNeeded) - { - *pcbObjId = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - *pszObjId = 0; - sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40, - pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / - 40) * 40); - pszObjId += strlen(pszObjId); - for (ptr = pbEncoded + 2 + lenBytes; ret && - ptr - pbEncoded - 1 - lenBytes < dataLen; ) - { - int val = 0; - - while (ptr - pbEncoded - 1 - lenBytes < dataLen && - (*ptr & 0x80)) - { - val <<= 7; - val |= *ptr & 0x7f; - ptr++; - } - val <<= 7; - val |= *ptr++; - sprintf(pszObjId, ".%d", val); - pszObjId += strlen(pszObjId); - } - } - } - else - bytesNeeded = 0; - *pcbObjId = bytesNeeded; - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -/* Warning: this assumes the address of value->Value.pbData is already set, in - * order to avoid overwriting memory. (In some cases, it may change it, if it - * doesn't copy anything to memory.) Be sure to set it correctly! - */ -static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - __TRY - { - DWORD dataLen; - CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - switch (pbEncoded[0]) - { - case ASN_NUMERICSTRING: - case ASN_PRINTABLESTRING: - case ASN_IA5STRING: - break; - default: - FIXME("Unimplemented string type %02x\n", pbEncoded[0]); - SetLastError(OSS_UNIMPLEMENTED); - ret = FALSE; - } - if (ret) - { - DWORD bytesNeeded = sizeof(CERT_NAME_VALUE); - - switch (pbEncoded[0]) - { - case ASN_NUMERICSTRING: - case ASN_PRINTABLESTRING: - case ASN_IA5STRING: - if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) - bytesNeeded += dataLen; - break; - } - if (!value) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - *pcbStructInfo = bytesNeeded; - switch (pbEncoded[0]) - { - case ASN_NUMERICSTRING: - value->dwValueType = CERT_RDN_NUMERIC_STRING; - break; - case ASN_PRINTABLESTRING: - value->dwValueType = CERT_RDN_PRINTABLE_STRING; - break; - case ASN_IA5STRING: - value->dwValueType = CERT_RDN_IA5_STRING; - break; - } - if (dataLen) - { - switch (pbEncoded[0]) - { - case ASN_NUMERICSTRING: - case ASN_PRINTABLESTRING: - case ASN_IA5STRING: - value->Value.cbData = dataLen; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - value->Value.pbData = (BYTE *)pbEncoded + 1 + - lenBytes; - else - { - assert(value->Value.pbData); - memcpy(value->Value.pbData, - pbEncoded + 1 + lenBytes, dataLen); - } - break; - } - } - else - { - value->Value.cbData = 0; - value->Value.pbData = NULL; - } - } - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId), - CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, - offsetof(CERT_RDN_ATTR, pszObjId), 0 }, - { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue, - sizeof(CERT_NAME_VALUE), FALSE, TRUE, offsetof(CERT_RDN_ATTR, - Value.pbData), 0 }, - }; - CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo; - - if (attr) - TRACE("attr->pszObjId is %p\n", attr->pszObjId); - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, - attr, pcbStructInfo, attr ? attr->pszObjId : NULL); - if (attr) - { - TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId, - debugstr_a(attr->pszObjId)); - TRACE("attr->dwValueType is %ld\n", attr->dwValueType); - } - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - __TRY - { - struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, - CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE, - offsetof(CERT_RDN_ATTR, pszObjId) }; - PCERT_RDN rdn = (PCERT_RDN)pvStructInfo; - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - __TRY - { - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE, - offsetof(CERT_RDN, rgRDNAttr) }; - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB); - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) - bytesNeeded += cbEncoded; - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - SetLastError(ERROR_MORE_DATA); - *pcbStructInfo = bytesNeeded; - ret = FALSE; - } - else - { - PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo; - - *pcbStructInfo = bytesNeeded; - blob->cbData = cbEncoded; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - blob->pbData = (LPBYTE)pbEncoded; - else - { - assert(blob->pbData); - memcpy(blob->pbData, pbEncoded, blob->cbData); - } - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - CRYPT_ALGORITHM_IDENTIFIER *algo = - (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo; - BOOL ret = TRUE; - struct AsnDecodeSequenceItem items[] = { - { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), - CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, - offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 }, - { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters), - CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, - offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 }, - }; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL); - if (ret && pvStructInfo) - { - TRACE("pszObjId is %p (%s)\n", algo->pszObjId, - debugstr_a(algo->pszObjId)); - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - struct AsnDecodeSequenceItem items[] = { - { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm), - CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), - FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO, - Algorithm.pszObjId) }, - { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, - offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) }, - }; - PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, info ? - info->Algorithm.Parameters.pbData : NULL); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - __TRY - { - DWORD bytesNeeded; - - if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) - { - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - PCERT_PUBLIC_KEY_INFO info; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; - info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo + - sizeof(CERT_PUBLIC_KEY_INFO); - ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (cbEncoded < 3) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - return FALSE; - } - if (GET_LEN_BYTES(pbEncoded[1]) > 1) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - return FALSE; - } - if (pbEncoded[1] > 1) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - return FALSE; - } - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(BOOL); - ret = TRUE; - } - else if (*pcbStructInfo < sizeof(BOOL)) - { - *pcbStructInfo = sizeof(BOOL); - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE; - ret = TRUE; - } - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo; - DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY); - BOOL ret; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - if (cbEncoded < 2) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - return FALSE; - } - if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT) - { - SetLastError(CRYPT_E_ASN1_BADTAG); - return FALSE; - } - lenBytes = GET_LEN_BYTES(pbEncoded[1]); - if (1 + lenBytes > cbEncoded) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - return FALSE; - } - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - switch (pbEncoded[0] & ASN_TYPE_MASK) - { - case 1: /* rfc822Name */ - case 2: /* dNSName */ - case 6: /* uniformResourceIdentifier */ - bytesNeeded += (dataLen + 1) * sizeof(WCHAR); - break; - case 7: /* iPAddress */ - bytesNeeded += dataLen; - break; - case 8: /* registeredID */ - /* FIXME: decode as OID */ - case 0: /* otherName */ - case 4: /* directoryName */ - FIXME("stub\n"); - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - break; - case 3: /* x400Address, unimplemented */ - case 5: /* ediPartyName, unimplemented */ - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - break; - default: - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - if (ret) - { - if (!entry) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - *pcbStructInfo = bytesNeeded; - /* MS used values one greater than the asn1 ones.. sigh */ - entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1; - switch (pbEncoded[0] & ASN_TYPE_MASK) - { - case 1: /* rfc822Name */ - case 2: /* dNSName */ - case 6: /* uniformResourceIdentifier */ - { - DWORD i; - - for (i = 0; i < dataLen; i++) - entry->u.pwszURL[i] = - (WCHAR)pbEncoded[1 + lenBytes + i]; - entry->u.pwszURL[i] = 0; - TRACE("URL is %p (%s)\n", entry->u.pwszURL, - debugstr_w(entry->u.pwszURL)); - break; - } - case 7: /* iPAddress */ - /* The next data pointer is in the pwszURL spot, that is, - * the first 4 bytes. Need to move it to the next spot. - */ - entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL; - entry->u.IPAddress.cbData = dataLen; - memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes, - dataLen); - break; - } - } - } - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, - offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; - PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - if (info) - TRACE("info->rgAltEntry is %p\n", info->rgAltEntry); - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, - offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -struct PATH_LEN_CONSTRAINT -{ - BOOL fPathLenConstraint; - DWORD dwPathLenConstraint; -}; - -static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pvStructInfo, *pcbStructInfo); - - if (cbEncoded) - { - if (pbEncoded[0] == ASN_INTEGER) - { - DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT); - - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - SetLastError(ERROR_MORE_DATA); - *pcbStructInfo = bytesNeeded; - ret = FALSE; - } - else - { - struct PATH_LEN_CONSTRAINT *constraint = - (struct PATH_LEN_CONSTRAINT *)pvStructInfo; - DWORD size = sizeof(constraint->dwPathLenConstraint); - - ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, - pbEncoded, cbEncoded, 0, NULL, - &constraint->dwPathLenConstraint, &size); - if (ret) - constraint->fPathLenConstraint = TRUE; - TRACE("got an int, dwPathLenConstraint is %ld\n", - constraint->dwPathLenConstraint); - } - } - else - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - } - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE, - offsetof(CERT_NAME_BLOB, pbData) }; - struct GenericArray *entries = (struct GenericArray *)pvStructInfo; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, - entries ? entries->rgItems : NULL); - TRACE("Returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, - offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 }, - { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO, - fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, - sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, - { ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO, - cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints, - sizeof(struct GenericArray), TRUE, TRUE, - offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 }, - }; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { ASN_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), - CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 }, - { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, - fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, - sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, - }; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -#define RSA1_MAGIC 0x31415352 - -struct DECODED_RSA_PUB_KEY -{ - DWORD pubexp; - CRYPT_INTEGER_BLOB modulus; -}; - -static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - __TRY - { - struct AsnDecodeSequenceItem items[] = { - { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus), - CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), - FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData), - 0 }, - { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp), - CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 }, - }; - struct DECODED_RSA_PUB_KEY *decodedKey = NULL; - DWORD size = 0; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, - CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL); - if (ret) - { - DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + - decodedKey->modulus.cbData; - - if (!pvStructInfo) - { - *pcbStructInfo = bytesNeeded; - ret = TRUE; - } - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - BLOBHEADER *hdr; - RSAPUBKEY *rsaPubKey; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - hdr = (BLOBHEADER *)pvStructInfo; - hdr->bType = PUBLICKEYBLOB; - hdr->bVersion = CUR_BLOB_VERSION; - hdr->reserved = 0; - hdr->aiKeyAlg = CALG_RSA_KEYX; - rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo + - sizeof(BLOBHEADER)); - rsaPubKey->magic = RSA1_MAGIC; - rsaPubKey->pubexp = decodedKey->pubexp; - rsaPubKey->bitlen = decodedKey->modulus.cbData * 8; - memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) + - sizeof(RSAPUBKEY), decodedKey->modulus.pbData, - decodedKey->modulus.cbData); - } - LocalFree(decodedKey); - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - DWORD bytesNeeded, dataLen; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - bytesNeeded = sizeof(CRYPT_DATA_BLOB); - else - bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB); - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - SetLastError(ERROR_MORE_DATA); - *pcbStructInfo = bytesNeeded; - ret = FALSE; - } - else - { - CRYPT_DATA_BLOB *blob; - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - blob = (CRYPT_DATA_BLOB *)pvStructInfo; - blob->cbData = dataLen; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes; - else - { - assert(blob->pbData); - if (blob->cbData) - memcpy(blob->pbData, pbEncoded + 1 + lenBytes, - blob->cbData); - } - } - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - DWORD bytesNeeded; - - if (!cbEncoded) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else if (pbEncoded[0] != ASN_OCTETSTRING) - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) - { - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - CRYPT_DATA_BLOB *blob; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - blob = (CRYPT_DATA_BLOB *)pvStructInfo; - blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB); - ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - if (pbEncoded[0] == ASN_BITSTRING) - { - DWORD bytesNeeded, dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - bytesNeeded = sizeof(CRYPT_BIT_BLOB); - else - bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB); - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - CRYPT_BIT_BLOB *blob; - - blob = (CRYPT_BIT_BLOB *)pvStructInfo; - blob->cbData = dataLen - 1; - blob->cUnusedBits = *(pbEncoded + 1 + - GET_LEN_BYTES(pbEncoded[1])); - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - { - blob->pbData = (BYTE *)pbEncoded + 2 + - GET_LEN_BYTES(pbEncoded[1]); - } - else - { - assert(blob->pbData); - if (blob->cbData) - { - BYTE mask = 0xff << blob->cUnusedBits; - - memcpy(blob->pbData, pbEncoded + 2 + - GET_LEN_BYTES(pbEncoded[1]), blob->cbData); - blob->pbData[blob->cbData - 1] &= mask; - } - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo); - - __TRY - { - DWORD bytesNeeded; - - if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) - { - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - CRYPT_BIT_BLOB *blob; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - blob = (CRYPT_BIT_BLOB *)pvStructInfo; - blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB); - ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - TRACE("returning %d (%08lx)\n", ret, GetLastError()); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(int); - return TRUE; - } - __TRY - { - BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)]; - CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; - DWORD size = sizeof(buf); - - blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB); - ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, - X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size); - if (ret) - { - if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, sizeof(int)))) - { - int val, i; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - if (blob->pbData[blob->cbData - 1] & 0x80) - { - /* initialize to a negative value to sign-extend */ - val = -1; - } - else - val = 0; - for (i = 0; i < blob->cbData; i++) - { - val <<= 8; - val |= blob->pbData[blob->cbData - i - 1]; - } - memcpy(pvStructInfo, &val, sizeof(int)); - } - } - else if (GetLastError() == ERROR_MORE_DATA) - SetLastError(CRYPT_E_ASN1_LARGE); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (pbEncoded[0] == ASN_INTEGER) - { - DWORD bytesNeeded, dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB); - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; - - blob->cbData = dataLen; - assert(blob->pbData); - if (blob->cbData) - { - DWORD i; - - for (i = 0; i < blob->cbData; i++) - { - blob->pbData[i] = *(pbEncoded + 1 + lenBytes + - dataLen - i - 1); - } - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - __TRY - { - DWORD bytesNeeded; - - if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) - { - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - CRYPT_INTEGER_BLOB *blob; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; - blob->pbData = (BYTE *)pvStructInfo + - sizeof(CRYPT_INTEGER_BLOB); - ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( - DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (pbEncoded[0] == ASN_INTEGER) - { - DWORD bytesNeeded, dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB); - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; - - blob->cbData = dataLen; - assert(blob->pbData); - /* remove leading zero byte if it exists */ - if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0) - { - blob->cbData--; - blob->pbData++; - } - if (blob->cbData) - { - DWORD i; - - for (i = 0; i < blob->cbData; i++) - { - blob->pbData[i] = *(pbEncoded + 1 + lenBytes + - dataLen - i - 1); - } - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - __TRY - { - DWORD bytesNeeded; - - if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) - { - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - CRYPT_INTEGER_BLOB *blob; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; - blob->pbData = (BYTE *)pvStructInfo + - sizeof(CRYPT_INTEGER_BLOB); - ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(int); - return TRUE; - } - __TRY - { - if (pbEncoded[0] == ASN_ENUMERATED) - { - unsigned int val = 0, i; - - if (cbEncoded <= 1) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else if (pbEncoded[1] == 0) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - /* A little strange looking, but we have to accept a sign byte: - * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also, - * assuming a small length is okay here, it has to be in short - * form. - */ - if (pbEncoded[1] > sizeof(unsigned int) + 1) - { - SetLastError(CRYPT_E_ASN1_LARGE); - return FALSE; - } - for (i = 0; i < pbEncoded[1]; i++) - { - val <<= 8; - val |= pbEncoded[2 + i]; - } - if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, sizeof(unsigned int)))) - { - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - memcpy(pvStructInfo, &val, sizeof(unsigned int)); - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -/* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE - * if it fails. - */ -#define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \ - do { \ - BYTE i; \ - \ - (word) = 0; \ - for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \ - { \ - if (!isdigit(*(pbEncoded))) \ - { \ - SetLastError(CRYPT_E_ASN1_CORRUPT); \ - ret = FALSE; \ - } \ - else \ - { \ - (word) *= 10; \ - (word) += *(pbEncoded)++ - '0'; \ - } \ - } \ - } while (0) - -static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len, - SYSTEMTIME *sysTime) -{ - BOOL ret; - - __TRY - { - ret = TRUE; - if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-')) - { - WORD hours, minutes = 0; - BYTE sign = *pbEncoded++; - - len--; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours); - if (ret && hours >= 24) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else if (len >= 2) - { - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes); - if (ret && minutes >= 60) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - } - if (ret) - { - if (sign == '+') - { - sysTime->wHour += hours; - sysTime->wMinute += minutes; - } - else - { - if (hours > sysTime->wHour) - { - sysTime->wDay--; - sysTime->wHour = 24 - (hours - sysTime->wHour); - } - else - sysTime->wHour -= hours; - if (minutes > sysTime->wMinute) - { - sysTime->wHour--; - sysTime->wMinute = 60 - (minutes - sysTime->wMinute); - } - else - sysTime->wMinute -= minutes; - } - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -#define MIN_ENCODED_TIME_LENGTH 10 - -static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(FILETIME); - return TRUE; - } - __TRY - { - ret = TRUE; - if (pbEncoded[0] == ASN_UTCTIME) - { - if (cbEncoded <= 1) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else if (pbEncoded[1] > 0x7f) - { - /* long-form date strings really can't be valid */ - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - SYSTEMTIME sysTime = { 0 }; - BYTE len = pbEncoded[1]; - - if (len < MIN_ENCODED_TIME_LENGTH) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - pbEncoded += 2; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear); - if (sysTime.wYear >= 50) - sysTime.wYear += 1900; - else - sysTime.wYear += 2000; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute); - if (ret && len > 0) - { - if (len >= 2 && isdigit(*pbEncoded) && - isdigit(*(pbEncoded + 1))) - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, - sysTime.wSecond); - else if (isdigit(*pbEncoded)) - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, - sysTime.wSecond); - if (ret) - ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, - &sysTime); - } - if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, - sizeof(FILETIME)))) - { - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - ret = SystemTimeToFileTime(&sysTime, - (FILETIME *)pvStructInfo); - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(FILETIME); - return TRUE; - } - __TRY - { - ret = TRUE; - if (pbEncoded[0] == ASN_GENERALTIME) - { - if (cbEncoded <= 1) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else if (pbEncoded[1] > 0x7f) - { - /* long-form date strings really can't be valid */ - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - BYTE len = pbEncoded[1]; - - if (len < MIN_ENCODED_TIME_LENGTH) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - SYSTEMTIME sysTime = { 0 }; - - pbEncoded += 2; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); - if (ret && len > 0) - { - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, - sysTime.wMinute); - if (ret && len > 0) - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, - sysTime.wSecond); - if (ret && len > 0 && (*pbEncoded == '.' || - *pbEncoded == ',')) - { - BYTE digits; - - pbEncoded++; - len--; - /* workaround macro weirdness */ - digits = min(len, 3); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits, - sysTime.wMilliseconds); - } - if (ret) - ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, - &sysTime); - } - if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, - sizeof(FILETIME)))) - { - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - ret = SystemTimeToFileTime(&sysTime, - (FILETIME *)pvStructInfo); - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - __TRY - { - if (pbEncoded[0] == ASN_UTCTIME) - ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType, - pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, - pcbStructInfo); - else if (pbEncoded[0] == ASN_GENERALTIME) - ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo); - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret = TRUE; - - __TRY - { - if (pbEncoded[0] == ASN_SEQUENCEOF) - { - DWORD bytesNeeded, dataLen, remainingLen, cValue; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes; - const BYTE *ptr; - - lenBytes = GET_LEN_BYTES(pbEncoded[1]); - bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY); - cValue = 0; - ptr = pbEncoded + 1 + lenBytes; - remainingLen = dataLen; - while (ret && remainingLen) - { - DWORD nextLen; - - ret = CRYPT_GetLen(ptr, remainingLen, &nextLen); - if (ret) - { - DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]); - - remainingLen -= 1 + nextLenBytes + nextLen; - ptr += 1 + nextLenBytes + nextLen; - bytesNeeded += sizeof(CRYPT_DER_BLOB); - if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) - bytesNeeded += 1 + nextLenBytes + nextLen; - cValue++; - } - } - if (ret) - { - CRYPT_SEQUENCE_OF_ANY *seq; - BYTE *nextPtr; - DWORD i; - - if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) - { - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo; - seq->cValue = cValue; - seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq + - sizeof(*seq)); - nextPtr = (BYTE *)seq->rgValue + - cValue * sizeof(CRYPT_DER_BLOB); - ptr = pbEncoded + 1 + lenBytes; - remainingLen = dataLen; - i = 0; - while (ret && remainingLen) - { - DWORD nextLen; - - ret = CRYPT_GetLen(ptr, remainingLen, &nextLen); - if (ret) - { - DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]); - - seq->rgValue[i].cbData = 1 + nextLenBytes + - nextLen; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - seq->rgValue[i].pbData = (BYTE *)ptr; - else - { - seq->rgValue[i].pbData = nextPtr; - memcpy(nextPtr, ptr, 1 + nextLenBytes + - nextLen); - nextPtr += 1 + nextLenBytes + nextLen; - } - remainingLen -= 1 + nextLenBytes + nextLen; - ptr += 1 + nextLenBytes + nextLen; - i++; - } - } - } - } - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - return FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - struct AsnDecodeSequenceItem items[] = { - { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT, - DistPointName), CRYPT_AsnDecodeAltNameInternal, - sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT, - DistPointName.u.FullName.rgAltEntry), 0 }, - { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, - offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 }, - { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer), - CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE, - offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 }, - }; - BOOL ret; - - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, - dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE, - offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) }; - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - BOOL ret; - - TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - - __TRY - { - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), TRUE, 0 }; - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY - return ret; -} - -BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, - const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) -{ - static HCRYPTOIDFUNCSET set = NULL; - BOOL ret = FALSE; - CryptDecodeObjectExFunc decodeFunc = NULL; - HCRYPTOIDFUNCADDR hFunc = NULL; - - TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n", - dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded, - cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); - - if (!pvStructInfo && !pcbStructInfo) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING - && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - if (!cbEncoded) - { - SetLastError(CRYPT_E_ASN1_EOD); - return FALSE; - } - if (cbEncoded > MAX_ENCODED_LEN) - { - SetLastError(CRYPT_E_ASN1_LARGE); - return FALSE; - } - - SetLastError(NOERROR); - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo) - *(BYTE **)pvStructInfo = NULL; - if (!HIWORD(lpszStructType)) - { - switch (LOWORD(lpszStructType)) - { - case (WORD)X509_CERT: - decodeFunc = CRYPT_AsnDecodeCert; - break; - case (WORD)X509_CERT_TO_BE_SIGNED: - decodeFunc = CRYPT_AsnDecodeCertInfo; - break; - case (WORD)X509_CERT_CRL_TO_BE_SIGNED: - decodeFunc = CRYPT_AsnDecodeCRLInfo; - break; - case (WORD)X509_EXTENSIONS: - decodeFunc = CRYPT_AsnDecodeExtensions; - break; - case (WORD)X509_NAME: - decodeFunc = CRYPT_AsnDecodeName; - break; - case (WORD)X509_PUBLIC_KEY_INFO: - decodeFunc = CRYPT_AsnDecodePubKeyInfo; - break; - case (WORD)X509_ALTERNATE_NAME: - decodeFunc = CRYPT_AsnDecodeAltName; - break; - case (WORD)X509_BASIC_CONSTRAINTS: - decodeFunc = CRYPT_AsnDecodeBasicConstraints; - break; - case (WORD)X509_BASIC_CONSTRAINTS2: - decodeFunc = CRYPT_AsnDecodeBasicConstraints2; - break; - case (WORD)RSA_CSP_PUBLICKEYBLOB: - decodeFunc = CRYPT_AsnDecodeRsaPubKey; - break; - case (WORD)X509_OCTET_STRING: - decodeFunc = CRYPT_AsnDecodeOctets; - break; - case (WORD)X509_BITS: - case (WORD)X509_KEY_USAGE: - decodeFunc = CRYPT_AsnDecodeBits; - break; - case (WORD)X509_INTEGER: - decodeFunc = CRYPT_AsnDecodeInt; - break; - case (WORD)X509_MULTI_BYTE_INTEGER: - decodeFunc = CRYPT_AsnDecodeInteger; - break; - case (WORD)X509_MULTI_BYTE_UINT: - decodeFunc = CRYPT_AsnDecodeUnsignedInteger; - break; - case (WORD)X509_ENUMERATED: - decodeFunc = CRYPT_AsnDecodeEnumerated; - break; - case (WORD)X509_CHOICE_OF_TIME: - decodeFunc = CRYPT_AsnDecodeChoiceOfTime; - break; - case (WORD)X509_SEQUENCE_OF_ANY: - decodeFunc = CRYPT_AsnDecodeSequenceOfAny; - break; - case (WORD)PKCS_UTC_TIME: - decodeFunc = CRYPT_AsnDecodeUtcTime; - break; - case (WORD)X509_CRL_DIST_POINTS: - decodeFunc = CRYPT_AsnDecodeCRLDistPoints; - break; - case (WORD)X509_ENHANCED_KEY_USAGE: - decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; - break; - default: - FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); - } - } - else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) - decodeFunc = CRYPT_AsnDecodeExtensions; - else if (!strcmp(lpszStructType, szOID_RSA_signingTime)) - decodeFunc = CRYPT_AsnDecodeUtcTime; - else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) - decodeFunc = CRYPT_AsnDecodeEnumerated; - else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) - decodeFunc = CRYPT_AsnDecodeBits; - else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER)) - decodeFunc = CRYPT_AsnDecodeOctets; - else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS)) - decodeFunc = CRYPT_AsnDecodeBasicConstraints; - else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) - decodeFunc = CRYPT_AsnDecodeBasicConstraints2; - else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) - decodeFunc = CRYPT_AsnDecodeAltName; - else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2)) - decodeFunc = CRYPT_AsnDecodeAltName; - else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION)) - decodeFunc = CRYPT_AsnDecodeAltName; - else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME)) - decodeFunc = CRYPT_AsnDecodeAltName; - else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) - decodeFunc = CRYPT_AsnDecodeAltName; - else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) - decodeFunc = CRYPT_AsnDecodeCRLDistPoints; - else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) - decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; - else - TRACE("OID %s not found or unimplemented, looking for DLL\n", - debugstr_a(lpszStructType)); - if (!decodeFunc) - { - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, - (void **)&decodeFunc, &hFunc); - } - if (decodeFunc) - ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded, - cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); - else - SetLastError(ERROR_FILE_NOT_FOUND); - if (hFunc) - CryptFreeOIDFunctionAddress(hFunc, 0); - return ret; -} - BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo) { @@ -5448,13 +2500,14 @@ static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv, { BOOL ret; HCRYPTKEY key; + static CHAR oid[] = szOID_RSA_RSA; TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo, pInfo, pcbInfo); if (!pszPublicKeyObjId) - pszPublicKeyObjId = szOID_RSA_RSA; + pszPublicKeyObjId = oid; if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key))) { DWORD keySize = 0; diff --git a/reactos/dll/win32/crypt32/main.c b/reactos/dll/win32/crypt32/main.c index 930df22dbb2..f3e8a38d490 100644 --- a/reactos/dll/win32/crypt32/main.c +++ b/reactos/dll/win32/crypt32/main.c @@ -14,7 +14,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" diff --git a/reactos/dll/win32/crypt32/oid.c b/reactos/dll/win32/crypt32/oid.c index 5af42096ad9..bbe4225529f 100644 --- a/reactos/dll/win32/crypt32/oid.c +++ b/reactos/dll/win32/crypt32/oid.c @@ -14,7 +14,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include @@ -23,7 +23,6 @@ #include "winbase.h" #include "wincrypt.h" #include "winreg.h" -#include "wingdi.h" #include "winuser.h" #include "wine/debug.h" #include "wine/list.h" @@ -51,8 +50,8 @@ void crypt_oid_free(void) free_oid_info(); } -CRITICAL_SECTION funcSetCS; -struct list funcSets; +static CRITICAL_SECTION funcSetCS; +static struct list funcSets; struct OIDFunctionSet { @@ -454,7 +453,7 @@ BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName, */ if (!pszFuncName || !pszOID) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return FALSE; } @@ -579,8 +578,8 @@ BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName, return rc ? FALSE : TRUE; } -CRITICAL_SECTION oidInfoCS; -struct list oidInfo; +static CRITICAL_SECTION oidInfoCS; +static struct list oidInfo; static const WCHAR tripledes[] = { '3','d','e','s',0 }; static const WCHAR cms3deswrap[] = { 'C','M','S','3','D','E','S','w','r','a', @@ -678,7 +677,7 @@ static const CRYPT_DATA_BLOB printableStringBlob = { sizeof(printableString), static const CRYPT_DATA_BLOB domainCompTypesBlob = { sizeof(domainCompTypes), (LPBYTE)domainCompTypes }; -struct OIDInfoConstructor { +static const struct OIDInfoConstructor { DWORD dwGroupId; LPCSTR pszOID; UINT Algid; @@ -952,7 +951,7 @@ static void init_oid_info(HINSTANCE hinst) } else { - int len = LoadStringW(hinst, (UINT)oidInfoConstructors[i].pwszName, + int len = LoadStringW(hinst, (UINT_PTR)oidInfoConstructors[i].pwszName, NULL, 0); if (len) @@ -969,7 +968,7 @@ static void init_oid_info(HINSTANCE hinst) (LPWSTR)((LPBYTE)info + sizeof(struct OIDInfo)); info->info.dwGroupId = oidInfoConstructors[i].dwGroupId; info->info.u.Algid = oidInfoConstructors[i].Algid; - LoadStringW(hinst, (UINT)oidInfoConstructors[i].pwszName, + LoadStringW(hinst, (UINT_PTR)oidInfoConstructors[i].pwszName, (LPWSTR)info->info.pwszName, len + 1); if (oidInfoConstructors[i].blob) { diff --git a/reactos/dll/win32/crypt32/proplist.c b/reactos/dll/win32/crypt32/proplist.c index ec9e242c0ec..b6bd7d20906 100644 --- a/reactos/dll/win32/crypt32/proplist.c +++ b/reactos/dll/win32/crypt32/proplist.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include @@ -132,7 +132,6 @@ BOOL ContextPropertyList_SetProperty(PCONTEXT_PROPERTY_LIST list, DWORD id, { prop->propID = id; prop->cbData = cbData; - list_init(&prop->entry); prop->pbData = data; list_add_tail(&list->properties, &prop->entry); ret = TRUE; @@ -158,6 +157,7 @@ void ContextPropertyList_RemoveProperty(PCONTEXT_PROPERTY_LIST list, DWORD id) list_remove(&prop->entry); CryptMemFree(prop->pbData); CryptMemFree(prop); + break; } } LeaveCriticalSection(&list->cs); diff --git a/reactos/dll/win32/crypt32/protectdata.c b/reactos/dll/win32/crypt32/protectdata.c index 0d5a4fa35bb..6b12f2d9751 100644 --- a/reactos/dll/win32/crypt32/protectdata.c +++ b/reactos/dll/win32/crypt32/protectdata.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ @@ -843,8 +843,6 @@ BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, HCRYPTKEY hKey; DWORD dwLength; - - TRACE("called\n"); SetLastError(ERROR_SUCCESS); @@ -863,7 +861,7 @@ BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, /* Windows appears to create an empty szDataDescr instead of maintaining * a NULL */ if (!szDataDescr) - szDataDescr = L'\0'; + szDataDescr=(WCHAR[]){'\0'}; /* get crypt context */ if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) diff --git a/reactos/dll/win32/crypt32/serialize.c b/reactos/dll/win32/crypt32/serialize.c index 900677b299b..b0765a71c98 100644 --- a/reactos/dll/win32/crypt32/serialize.c +++ b/reactos/dll/win32/crypt32/serialize.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include "windef.h" @@ -26,77 +26,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt); -/* Some typedefs that make it easier to abstract which type of context we're - * working with. - */ -typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType, - const BYTE *pbCertEncoded, DWORD cbCertEncoded); -typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore, - const void *context, DWORD dwAddDisposition, const void **ppStoreContext); -typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, - DWORD dwAddDisposition, const void **ppContext); -typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore, - const void *pPrevContext); -typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context, - DWORD dwPropID, void *pvData, DWORD *pcbData); -typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context, - DWORD dwPropID, DWORD dwFlags, const void *pvData); -typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags, - BYTE *pbElement, DWORD *pcbElement); -typedef BOOL (WINAPI *FreeContextFunc)(const void *context); -typedef BOOL (WINAPI *DeleteContextFunc)(const void *context); - -/* An abstract context (certificate, CRL, or CTL) interface */ -typedef struct _WINE_CONTEXT_INTERFACE -{ - CreateContextFunc create; - AddContextToStoreFunc addContextToStore; - AddEncodedContextToStoreFunc addEncodedToStore; - EnumContextsInStoreFunc enumContextsInStore; - GetContextPropertyFunc getProp; - SetContextPropertyFunc setProp; - SerializeElementFunc serialize; - FreeContextFunc free; - DeleteContextFunc deleteFromStore; -} WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE; - -static const WINE_CONTEXT_INTERFACE gCertInterface = { - (CreateContextFunc)CertCreateCertificateContext, - (AddContextToStoreFunc)CertAddCertificateContextToStore, - (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore, - (EnumContextsInStoreFunc)CertEnumCertificatesInStore, - (GetContextPropertyFunc)CertGetCertificateContextProperty, - (SetContextPropertyFunc)CertSetCertificateContextProperty, - (SerializeElementFunc)CertSerializeCertificateStoreElement, - (FreeContextFunc)CertFreeCertificateContext, - (DeleteContextFunc)CertDeleteCertificateFromStore, -}; - -static const WINE_CONTEXT_INTERFACE gCRLInterface = { - (CreateContextFunc)CertCreateCRLContext, - (AddContextToStoreFunc)CertAddCRLContextToStore, - (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore, - (EnumContextsInStoreFunc)CertEnumCRLsInStore, - (GetContextPropertyFunc)CertGetCRLContextProperty, - (SetContextPropertyFunc)CertSetCRLContextProperty, - (SerializeElementFunc)CertSerializeCRLStoreElement, - (FreeContextFunc)CertFreeCRLContext, - (DeleteContextFunc)CertDeleteCRLFromStore, -}; - -static const WINE_CONTEXT_INTERFACE gCTLInterface = { - (CreateContextFunc)CertCreateCTLContext, - (AddContextToStoreFunc)CertAddCTLContextToStore, - (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore, - (EnumContextsInStoreFunc)CertEnumCTLsInStore, - (GetContextPropertyFunc)CertGetCTLContextProperty, - (SetContextPropertyFunc)CertSetCTLContextProperty, - (SerializeElementFunc)CertSerializeCTLStoreElement, - (FreeContextFunc)CertFreeCTLContext, - (DeleteContextFunc)CertDeleteCTLFromStore, -}; - /* An extended certificate property in serialized form is prefixed by this * header. */ @@ -107,45 +36,29 @@ typedef struct _WINE_CERT_PROP_HEADER DWORD cb; } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER; -BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext, - DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) -{ - FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement, - pcbElement); - return FALSE; -} - -BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext, - DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) -{ - FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement, - pcbElement); - return FALSE; -} - -BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, - DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +static BOOL CRYPT_SerializeStoreElement(const void *context, + const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID, + PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BYTE *pbElement, + DWORD *pcbElement) { BOOL ret; - TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement, - pcbElement); + TRACE("(%p, %p, %08lx, %p, %p)\n", context, contextInterface, dwFlags, + pbElement, pcbElement); - if (pCertContext) + if (context) { - DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + - pCertContext->cbCertEncoded; + DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext; DWORD prop = 0; ret = TRUE; do { - prop = CertEnumCertificateContextProperties(pCertContext, prop); + prop = contextInterface->enumProps(context, prop); if (prop) { DWORD propSize = 0; - ret = CertGetCertificateContextProperty(pCertContext, - prop, NULL, &propSize); + ret = contextInterface->getProp(context, prop, NULL, &propSize); if (ret) bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize; } @@ -170,13 +83,13 @@ BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, prop = 0; do { - prop = CertEnumCertificateContextProperties(pCertContext, prop); + prop = contextInterface->enumProps(context, prop); if (prop) { DWORD propSize = 0; - ret = CertGetCertificateContextProperty(pCertContext, - prop, NULL, &propSize); + ret = contextInterface->getProp(context, prop, NULL, + &propSize); if (ret) { if (bufSize < propSize) @@ -189,8 +102,8 @@ BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, } if (buf) { - ret = CertGetCertificateContextProperty( - pCertContext, prop, buf, &propSize); + ret = contextInterface->getProp(context, prop, buf, + &propSize); if (ret) { hdr = (PWINE_CERT_PROP_HEADER)pbElement; @@ -213,11 +126,11 @@ BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, CryptMemFree(buf); hdr = (PWINE_CERT_PROP_HEADER)pbElement; - hdr->propID = CERT_CERT_PROP_ID; + hdr->propID = contextPropID; hdr->unknown = 1; - hdr->cb = pCertContext->cbCertEncoded; + hdr->cb = cbEncodedContext; memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER), - pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); + encodedContext, cbEncodedContext); } } else @@ -225,6 +138,30 @@ BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, return ret; } +BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, + DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +{ + return CRYPT_SerializeStoreElement(pCertContext, + pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, + CERT_CERT_PROP_ID, pCertInterface, dwFlags, pbElement, pcbElement); +} + +BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext, + DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +{ + return CRYPT_SerializeStoreElement(pCrlContext, + pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded, + CERT_CRL_PROP_ID, pCRLInterface, dwFlags, pbElement, pcbElement); +} + +BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext, + DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +{ + return CRYPT_SerializeStoreElement(pCtlContext, + pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded, + CERT_CTL_PROP_ID, pCRLInterface, dwFlags, pbElement, pcbElement); +} + /* Looks for the property with ID propID in the buffer buf. Returns a pointer * to its header if a valid header is found, NULL if not. Valid means the * length of thte property won't overrun buf, and the unknown field is 1. @@ -251,7 +188,7 @@ static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf, buf += sizeof(WINE_CERT_PROP_HEADER); if (size < hdr->cb) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); done = TRUE; } else if (!hdr->propID) @@ -339,16 +276,16 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, switch (type) { case CERT_STORE_CERTIFICATE_CONTEXT: - contextInterface = &gCertInterface; + contextInterface = pCertInterface; break; case CERT_STORE_CRL_CONTEXT: - contextInterface = &gCRLInterface; + contextInterface = pCRLInterface; break; case CERT_STORE_CTL_CONTEXT: - contextInterface = &gCTLInterface; + contextInterface = pCTLInterface; break; default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } if (!hdr) @@ -375,8 +312,7 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, pbElement += sizeof(WINE_CERT_PROP_HEADER); if (cbElement < hdr->cb) { - SetLastError(HRESULT_FROM_WIN32( - ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); ret = FALSE; } else if (!hdr->propID) @@ -483,16 +419,16 @@ BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore, switch (type) { case CERT_STORE_CERTIFICATE_CONTEXT: - contextInterface = &gCertInterface; + contextInterface = pCertInterface; break; case CERT_STORE_CRL_CONTEXT: - contextInterface = &gCRLInterface; + contextInterface = pCRLInterface; break; case CERT_STORE_CTL_CONTEXT: - contextInterface = &gCTLInterface; + contextInterface = pCTLInterface; break; default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); } if (contextInterface) { diff --git a/reactos/dll/win32/crypt32/store.c b/reactos/dll/win32/crypt32/store.c index a90cc3f3dfd..95b91dabce4 100644 --- a/reactos/dll/win32/crypt32/store.c +++ b/reactos/dll/win32/crypt32/store.c @@ -14,12 +14,9 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * FIXME: - * - As you can see in the stubs below, support for CRLs and CTLs is missing. - * Mostly this should be copy-paste work, and some code (e.g. extended - * properties) could be shared between them. * - The concept of physical stores and locations isn't implemented. (This * doesn't mean registry stores et al aren't implemented. See the PSDK for * registering and enumerating physical stores and locations.) @@ -32,7 +29,6 @@ #include "winbase.h" #include "winnls.h" #include "winreg.h" -#include "wingdi.h" #include "winuser.h" #include "wincrypt.h" #include "wine/debug.h" @@ -45,94 +41,76 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt); #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563 -/* Some typedefs that make it easier to abstract which type of context we're - * working with. - */ -typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType, - const BYTE *pbCertEncoded, DWORD cbCertEncoded); -typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore, - const void *context, DWORD dwAddDisposition, const void **ppStoreContext); -typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, - DWORD dwAddDisposition, const void **ppContext); -typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore, - const void *pPrevContext); -typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context, - DWORD dwPropID, void *pvData, DWORD *pcbData); -typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context, - DWORD dwPropID, DWORD dwFlags, const void *pvData); -typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags, - BYTE *pbElement, DWORD *pcbElement); -typedef BOOL (WINAPI *FreeContextFunc)(const void *context); -typedef BOOL (WINAPI *DeleteContextFunc)(const void *context); - -/* An abstract context (certificate, CRL, or CTL) interface */ -typedef struct _WINE_CONTEXT_INTERFACE -{ - CreateContextFunc create; - AddContextToStoreFunc addContextToStore; - AddEncodedContextToStoreFunc addEncodedToStore; - EnumContextsInStoreFunc enumContextsInStore; - GetContextPropertyFunc getProp; - SetContextPropertyFunc setProp; - SerializeElementFunc serialize; - FreeContextFunc free; - DeleteContextFunc deleteFromStore; -} WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE; - static const WINE_CONTEXT_INTERFACE gCertInterface = { (CreateContextFunc)CertCreateCertificateContext, (AddContextToStoreFunc)CertAddCertificateContextToStore, (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore, + (DuplicateContextFunc)CertDuplicateCertificateContext, (EnumContextsInStoreFunc)CertEnumCertificatesInStore, + (EnumPropertiesFunc)CertEnumCertificateContextProperties, (GetContextPropertyFunc)CertGetCertificateContextProperty, (SetContextPropertyFunc)CertSetCertificateContextProperty, (SerializeElementFunc)CertSerializeCertificateStoreElement, (FreeContextFunc)CertFreeCertificateContext, (DeleteContextFunc)CertDeleteCertificateFromStore, }; +PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface; static const WINE_CONTEXT_INTERFACE gCRLInterface = { (CreateContextFunc)CertCreateCRLContext, (AddContextToStoreFunc)CertAddCRLContextToStore, (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore, + (DuplicateContextFunc)CertDuplicateCRLContext, (EnumContextsInStoreFunc)CertEnumCRLsInStore, + (EnumPropertiesFunc)CertEnumCRLContextProperties, (GetContextPropertyFunc)CertGetCRLContextProperty, (SetContextPropertyFunc)CertSetCRLContextProperty, (SerializeElementFunc)CertSerializeCRLStoreElement, (FreeContextFunc)CertFreeCRLContext, (DeleteContextFunc)CertDeleteCRLFromStore, }; +PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface; static const WINE_CONTEXT_INTERFACE gCTLInterface = { (CreateContextFunc)CertCreateCTLContext, (AddContextToStoreFunc)CertAddCTLContextToStore, (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore, + (DuplicateContextFunc)CertDuplicateCTLContext, (EnumContextsInStoreFunc)CertEnumCTLsInStore, + (EnumPropertiesFunc)CertEnumCTLContextProperties, (GetContextPropertyFunc)CertGetCTLContextProperty, (SetContextPropertyFunc)CertSetCTLContextProperty, (SerializeElementFunc)CertSerializeCTLStoreElement, (FreeContextFunc)CertFreeCTLContext, (DeleteContextFunc)CertDeleteCTLFromStore, }; +PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface; struct WINE_CRYPTCERTSTORE; typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara); -struct _WINE_CERT_CONTEXT; +/* Called to enumerate the next context in a store. */ +typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev); -/* Called to enumerate the next certificate in a store. */ -typedef struct _WINE_CERT_CONTEXT * (*EnumCertFunc) - (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT *pPrev); - -/* Called to add a new certificate context to a store. If ppStoreContext is - * not NULL, the added context should be returned in *ppStoreContext. +/* Called to add a context to a store. If toReplace is not NULL, + * context replaces toReplace in the store, and access checks should not be + * performed. Otherwise context is a new context, and it should only be + * added if the store allows it. If ppStoreContext is not NULL, the added + * context should be returned in *ppStoreContext. */ -typedef BOOL (*AddCertFunc)(struct WINE_CRYPTCERTSTORE *store, - struct _WINE_CERT_CONTEXT *context, DWORD dwAddDisposition, - PCCERT_CONTEXT *ppStoreContext); +typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context, + void *toReplace, const void **ppStoreContext); + +typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context); + +typedef struct _CONTEXT_STORE +{ + AddFunc addContext; + EnumFunc enumContext; + DeleteFunc deleteContext; +} CONTEXT_STORE, *PCONTEXT_STORE; typedef enum _CertStoreType { StoreTypeMem, @@ -149,66 +127,22 @@ typedef enum _CertStoreType { */ typedef struct WINE_CRYPTCERTSTORE { - DWORD dwMagic; - LONG ref; - DWORD dwOpenFlags; - HCRYPTPROV cryptProv; - CertStoreType type; - PFN_CERT_STORE_PROV_CLOSE closeStore; - AddCertFunc addCert; - EnumCertFunc enumCert; - PFN_CERT_STORE_PROV_DELETE_CERT deleteCert; - PFN_CERT_STORE_PROV_CONTROL control; /* optional */ + DWORD dwMagic; + LONG ref; + DWORD dwOpenFlags; + HCRYPTPROV cryptProv; + CertStoreType type; + PFN_CERT_STORE_PROV_CLOSE closeStore; + CONTEXT_STORE certs; + CONTEXT_STORE crls; + PFN_CERT_STORE_PROV_CONTROL control; /* optional */ } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE; -typedef enum _ContextType { - ContextTypeData, - ContextTypeLink, -} ContextType; - -/* A certificate context. This is the base type, and the two real types - * (data and link) derive from it. Each one can be cast to a PCCERT_CONTEXT. - */ -typedef struct _WINE_CERT_CONTEXT -{ - CERT_CONTEXT cert; - LONG ref; - ContextType type; -} WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT; -typedef const struct _WINE_CERT_CONTEXT PCWINE_CERT_CONTEXT; - -typedef struct _WINE_CERT_CONTEXT_DATA -{ - CERT_CONTEXT cert; - LONG ref; - ContextType type; /* always ContextTypeData */ - PCONTEXT_PROPERTY_LIST properties; -} WINE_CERT_CONTEXT_DATA, *PWINE_CERT_CONTEXT_DATA; -typedef const struct _WINE_CERT_CONTEXT_DATA PCWINE_CERT_CONTEXT_DATA; - -typedef struct _WINE_CERT_CONTEXT_LINK -{ - CERT_CONTEXT cert; - LONG ref; - ContextType type; /* always ContextTypeLink */ - PWINE_CERT_CONTEXT linked; -} WINE_CERT_CONTEXT_LINK, *PWINE_CERT_CONTEXT_LINK; -typedef const struct _WINE_CERT_CONTEXT_LINK PCWINE_CERT_CONTEXT_LINK; - -/* A mem store has a list of these. They're also returned by the mem store - * during enumeration. - */ -typedef struct _WINE_CERT_LIST_ENTRY -{ - WINE_CERT_CONTEXT_LINK cert; - struct list entry; -} WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY; - typedef struct _WINE_MEMSTORE { WINECRYPT_CERTSTORE hdr; - CRITICAL_SECTION cs; - struct list certs; + struct ContextList *certs; + struct ContextList *crls; } WINE_MEMSTORE, *PWINE_MEMSTORE; typedef struct _WINE_HASH_TO_DELETE @@ -226,6 +160,7 @@ typedef struct _WINE_REGSTOREINFO BOOL dirty; CRITICAL_SECTION cs; struct list certsToDelete; + struct list crlsToDelete; } WINE_REGSTOREINFO, *PWINE_REGSTOREINFO; typedef struct _WINE_STORE_LIST_ENTRY @@ -236,19 +171,6 @@ typedef struct _WINE_STORE_LIST_ENTRY struct list entry; } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY; -/* Returned by a collection store during enumeration. - * Note: relies on the list entry being valid after use, which a number of - * conditions might make untrue (reentrancy, closing a collection store before - * continuing an enumeration on it, ...). The tests seem to indicate this - * sort of unsafety is okay, since Windows isn't well-behaved in these - * scenarios either. - */ -typedef struct _WINE_COLLECTION_CERT_CONTEXT -{ - WINE_CERT_CONTEXT_LINK cert; - PWINE_STORE_LIST_ENTRY storeEntry; -} WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT; - typedef struct _WINE_COLLECTIONSTORE { WINECRYPT_CERTSTORE hdr; @@ -265,27 +187,11 @@ typedef struct _WINE_PROVIDERSTORE PFN_CERT_STORE_PROV_CLOSE provCloseStore; PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert; PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert; + PFN_CERT_STORE_PROV_WRITE_CRL provWriteCrl; + PFN_CERT_STORE_PROV_DELETE_CRL provDeleteCrl; PFN_CERT_STORE_PROV_CONTROL provControl; } WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE; -/* Internal version of CertGetCertificateContextProperty that gets properties - * directly from the context (or the context it's linked to, depending on its - * type.) Doesn't handle special-case properties, since they are handled by - * CertGetCertificateContextProperty, and are particular to the store in which - * the property exists (which is separate from the context.) - */ -static BOOL WINAPI CRYPT_GetCertificateContextProperty( - PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData); - -/* Internal version of CertSetCertificateContextProperty that sets properties - * directly on the context (or the context it's linked to, depending on its - * type.) Doesn't handle special cases, since they're handled by - * CertSetCertificateContextProperty anyway. - */ -static BOOL WINAPI CRYPT_SetCertificateContextProperty( - PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, - const void *pvData); - static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv, DWORD dwFlags, CertStoreType type) { @@ -301,166 +207,92 @@ static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv, store->dwOpenFlags = dwFlags; } -/* Initializes the reference ref to point to context, and increments context's - * reference count. Also sets the hCertStore member of the reference to store. - */ -static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_LINK ref, - PWINE_CERT_CONTEXT context, HCERTSTORE store) -{ - TRACE("(%p, %p)\n", ref, context); - memcpy(&ref->cert, context, sizeof(ref->cert)); - ref->ref = 1; - ref->type = ContextTypeLink; - ref->linked = context; - InterlockedIncrement(&context->ref); - TRACE("%p's ref count is %ld\n", context, context->ref); - ref->cert.hCertStore = store; -} - -static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition, - PCCERT_CONTEXT *ppStoreContext) +static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert, + void *toReplace, const void **ppStoreContext) { WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; - BOOL add = FALSE, ret; - PCCERT_CONTEXT existing = NULL; + PCERT_CONTEXT context; - TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext); + TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); - if (dwAddDisposition != CERT_STORE_ADD_ALWAYS) + context = (PCERT_CONTEXT)ContextList_Add(ms->certs, cert, toReplace); + if (context) { - BYTE hashToAdd[20]; - DWORD size = sizeof(hashToAdd); - - ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)cert, - CERT_HASH_PROP_ID, hashToAdd, &size); - if (ret) - { - CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd }; - - existing = CertFindCertificateInStore(store, - cert->cert.dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob, - NULL); - } + context->hCertStore = store; + if (ppStoreContext) + *ppStoreContext = CertDuplicateCertificateContext(context); } - switch (dwAddDisposition) - { - case CERT_STORE_ADD_ALWAYS: - add = TRUE; - break; - case CERT_STORE_ADD_NEW: - { - if (existing) - { - TRACE("found matching certificate, not adding\n"); - SetLastError(CRYPT_E_EXISTS); - add = FALSE; - } - else - add = TRUE; - break; - } - case CERT_STORE_ADD_REPLACE_EXISTING: - { - add = TRUE; - if (existing) - { - TRACE("found matching certificate, replacing\n"); - CertDeleteCertificateFromStore(existing); - } - break; - } - default: - FIXME("Unimplemented add disposition %ld\n", dwAddDisposition); - add = FALSE; - } - if (existing) - CertFreeCertificateContext(existing); - if (add) - { - PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc( - sizeof(WINE_CERT_LIST_ENTRY)); - - if (entry) - { - TRACE("adding %p\n", entry); - CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)cert, store); - EnterCriticalSection(&ms->cs); - list_add_tail(&ms->certs, &entry->entry); - LeaveCriticalSection(&ms->cs); - if (ppStoreContext) - *ppStoreContext = - CertDuplicateCertificateContext((PCCERT_CONTEXT)entry); - ret = TRUE; - } - else - ret = FALSE; - } - else - ret = FALSE; - TRACE("returning %d\n", ret); - return ret; + return context ? TRUE : FALSE; } -static PWINE_CERT_CONTEXT CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT pPrev) +static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) { WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; - PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev; - PWINE_CERT_CONTEXT ret; - struct list *listNext; + void *ret; TRACE("(%p, %p)\n", store, pPrev); - EnterCriticalSection(&ms->cs); - if (prevEntry) - { - listNext = list_next(&ms->certs, &prevEntry->entry); - CertFreeCertificateContext((PCCERT_CONTEXT)pPrev); - } - else - listNext = list_next(&ms->certs, &ms->certs); - if (listNext) - ret = (PWINE_CERT_CONTEXT)CertDuplicateCertificateContext( - (PCCERT_CONTEXT)LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry)); - else - { + + ret = ContextList_Enum(ms->certs, pPrev); + if (!ret) SetLastError(CRYPT_E_NOT_FOUND); - ret = NULL; - } - LeaveCriticalSection(&ms->cs); TRACE("returning %p\n", ret); return ret; } -static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) +static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext) { - WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore; - PWINE_CERT_LIST_ENTRY cert = (PWINE_CERT_LIST_ENTRY)pCertContext; - BOOL ret; + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; - /* The passed-in context is itself a list entry, so just remove it. */ - EnterCriticalSection(&store->cs); - list_remove(&cert->entry); - ret = CertFreeCertificateContext(pCertContext); - LeaveCriticalSection(&store->cs); + ContextList_Delete(ms->certs, pCertContext); + return TRUE; +} + +static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl, + void *toReplace, const void **ppStoreContext) +{ + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + PCRL_CONTEXT context; + + TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); + + context = (PCRL_CONTEXT)ContextList_Add(ms->crls, crl, toReplace); + if (context) + { + context->hCertStore = store; + if (ppStoreContext) + *ppStoreContext = CertDuplicateCRLContext(context); + } + return context ? TRUE : FALSE; +} + +static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + void *ret; + + TRACE("(%p, %p)\n", store, pPrev); + + ret = ContextList_Enum(ms->crls, pPrev); + if (!ret) + SetLastError(CRYPT_E_NOT_FOUND); + + TRACE("returning %p\n", ret); return ret; } +static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext) +{ + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + + ContextList_Delete(ms->crls, pCrlContext); + return TRUE; +} + static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store) { - PWINE_CERT_LIST_ENTRY cert, next; - - EnterCriticalSection(&store->cs); - LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY, - entry) - { - TRACE("removing %p\n", cert); - list_remove(&cert->entry); - CertFreeCertificateContext((PCCERT_CONTEXT)cert); - } - LeaveCriticalSection(&store->cs); + ContextList_Empty(store->certs); + ContextList_Empty(store->crls); } static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) @@ -471,8 +303,8 @@ static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) if (dwFlags) FIXME("Unimplemented flags: %08lx\n", dwFlags); - CRYPT_MemEmptyStore(store); - DeleteCriticalSection(&store->cs); + ContextList_Free(store->certs); + ContextList_Free(store->crls); CryptMemFree(store); } @@ -495,45 +327,23 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, { memset(store, 0, sizeof(WINE_MEMSTORE)); CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem); - store->hdr.closeStore = CRYPT_MemCloseStore; - store->hdr.addCert = CRYPT_MemAddCert; - store->hdr.enumCert = CRYPT_MemEnumCert; - store->hdr.deleteCert = CRYPT_MemDeleteCert; - store->hdr.control = NULL; - InitializeCriticalSection(&store->cs); - list_init(&store->certs); + store->hdr.closeStore = CRYPT_MemCloseStore; + store->hdr.certs.addContext = CRYPT_MemAddCert; + store->hdr.certs.enumContext = CRYPT_MemEnumCert; + store->hdr.certs.deleteContext = CRYPT_MemDeleteCert; + store->hdr.crls.addContext = CRYPT_MemAddCrl; + store->hdr.crls.enumContext = CRYPT_MemEnumCrl; + store->hdr.crls.deleteContext = CRYPT_MemDeleteCrl; + store->hdr.control = NULL; + store->certs = ContextList_Create(pCertInterface, + sizeof(CERT_CONTEXT)); + store->crls = ContextList_Create(pCRLInterface, + sizeof(CRL_CONTEXT)); } } return (PWINECRYPT_CERTSTORE)store; } -static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition, - PCCERT_CONTEXT *ppStoreContext) -{ - PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - PWINE_STORE_LIST_ENTRY entry, next; - BOOL ret; - - TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext); - - ret = FALSE; - EnterCriticalSection(&cs->cs); - LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY, - entry) - { - if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG) - { - ret = entry->store->addCert(entry->store, cert, dwAddDisposition, - ppStoreContext); - break; - } - } - LeaveCriticalSection(&cs->cs); - SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); - return ret; -} - static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags) { PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; @@ -552,65 +362,113 @@ static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags) CryptMemFree(cs); } -/* Advances a collection enumeration by one cert, if possible, where advancing - * means: +static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store, + PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize, + BOOL addRef) +{ + void *ret = Context_CreateLinkContext(contextSize, child, + sizeof(PWINE_STORE_LIST_ENTRY), addRef); + + if (ret) + *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize) + = storeEntry; + + return ret; +} + +static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store, + unsigned int contextStoreOffset, void *context, void *toReplace, unsigned int contextSize, + void **pChildContext) +{ + BOOL ret; + void *childContext = NULL; + PWINE_STORE_LIST_ENTRY storeEntry = NULL; + + TRACE("(%p, %d, %p, %p, %d)\n", store, contextStoreOffset, context, + toReplace, contextSize); + + ret = FALSE; + if (toReplace) + { + void *existingLinked = Context_GetLinkedContext(toReplace, contextSize); + PCONTEXT_STORE contextStore; + + storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace, + contextSize); + contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store + + contextStoreOffset); + ret = contextStore->addContext(storeEntry->store, context, + existingLinked, (const void **)&childContext); + } + else + { + PWINE_STORE_LIST_ENTRY entry, next; + + EnterCriticalSection(&store->cs); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores, + WINE_STORE_LIST_ENTRY, entry) + { + if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG) + { + PCONTEXT_STORE contextStore = (PCONTEXT_STORE)( + (LPBYTE)entry->store + contextStoreOffset); + + storeEntry = entry; + ret = contextStore->addContext(entry->store, context, NULL, + (const void **)&childContext); + break; + } + } + LeaveCriticalSection(&store->cs); + if (!storeEntry) + SetLastError(E_ACCESSDENIED); + } + *pChildContext = childContext; + return ret; +} + +/* Advances a collection enumeration by one context, if possible, where + * advancing means: * - calling the current store's enumeration function once, and returning - * the enumerated cert if one is returned + * the enumerated context if one is returned * - moving to the next store if the current store has no more items, and * recursively calling itself to get the next item. * Returns NULL if the collection contains no more items or on error. * Assumes the collection store's lock is held. */ -static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum( - PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry, - PWINE_COLLECTION_CERT_CONTEXT pPrev) +static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store, + PWINE_STORE_LIST_ENTRY storeEntry, size_t contextStoreOffset, + PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize) { - PWINE_COLLECTION_CERT_CONTEXT ret; - PWINE_CERT_CONTEXT child; + void *ret, *child; struct list *storeNext = list_next(&store->stores, &storeEntry->entry); + PCONTEXT_STORE contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store + + contextStoreOffset); TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev); if (pPrev) { /* Ref-counting funny business: "duplicate" (addref) the child, because - * the CertFreeCertificateContext(pPrev) below can cause the ref count - * to become negative. See comment below as well. + * the free(pPrev) below can cause the ref count to become negative. */ - child = ((PWINE_COLLECTION_CERT_CONTEXT)pPrev)->cert.linked; - CertDuplicateCertificateContext((PCCERT_CONTEXT)child); - child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, - child); - CertFreeCertificateContext((PCCERT_CONTEXT)pPrev); + child = Context_GetLinkedContext(pPrev, contextSize); + contextInterface->duplicate(child); + child = contextStore->enumContext(storeEntry->store, child); + contextInterface->free(pPrev); pPrev = NULL; } else - child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, - NULL); + child = storeEntry->store->certs.enumContext(storeEntry->store, NULL); if (child) - { - ret = CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT)); - if (ret) - { - CRYPT_InitCertRef((PWINE_CERT_CONTEXT_LINK)ret, child, store); - /* enumCert already addref'd once, and CRYPT_InitCertRef does again, - * so free child once to get the ref count right. (Not doing so - * will leak memory if the caller calls CertFreeCertificateContext - * rather than CertEnumCertificatesInStore.) - */ - CertFreeCertificateContext((PCCERT_CONTEXT)child); - ret->storeEntry = storeEntry; - } - else - CertFreeCertificateContext((PCCERT_CONTEXT)child); - } + ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child, + contextSize, FALSE); else { if (storeNext) - { - storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry); - ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL); - } + ret = CRYPT_CollectionAdvanceEnum(store, LIST_ENTRY(storeNext, + WINE_STORE_LIST_ENTRY, entry), contextStoreOffset, + contextInterface, NULL, contextSize); else { SetLastError(CRYPT_E_NOT_FOUND); @@ -621,53 +479,161 @@ static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum( return ret; } -static PWINE_CERT_CONTEXT CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT pPrev) +static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert, + void *toReplace, const void **ppStoreContext) +{ + BOOL ret; + void *childContext = NULL; + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + + ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs), + cert, toReplace, sizeof(CERT_CONTEXT), &childContext); + if (ppStoreContext && childContext) + { + PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *) + Context_GetExtra(childContext, sizeof(CERT_CONTEXT)); + PCERT_CONTEXT context = + CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext, + sizeof(CERT_CONTEXT), TRUE); + + if (context) + context->hCertStore = store; + *ppStoreContext = context; + } + CertFreeCertificateContext((PCCERT_CONTEXT)childContext); + return ret; +} + +static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) { PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - PWINE_COLLECTION_CERT_CONTEXT prevEntry = - (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret; + void *ret; TRACE("(%p, %p)\n", store, pPrev); - if (prevEntry) + EnterCriticalSection(&cs->cs); + if (pPrev) { - EnterCriticalSection(&cs->cs); - ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->storeEntry, prevEntry); - LeaveCriticalSection(&cs->cs); + PWINE_STORE_LIST_ENTRY storeEntry = + *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev, + sizeof(CERT_CONTEXT)); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, pPrev, + sizeof(CERT_CONTEXT)); } else { - EnterCriticalSection(&cs->cs); if (!list_empty(&cs->stores)) { - PWINE_STORE_LIST_ENTRY storeEntry; + PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next, + WINE_STORE_LIST_ENTRY, entry); - storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY, - entry); - ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, NULL); + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, NULL, + sizeof(CERT_CONTEXT)); } else { SetLastError(CRYPT_E_NOT_FOUND); ret = NULL; } - LeaveCriticalSection(&cs->cs); } + LeaveCriticalSection(&cs->cs); + if (ret) + ((PCERT_CONTEXT)ret)->hCertStore = store; TRACE("returning %p\n", ret); - return (PWINE_CERT_CONTEXT)ret; + return ret; } -static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) +static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store, + void *pCertContext) { - PWINE_COLLECTION_CERT_CONTEXT context = - (PWINE_COLLECTION_CERT_CONTEXT)pCertContext; BOOL ret; - TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags); + TRACE("(%p, %p)\n", store, pCertContext); - ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->cert.linked); + ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT) + Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT))); + return ret; +} + +static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl, + void *toReplace, const void **ppStoreContext) +{ + BOOL ret; + void *childContext = NULL; + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + + ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls), + crl, toReplace, sizeof(CRL_CONTEXT), &childContext); + if (ppStoreContext && childContext) + { + PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *) + Context_GetExtra(childContext, sizeof(CRL_CONTEXT)); + PCRL_CONTEXT context = + CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext, + sizeof(CRL_CONTEXT), TRUE); + + if (context) + context->hCertStore = store; + *ppStoreContext = context; + } + CertFreeCRLContext((PCCRL_CONTEXT)childContext); + return ret; +} + +static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + void *ret; + + TRACE("(%p, %p)\n", store, pPrev); + + EnterCriticalSection(&cs->cs); + if (pPrev) + { + PWINE_STORE_LIST_ENTRY storeEntry = + *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev, + sizeof(CRL_CONTEXT)); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, pPrev, + sizeof(CRL_CONTEXT)); + } + else + { + if (!list_empty(&cs->stores)) + { + PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next, + WINE_STORE_LIST_ENTRY, entry); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, NULL, + sizeof(CRL_CONTEXT)); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + } + LeaveCriticalSection(&cs->cs); + if (ret) + ((PCRL_CONTEXT)ret)->hCertStore = store; + TRACE("returning %p\n", ret); + return ret; +} + +static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store, + void *pCrlContext) +{ + BOOL ret; + + TRACE("(%p, %p)\n", store, pCrlContext); + + ret = CertDeleteCRLFromStore((PCCRL_CONTEXT) + Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT))); return ret; } @@ -689,10 +655,13 @@ static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, memset(store, 0, sizeof(WINE_COLLECTIONSTORE)); CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeCollection); - store->hdr.closeStore = CRYPT_CollectionCloseStore; - store->hdr.addCert = CRYPT_CollectionAddCert; - store->hdr.enumCert = CRYPT_CollectionEnumCert; - store->hdr.deleteCert = CRYPT_CollectionDeleteCert; + store->hdr.closeStore = CRYPT_CollectionCloseStore; + store->hdr.certs.addContext = CRYPT_CollectionAddCert; + store->hdr.certs.enumContext = CRYPT_CollectionEnumCert; + store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert; + store->hdr.crls.addContext = CRYPT_CollectionAddCRL; + store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL; + store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL; InitializeCriticalSection(&store->cs); list_init(&store->stores); } @@ -713,69 +682,137 @@ static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) CryptMemFree(store); } -static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition, - PCCERT_CONTEXT *ppStoreContext) +static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert, + void *toReplace, const void **ppStoreContext) { PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; BOOL ret; - TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext); + TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); - if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) - { - SetLastError(ERROR_ACCESS_DENIED); - ret = FALSE; - } + if (toReplace) + ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace, + (const void **)ppStoreContext); else { - ret = TRUE; - if (ps->provWriteCert) - ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert, - CERT_STORE_PROV_WRITE_ADD_FLAG); - if (ret) + if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) { - ret = ps->memStore->addCert(ps->memStore, cert, - dwAddDisposition, ppStoreContext); - /* dirty trick: replace the returned context's hCertStore with - * store. - */ - if (ppStoreContext) - (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store; + SetLastError(ERROR_ACCESS_DENIED); + ret = FALSE; + } + else + { + ret = TRUE; + if (ps->provWriteCert) + ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert, + CERT_STORE_PROV_WRITE_ADD_FLAG); + if (ret) + ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL, + (const void **)ppStoreContext); } } + /* dirty trick: replace the returned context's hCertStore with + * store. + */ + if (ppStoreContext) + (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store; return ret; } -static PWINE_CERT_CONTEXT CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT pPrev) +static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) { PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - PWINE_CERT_CONTEXT ret; + void *ret; - ret = ps->memStore->enumCert(ps->memStore, pPrev); + ret = ps->memStore->certs.enumContext(ps->memStore, pPrev); if (ret) { /* same dirty trick: replace the returned context's hCertStore with * store. */ - ret->cert.hCertStore = store; + ((PCERT_CONTEXT)ret)->hCertStore = store; } return ret; } -static BOOL WINAPI CRYPT_ProvDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT cert, DWORD dwFlags) +static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert) { - PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; BOOL ret = TRUE; - TRACE("(%p, %p, %08lx)\n", hCertStore, cert, dwFlags); + TRACE("(%p, %p)\n", store, cert); - if (store->provDeleteCert) - ret = store->provDeleteCert(store->hStoreProv, cert, dwFlags); + if (ps->provDeleteCert) + ret = ps->provDeleteCert(ps->hStoreProv, cert, 0); if (ret) - ret = store->memStore->deleteCert(store->memStore, cert, dwFlags); + ret = ps->memStore->certs.deleteContext(ps->memStore, cert); + return ret; +} + +static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl, + void *toReplace, const void **ppStoreContext) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret; + + TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); + + if (toReplace) + ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace, + (const void **)ppStoreContext); + else + { + if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) + { + SetLastError(ERROR_ACCESS_DENIED); + ret = FALSE; + } + else + { + ret = TRUE; + if (ps->provWriteCrl) + ret = ps->provWriteCrl(ps->hStoreProv, (PCCRL_CONTEXT)crl, + CERT_STORE_PROV_WRITE_ADD_FLAG); + if (ret) + ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL, + (const void **)ppStoreContext); + } + } + /* dirty trick: replace the returned context's hCertStore with + * store. + */ + if (ppStoreContext) + (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store; + return ret; +} + +static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + void *ret; + + ret = ps->memStore->crls.enumContext(ps->memStore, pPrev); + if (ret) + { + /* same dirty trick: replace the returned context's hCertStore with + * store. + */ + ((PCERT_CONTEXT)ret)->hCertStore = store; + } + return ret; +} + +static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret = TRUE; + + TRACE("(%p, %p)\n", store, crl); + + if (ps->provDeleteCrl) + ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0); + if (ret) + ret = ps->memStore->crls.deleteContext(ps->memStore, crl); return ret; } @@ -814,9 +851,12 @@ static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv, ret->memStore = memStore; ret->hStoreProv = pProvInfo->hStoreProv; ret->hdr.closeStore = CRYPT_ProvCloseStore; - ret->hdr.addCert = CRYPT_ProvAddCert; - ret->hdr.enumCert = CRYPT_ProvEnumCert; - ret->hdr.deleteCert = CRYPT_ProvDeleteCert; + ret->hdr.certs.addContext = CRYPT_ProvAddCert; + ret->hdr.certs.enumContext = CRYPT_ProvEnumCert; + ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert; + ret->hdr.crls.addContext = CRYPT_ProvAddCRL; + ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL; + ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL; ret->hdr.control = CRYPT_ProvControl; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC) ret->provCloseStore = @@ -835,6 +875,18 @@ static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv, CERT_STORE_PROV_DELETE_CERT_FUNC]; else ret->provDeleteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_WRITE_CRL_FUNC) + ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_WRITE_CRL_FUNC]; + else + ret->provWriteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_DELETE_CRL_FUNC) + ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_DELETE_CRL_FUNC]; + else + ret->provDeleteCert = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CONTROL_FUNC) ret->provControl = pProvInfo->rgpvStoreProvFunc[ @@ -867,9 +919,10 @@ static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, dwFlags, pvPara, NULL, &provInfo); else { - PWINECRYPT_CERTSTORE memStore; + HCERTSTORE memStore; - memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL); + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); if (memStore) { if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, @@ -1092,7 +1145,8 @@ static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store) static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW }; static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface, &gCRLInterface, &gCTLInterface }; - struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL }; + struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete, + NULL }; BOOL ret = TRUE; DWORD i; @@ -1171,14 +1225,11 @@ static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) CryptMemFree(store); } -static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT cert, DWORD dwFlags) +static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store, + const void *context, DWORD dwFlags) { - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; BOOL ret; - TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags); - if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG) { store->dirty = TRUE; @@ -1189,14 +1240,12 @@ static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, return ret; } -static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) +static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store, + struct list *deleteList, const void *context, + PCWINE_CONTEXT_INTERFACE contextInterface) { - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; BOOL ret; - TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags); - if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG) { SetLastError(ERROR_ACCESS_DENIED); @@ -1211,12 +1260,12 @@ static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, { DWORD size = sizeof(toDelete->hash); - ret = CertGetCertificateContextProperty(pCertContext, - CERT_HASH_PROP_ID, toDelete->hash, &size); + ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, + toDelete->hash, &size); if (ret) { EnterCriticalSection(&store->cs); - list_add_tail(&store->certsToDelete, &toDelete->entry); + list_add_tail(deleteList, &toDelete->entry); LeaveCriticalSection(&store->cs); } else @@ -1233,6 +1282,48 @@ static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, return ret; } +static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags); + + return CRYPT_RegWriteContext(store, cert, dwFlags); +} + +static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags); + + return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext, + pCertInterface); +} + +static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT crl, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags); + + return CRYPT_RegWriteContext(store, crl, dwFlags); +} + +static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT pCrlContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %08lx)\n", store, pCrlContext, dwFlags); + + return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext, + pCRLInterface); +} + static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, DWORD dwCtrlType, void const *pvCtrlPara) { @@ -1321,8 +1412,8 @@ static void *regProvFuncs[] = { CRYPT_RegDeleteCert, NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ - NULL, /* CERT_STORE_PROV_WRITE_CRL_FUNC */ - NULL, /* CERT_STORE_PROV_DELETE_CRL_FUNC */ + CRYPT_RegWriteCRL, + CRYPT_RegDeleteCRL, NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ @@ -1377,6 +1468,7 @@ static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, regInfo->key = key; InitializeCriticalSection(®Info->cs); list_init(®Info->certsToDelete); + list_init(®Info->crlsToDelete); CRYPT_RegReadFromReg(regInfo); regInfo->dirty = FALSE; provInfo.cbSize = sizeof(provInfo); @@ -1415,7 +1507,7 @@ static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, if (!pvPara) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return NULL; } @@ -1463,7 +1555,7 @@ static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, debugstr_w(storeName)); return NULL; default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return NULL; } @@ -1698,7 +1790,7 @@ HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv, { if (!szSubSystemProtocol) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return 0; } return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv, @@ -1710,7 +1802,7 @@ HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv, { if (!szSubSystemProtocol) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return 0; } return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv, @@ -1725,442 +1817,102 @@ BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType, return TRUE; } -PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType, - const BYTE* pbCrlEncoded, DWORD cbCrlEncoded) +DWORD CertStore_GetAccessState(HCERTSTORE hCertStore) { - PCRL_CONTEXT pcrl; - BYTE* data; + DWORD state = 0; - TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded); - - /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */ - pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) ); - if( !pcrl ) - return NULL; - - data = CryptMemAlloc( cbCrlEncoded ); - if( !data ) + if (hCertStore) { - CryptMemFree( pcrl ); - return NULL; + PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; + + if (store->type != StoreTypeMem && + !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) + state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; } - - pcrl->dwCertEncodingType = dwCertEncodingType; - pcrl->pbCrlEncoded = data; - pcrl->cbCrlEncoded = cbCrlEncoded; - pcrl->pCrlInfo = NULL; - pcrl->hCertStore = 0; - - return pcrl; + return state; } -/* Decodes the encoded certificate and creates the certificate context for it. - */ -static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext( - DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded) -{ - PWINE_CERT_CONTEXT_DATA cert = NULL; - BOOL ret; - PCERT_SIGNED_CONTENT_INFO signedCert = NULL; - PCERT_INFO certInfo = NULL; - DWORD size = 0; - - TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, - cbCertEncoded); - - /* First try to decode it as a signed cert. */ - ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded, - cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&signedCert, &size); - if (ret) - { - size = 0; - ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, - signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, - CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&certInfo, &size); - LocalFree(signedCert); - } - /* Failing that, try it as an unsigned cert */ - if (!ret) - { - size = 0; - ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, - pbCertEncoded, cbCertEncoded, - CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, - (BYTE *)&certInfo, &size); - } - if (ret) - { - BYTE *data = NULL; - - cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_DATA)); - if (!cert) - goto end; - data = CryptMemAlloc(cbCertEncoded); - if (!data) - { - CryptMemFree(cert); - cert = NULL; - goto end; - } - memcpy(data, pbCertEncoded, cbCertEncoded); - cert->cert.dwCertEncodingType = dwCertEncodingType; - cert->cert.pbCertEncoded = data; - cert->cert.cbCertEncoded = cbCertEncoded; - cert->cert.pCertInfo = certInfo; - cert->cert.hCertStore = 0; - cert->ref = 1; - cert->type = ContextTypeData; - cert->properties = ContextPropertyList_Create(); - } - -end: - return (PWINE_CERT_CONTEXT)cert; -} - -PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType, - const BYTE *pbCertEncoded, DWORD cbCertEncoded) -{ - PWINE_CERT_CONTEXT cert; - - TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, - cbCertEncoded); - - cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded, - cbCertEncoded); - return (PCCERT_CONTEXT)cert; -} - -/* If context is a link, follows it to its linked context (recursively, if - * necessary) and returns the data context associated with the link. - * Otherwise just returns context. - */ -static inline PWINE_CERT_CONTEXT_DATA CertContext_GetDataContext( - PWINE_CERT_CONTEXT context) -{ - PWINE_CERT_CONTEXT ptr = context; - - while (ptr && ptr->type == ContextTypeLink) - ptr = ((PWINE_CERT_CONTEXT_LINK)ptr)->linked; - return (ptr && ptr->type == ContextTypeData) ? - (PWINE_CERT_CONTEXT_DATA)ptr : NULL; -} - -DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext, - DWORD dwPropId) -{ - PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext( - (PWINE_CERT_CONTEXT)pCertContext); - DWORD ret; - - TRACE("(%p, %ld)\n", pCertContext, dwPropId); - - if (linked) - ret = ContextPropertyList_EnumPropIDs(linked->properties, dwPropId); - else - ret = 0; - return ret; -} - -static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId, - ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, - DWORD *pcbData) -{ - BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, - pcbData); - if (ret) - { - CRYPT_DATA_BLOB blob = { *pcbData, pvData }; - - ret = CRYPT_SetCertificateContextProperty(context, dwPropId, - 0, &blob); - } - return ret; -} - -static BOOL WINAPI CRYPT_GetCertificateContextProperty( - PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData) -{ - PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(context); - BOOL ret; - CRYPT_DATA_BLOB blob; - - TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData); - - if (linked) - ret = ContextPropertyList_FindProperty(linked->properties, dwPropId, - &blob); - else - ret = FALSE; - if (ret) - { - if (!pvData) - { - *pcbData = blob.cbData; - ret = TRUE; - } - else if (*pcbData < blob.cbData) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = blob.cbData; - } - else - { - memcpy(pvData, blob.pbData, blob.cbData); - *pcbData = blob.cbData; - ret = TRUE; - } - } - else - { - /* Implicit properties */ - switch (dwPropId) - { - case CERT_SHA1_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1, - context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData, - pcbData); - break; - case CERT_MD5_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, - context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData, - pcbData); - break; - case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, - context->cert.pCertInfo->Subject.pbData, - context->cert.pCertInfo->Subject.cbData, - pvData, pcbData); - break; - case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, - context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, - context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, - pvData, pcbData); - break; - case CERT_SIGNATURE_HASH_PROP_ID: - case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: - FIXME("implicit property %ld\n", dwPropId); - SetLastError(CRYPT_E_NOT_FOUND); - break; - default: - SetLastError(CRYPT_E_NOT_FOUND); - } - } - TRACE("returning %d\n", ret); - return ret; -} - -BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, - DWORD dwPropId, void *pvData, DWORD *pcbData) -{ - BOOL ret; - - TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData); - - /* Special cases for invalid/special prop IDs. - */ - switch (dwPropId) - { - case 0: - case CERT_CERT_PROP_ID: - case CERT_CRL_PROP_ID: - case CERT_CTL_PROP_ID: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - case CERT_ACCESS_STATE_PROP_ID: - if (!pvData) - { - *pcbData = sizeof(DWORD); - return TRUE; - } - else if (*pcbData < sizeof(DWORD)) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = sizeof(DWORD); - return FALSE; - } - else - { - DWORD state = 0; - - if (pCertContext->hCertStore) - { - PWINECRYPT_CERTSTORE store = - (PWINECRYPT_CERTSTORE)pCertContext->hCertStore; - - if (!(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) - state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; - } - *(DWORD *)pvData = state; - return TRUE; - } - } - - ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCertContext, - dwPropId, pvData, pcbData); - TRACE("returning %d\n", ret); - return ret; -} - -static BOOL WINAPI CRYPT_SetCertificateContextProperty( - PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(context); - BOOL ret; - - TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData); - - if (!linked) - ret = FALSE; - else if (!pvData) - { - ContextPropertyList_RemoveProperty(linked->properties, dwPropId); - ret = TRUE; - } - else - { - switch (dwPropId) - { - case CERT_AUTO_ENROLL_PROP_ID: - case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ - case CERT_DESCRIPTION_PROP_ID: - case CERT_FRIENDLY_NAME_PROP_ID: - case CERT_HASH_PROP_ID: - case CERT_KEY_IDENTIFIER_PROP_ID: - case CERT_MD5_HASH_PROP_ID: - case CERT_NEXT_UPDATE_LOCATION_PROP_ID: - case CERT_PUBKEY_ALG_PARA_PROP_ID: - case CERT_PVK_FILE_PROP_ID: - case CERT_SIGNATURE_HASH_PROP_ID: - case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: - case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: - case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: - case CERT_ENROLLMENT_PROP_ID: - case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: - case CERT_RENEWAL_PROP_ID: - { - PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData; - - ret = ContextPropertyList_SetProperty(linked->properties, dwPropId, - blob->pbData, blob->cbData); - break; - } - case CERT_DATE_STAMP_PROP_ID: - ret = ContextPropertyList_SetProperty(linked->properties, dwPropId, - pvData, sizeof(FILETIME)); - break; - default: - FIXME("%ld: stub\n", dwPropId); - ret = FALSE; - } - } - TRACE("returning %d\n", ret); - return ret; -} - -BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext, - DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - BOOL ret; - - TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData); - - /* Handle special cases for "read-only"/invalid prop IDs. Windows just - * crashes on most of these, I'll be safer. - */ - switch (dwPropId) - { - case 0: - case CERT_ACCESS_STATE_PROP_ID: - case CERT_CERT_PROP_ID: - case CERT_CRL_PROP_ID: - case CERT_CTL_PROP_ID: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - } - ret = CRYPT_SetCertificateContextProperty((PWINE_CERT_CONTEXT)pCertContext, - dwPropId, dwFlags, pvData); - TRACE("returning %d\n", ret); - return ret; -} - -PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext( - PCCERT_CONTEXT pCertContext) -{ - PWINE_CERT_CONTEXT context = (PWINE_CERT_CONTEXT)pCertContext; - - TRACE("(%p)\n", pCertContext); - InterlockedIncrement(&context->ref); - return pCertContext; -} +#define CertContext_CopyProperties(to, from) \ + Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT)) BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, PCCERT_CONTEXT *ppStoreContext) { PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; - PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext( - (PWINE_CERT_CONTEXT)pCertContext); - PWINE_CERT_CONTEXT cert; - BOOL ret; + BOOL ret = TRUE; + PCCERT_CONTEXT toAdd = NULL, existing = NULL; TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext, dwAddDisposition, ppStoreContext); - /* FIXME: some tests needed to verify return codes */ - if (!store) + /* Weird case to pass a test */ + if (dwAddDisposition == 0) { - SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(STATUS_ACCESS_VIOLATION); return FALSE; } - if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + if (dwAddDisposition != CERT_STORE_ADD_ALWAYS) { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + BYTE hashToAdd[20]; + DWORD size = sizeof(hashToAdd); - cert = CRYPT_CreateCertificateContext(pCertContext->dwCertEncodingType, - pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); - if (cert) - { - PWINE_CERT_CONTEXT_DATA certData = CertContext_GetDataContext(cert); - - ContextPropertyList_Copy(certData->properties, linked->properties); - ret = store->addCert(store, cert, dwAddDisposition, ppStoreContext); - CertFreeCertificateContext((PCCERT_CONTEXT)cert); - } - else - ret = FALSE; - return ret; -} - -BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, - DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext) -{ - WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; - BOOL ret; - - TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType, - pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext); - - if (!hcs) - ret = FALSE; - else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - ret = FALSE; - else - { - PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext( - dwCertEncodingType, pbCertEncoded, cbCertEncoded); - - if (cert) + ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID, + hashToAdd, &size); + if (ret) { - ret = hcs->addCert(hcs, cert, dwAddDisposition, ppCertContext); - CertFreeCertificateContext((PCCERT_CONTEXT)cert); + CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd }; + + existing = CertFindCertificateInStore(hCertStore, + pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob, + NULL); + } + } + + switch (dwAddDisposition) + { + case CERT_STORE_ADD_ALWAYS: + toAdd = CertDuplicateCertificateContext(pCertContext); + break; + case CERT_STORE_ADD_NEW: + if (existing) + { + TRACE("found matching certificate, not adding\n"); + SetLastError(CRYPT_E_EXISTS); + ret = FALSE; } else - ret = FALSE; + toAdd = CertDuplicateCertificateContext(pCertContext); + break; + case CERT_STORE_ADD_REPLACE_EXISTING: + toAdd = CertDuplicateCertificateContext(pCertContext); + break; + case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: + toAdd = CertDuplicateCertificateContext(pCertContext); + if (existing) + CertContext_CopyProperties(toAdd, existing); + break; + case CERT_STORE_ADD_USE_EXISTING: + if (existing) + CertContext_CopyProperties(existing, pCertContext); + break; + default: + FIXME("Unimplemented add disposition %ld\n", dwAddDisposition); + ret = FALSE; } + + if (toAdd) + { + if (store) + ret = store->certs.addContext(store, (void *)toAdd, + (void *)existing, (const void **)ppStoreContext); + else if (ppStoreContext) + *ppStoreContext = CertDuplicateCertificateContext(toAdd); + CertFreeCertificateContext(toAdd); + } + CertFreeCertificateContext(existing); + + TRACE("returning %d\n", ret); return ret; } @@ -2176,7 +1928,7 @@ PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) ret = NULL; else - ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, (PWINE_CERT_CONTEXT)pPrev); + ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev); return ret; } @@ -2201,49 +1953,144 @@ BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) ret = FALSE; else - ret = hcs->deleteCert(hcs, pCertContext, 0); + ret = hcs->certs.deleteContext(hcs, (void *)pCertContext); CertFreeCertificateContext(pCertContext); } return ret; } -BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded, - DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext) -{ - FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore, - dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition, - ppCrlContext); - return FALSE; -} +#define CrlContext_CopyProperties(to, from) \ + Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT)) -BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore, - PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition, - PCCRL_CONTEXT* ppStoreContext ) +BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore, + PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition, + PCCRL_CONTEXT* ppStoreContext) { - FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext, - dwAddDisposition, ppStoreContext); - return TRUE; -} + PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; + BOOL ret = TRUE; + PCCRL_CONTEXT toAdd = NULL, existing = NULL; -BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext) -{ - FIXME("%p\n", pCrlContext ); + TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCrlContext, + dwAddDisposition, ppStoreContext); - return TRUE; + /* Weird case to pass a test */ + if (dwAddDisposition == 0) + { + SetLastError(STATUS_ACCESS_VIOLATION); + return FALSE; + } + if (dwAddDisposition != CERT_STORE_ADD_ALWAYS) + { + existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING, + pCrlContext, NULL); + } + + switch (dwAddDisposition) + { + case CERT_STORE_ADD_ALWAYS: + toAdd = CertDuplicateCRLContext(pCrlContext); + break; + case CERT_STORE_ADD_NEW: + if (existing) + { + TRACE("found matching CRL, not adding\n"); + SetLastError(CRYPT_E_EXISTS); + ret = FALSE; + } + else + toAdd = CertDuplicateCRLContext(pCrlContext); + break; + case CERT_STORE_ADD_NEWER: + if (existing) + { + LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate, + &pCrlContext->pCrlInfo->ThisUpdate); + + if (newer < 0) + toAdd = CertDuplicateCRLContext(pCrlContext); + else + { + TRACE("existing CRL is newer, not adding\n"); + SetLastError(CRYPT_E_EXISTS); + ret = FALSE; + } + } + else + toAdd = CertDuplicateCRLContext(pCrlContext); + break; + case CERT_STORE_ADD_REPLACE_EXISTING: + toAdd = CertDuplicateCRLContext(pCrlContext); + break; + case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: + toAdd = CertDuplicateCRLContext(pCrlContext); + if (existing) + CrlContext_CopyProperties(toAdd, existing); + break; + case CERT_STORE_ADD_USE_EXISTING: + if (existing) + CrlContext_CopyProperties(existing, pCrlContext); + break; + default: + FIXME("Unimplemented add disposition %ld\n", dwAddDisposition); + ret = FALSE; + } + + if (toAdd) + { + if (store) + ret = store->crls.addContext(store, (void *)toAdd, + (void *)existing, (const void **)ppStoreContext); + else if (ppStoreContext) + *ppStoreContext = CertDuplicateCRLContext(toAdd); + CertFreeCRLContext(toAdd); + } + CertFreeCRLContext(existing); + + TRACE("returning %d\n", ret); + return ret; } BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) { - FIXME("(%p): stub\n", pCrlContext); - return TRUE; + BOOL ret; + + TRACE("(%p)\n", pCrlContext); + + if (!pCrlContext) + ret = TRUE; + else if (!pCrlContext->hCertStore) + { + ret = TRUE; + CertFreeCRLContext(pCrlContext); + } + else + { + PWINECRYPT_CERTSTORE hcs = + (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore; + + if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + ret = FALSE; + else + ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext); + CertFreeCRLContext(pCrlContext); + } + return ret; } PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore, PCCRL_CONTEXT pPrev) { - FIXME("(%p, %p): stub\n", hCertStore, pPrev); - return NULL; + WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; + PCCRL_CONTEXT ret; + + TRACE("(%p, %p)\n", hCertStore, pPrev); + if (!hCertStore) + ret = NULL; + else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + ret = NULL; + else + ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev); + return ret; } PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType, @@ -2273,6 +2120,12 @@ BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore, return TRUE; } +PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext) +{ + FIXME("(%p): stub\n", pCtlContext ); + return pCtlContext; +} + BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext) { FIXME("(%p): stub\n", pCtlContext ); @@ -2351,19 +2204,11 @@ BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags, return ret; } -BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext, - DWORD dwPropId, void *pvData, DWORD *pcbData) +DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext, + DWORD dwPropId) { - FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData); - return FALSE; -} - -BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext, - DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags, - pvData); - return FALSE; + FIXME("(%p, %ld): stub\n", pCTLContext, dwPropId); + return 0; } BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext, @@ -2381,185 +2226,6 @@ BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext, return FALSE; } -static void CertDataContext_Free(PWINE_CERT_CONTEXT_DATA context) -{ - CryptMemFree(context->cert.pbCertEncoded); - LocalFree(context->cert.pCertInfo); - ContextPropertyList_Free(context->properties); - CryptMemFree(context); -} - -static void CertLinkContext_Free(PWINE_CERT_CONTEXT_LINK context) -{ - CertFreeCertificateContext((PCCERT_CONTEXT)context->linked); - CryptMemFree(context); -} - -static void CertContext_Release(PWINE_CERT_CONTEXT context) -{ - if (InterlockedDecrement(&context->ref) == 0) - { - TRACE("freeing %p\n", context); - switch (context->type) - { - case ContextTypeData: - CertDataContext_Free((PWINE_CERT_CONTEXT_DATA)context); - break; - case ContextTypeLink: - CertLinkContext_Free((PWINE_CERT_CONTEXT_LINK)context); - break; - default: - assert(0); - } - } - else - TRACE("%p's ref count is %ld\n", context, context->ref); -} - -BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) -{ - TRACE("(%p)\n", pCertContext); - - if (pCertContext) - CertContext_Release((PWINE_CERT_CONTEXT)pCertContext); - return TRUE; -} - -typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara); - -static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) -{ - return TRUE; -} - -static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) -{ - BOOL ret; - BYTE hash[16]; - DWORD size = sizeof(hash); - - ret = CertGetCertificateContextProperty(pCertContext, - CERT_MD5_HASH_PROP_ID, hash, &size); - if (ret) - { - const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; - - if (size == pHash->cbData) - ret = !memcmp(pHash->pbData, hash, size); - else - ret = FALSE; - } - return ret; -} - -static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) -{ - BOOL ret; - BYTE hash[20]; - DWORD size = sizeof(hash); - - ret = CertGetCertificateContextProperty(pCertContext, - CERT_SHA1_HASH_PROP_ID, hash, &size); - if (ret) - { - const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; - - if (size == pHash->cbData) - ret = !memcmp(pHash->pbData, hash, size); - else - ret = FALSE; - } - return ret; -} - -static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) -{ - const CERT_NAME_BLOB *blob = (const CERT_NAME_BLOB *)pvPara, *toCompare; - BOOL ret; - - if (dwType & CERT_INFO_SUBJECT_FLAG) - toCompare = &pCertContext->pCertInfo->Subject; - else - toCompare = &pCertContext->pCertInfo->Issuer; - if (toCompare->cbData == blob->cbData) - ret = !memcmp(toCompare->pbData, blob->pbData, blob->cbData); - else - ret = FALSE; - return ret; -} - -static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, - DWORD dwType, DWORD dwFlags, const void *pvPara) -{ - const CERT_INFO *pCertInfo = (const CERT_INFO *)pvPara; - BOOL ret; - - if (pCertInfo->Issuer.cbData == pCertContext->pCertInfo->Subject.cbData) - ret = !memcmp(pCertInfo->Issuer.pbData, - pCertContext->pCertInfo->Subject.pbData, pCertInfo->Issuer.cbData); - else - ret = FALSE; - return ret; -} - -PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, - const void *pvPara, PCCERT_CONTEXT pPrevCertContext) -{ - PCCERT_CONTEXT ret; - CertCompareFunc compare; - - TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType, - dwFlags, dwType, pvPara, pPrevCertContext); - - switch (dwType >> CERT_COMPARE_SHIFT) - { - case CERT_COMPARE_ANY: - compare = compare_cert_any; - break; - case CERT_COMPARE_MD5_HASH: - compare = compare_cert_by_md5_hash; - break; - case CERT_COMPARE_SHA1_HASH: - compare = compare_cert_by_sha1_hash; - break; - case CERT_COMPARE_NAME: - compare = compare_cert_by_name; - break; - case CERT_COMPARE_SUBJECT_CERT: - compare = compare_cert_by_subject_cert; - break; - default: - FIXME("find type %08lx unimplemented\n", dwType); - compare = NULL; - } - - if (compare) - { - BOOL matches = FALSE; - - ret = pPrevCertContext; - do { - ret = CertEnumCertificatesInStore(hCertStore, ret); - if (ret) - matches = compare(ret, dwType, dwFlags, pvPara); - } while (ret != NULL && !matches); - if (!ret) - SetLastError(CRYPT_E_NOT_FOUND); - } - else - { - SetLastError(CRYPT_E_NOT_FOUND); - ret = NULL; - } - return ret; -} - BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority) { @@ -2575,17 +2241,17 @@ BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, return TRUE; if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return FALSE; } if (collection->hdr.type != StoreTypeCollection) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return FALSE; } if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return FALSE; } @@ -2641,14 +2307,14 @@ void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore, return; if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return; } if (collection->hdr.type != StoreTypeCollection) return; if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + SetLastError(E_INVALIDARG); return; } EnterCriticalSection(&collection->cs); diff --git a/reactos/dll/win32/crypt32/str.c b/reactos/dll/win32/crypt32/str.c index cf56c479fb9..a80301e4110 100644 --- a/reactos/dll/win32/crypt32/str.c +++ b/reactos/dll/win32/crypt32/str.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include "windef.h" diff --git a/reactos/dll/win32/crypt32/version.rc b/reactos/dll/win32/crypt32/version.rc new file mode 100644 index 00000000000..647c766c05d --- /dev/null +++ b/reactos/dll/win32/crypt32/version.rc @@ -0,0 +1,28 @@ +/* + * crypt32 dll version resources + * + * Copyright (C) 2006 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 + */ + +#define WINE_FILEDESCRIPTION_STR "Wine CryptoAPI Library" +#define WINE_FILENAME_STR "crypt32.dll" +#define WINE_FILEVERSION 5,131,2600,1243 +#define WINE_FILEVERSION_STR "5.131.2600.1243" +#define WINE_PRODUCTVERSION 5,131,2600,1243 +#define WINE_PRODUCTVERSION_STR "5.131.2600.1243" + +#include "wine/wine_common_ver.rc"