Implement encoding/decoding of CERT_ALT_NAME_INFOs and CRL_INFOs.
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index ad4fb4b..121569f 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -35,6 +35,9 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+
+#define NONAMELESSUNION
+
#include "windef.h"
#include "winbase.h"
#include "excpt.h"
@@ -59,6 +62,9 @@
#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
+#define ASN_FLAGS_MASK 0xf0
+#define ASN_TYPE_MASK 0x0f
+
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
static const WCHAR szDllName[] = { 'D','l','l',0 };
@@ -119,7 +125,11 @@
static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
-static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
+/* 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,
@@ -419,9 +429,9 @@
HMODULE lib;
CryptEncodeObjectFunc pCryptEncodeObject;
- TRACE("(0x%08lx, %s, %p, %p, %p)\n",
- dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
- "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
+ TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
+ debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
+ pcbEncoded);
if (!pbEncoded && !pcbEncoded)
{
@@ -835,6 +845,156 @@
return ret;
}
+static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
+ BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ struct AsnEncodeSequenceItem items[3] = {
+ { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
+ { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
+ { 0 }
+ };
+ DWORD cItem = 2;
+ BOOL ret;
+
+ TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
+
+ if (entry->cExtension)
+ {
+ items[cItem].pvStructInfo = &entry->cExtension;
+ items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
+ cItem++;
+ }
+
+ ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
+ pbEncoded, pcbEncoded);
+
+ TRACE("returning %d (%08lx)\n", ret, GetLastError());
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
+ DWORD bytesNeeded, dataLen, lenBytes, i;
+ const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
+ ((const BYTE *)pvStructInfo + sizeof(DWORD));
+ BOOL ret = TRUE;
+
+ for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
+ {
+ DWORD size;
+
+ ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
+ if (ret)
+ dataLen += size;
+ }
+ CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+ bytesNeeded = 1 + lenBytes + dataLen;
+ if (!pbEncoded)
+ *pcbEncoded = bytesNeeded;
+ else
+ {
+ if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
+ pcbEncoded, bytesNeeded)))
+ {
+ if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+ pbEncoded = *(BYTE **)pbEncoded;
+ *pbEncoded++ = ASN_SEQUENCEOF;
+ CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+ pbEncoded += lenBytes;
+ for (i = 0; i < cCRLEntry; i++)
+ {
+ DWORD size = dataLen;
+
+ ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
+ pbEncoded += size;
+ dataLen -= size;
+ }
+ }
+ }
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ const DWORD *ver = (const DWORD *)pvStructInfo;
+ BOOL ret;
+
+ /* CRL_V1 is not encoded */
+ if (*ver == CRL_V1)
+ {
+ *pcbEncoded = 0;
+ ret = TRUE;
+ }
+ else
+ ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
+ dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+ return ret;
+}
+
+/* Like in Windows, this blithely ignores the validity of the passed-in
+ * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
+ * decode properly, see CRYPT_AsnDecodeCRLInfo.
+ */
+static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+
+ __TRY
+ {
+ const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
+ struct AsnEncodeSequenceItem items[7] = {
+ { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
+ { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
+ { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
+ { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
+ { 0 }
+ };
+ struct AsnConstructedItem constructed = { 0 };
+ DWORD cItem = 4;
+
+ if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
+ {
+ items[cItem].pvStructInfo = &info->NextUpdate;
+ items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
+ cItem++;
+ }
+ if (info->cCRLEntry)
+ {
+ items[cItem].pvStructInfo = &info->cCRLEntry;
+ items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
+ cItem++;
+ }
+ if (info->cExtension)
+ {
+ /* FIXME: is this really constructed? if so, is this the right tag?
+ */
+ constructed.tag = 3;
+ constructed.pvStructInfo = &info->cExtension;
+ constructed.encodeFunc = CRYPT_AsnEncodeExtensions;
+ items[cItem].pvStructInfo = &constructed;
+ items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
+ cItem++;
+ }
+
+ ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
+ dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+ }
+ __EXCEPT(page_fault)
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ ret = FALSE;
+ }
+ __ENDTRY
+ return ret;
+}
+
static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
DWORD *pcbEncoded)
{
@@ -1328,6 +1488,171 @@
return ret;
}
+static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
+ BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+ DWORD dataLen;
+
+ ret = TRUE;
+ switch (entry->dwAltNameChoice)
+ {
+ case CERT_ALT_NAME_RFC822_NAME:
+ case CERT_ALT_NAME_DNS_NAME:
+ case CERT_ALT_NAME_URL:
+ if (entry->u.pwszURL)
+ {
+ DWORD i;
+
+ /* Not + 1: don't encode the NULL-terminator */
+ dataLen = lstrlenW(entry->u.pwszURL);
+ for (i = 0; ret && i < dataLen; i++)
+ {
+ if (entry->u.pwszURL[i] > 0x7f)
+ {
+ SetLastError(CRYPT_E_INVALID_IA5_STRING);
+ ret = FALSE;
+ *pcbEncoded = i;
+ }
+ }
+ }
+ else
+ dataLen = 0;
+ break;
+ case CERT_ALT_NAME_IP_ADDRESS:
+ dataLen = entry->u.IPAddress.cbData;
+ break;
+ case CERT_ALT_NAME_REGISTERED_ID:
+ /* FIXME: encode OID */
+ case CERT_ALT_NAME_OTHER_NAME:
+ case CERT_ALT_NAME_DIRECTORY_NAME:
+ FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
+ return FALSE;
+ default:
+ SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
+ return FALSE;
+ }
+ if (ret)
+ {
+ DWORD bytesNeeded, lenBytes;
+
+ CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+ bytesNeeded = 1 + dataLen + lenBytes;
+ if (!pbEncoded)
+ *pcbEncoded = bytesNeeded;
+ else if (*pcbEncoded < bytesNeeded)
+ {
+ SetLastError(ERROR_MORE_DATA);
+ *pcbEncoded = bytesNeeded;
+ ret = FALSE;
+ }
+ else
+ {
+ *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
+ CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+ pbEncoded += lenBytes;
+ switch (entry->dwAltNameChoice)
+ {
+ case CERT_ALT_NAME_RFC822_NAME:
+ case CERT_ALT_NAME_DNS_NAME:
+ case CERT_ALT_NAME_URL:
+ {
+ DWORD i;
+
+ for (i = 0; i < dataLen; i++)
+ *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
+ break;
+ }
+ case CERT_ALT_NAME_IP_ADDRESS:
+ memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
+ break;
+ }
+ if (ret)
+ *pcbEncoded = bytesNeeded;
+ }
+ }
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+
+ __TRY
+ {
+ const CERT_ALT_NAME_INFO *info =
+ (const CERT_ALT_NAME_INFO *)pvStructInfo;
+
+ DWORD bytesNeeded, dataLen, lenBytes, i;
+
+ ret = TRUE;
+ /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
+ * can't encode an erroneous entry index if it's bigger than this.
+ */
+ for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
+ {
+ DWORD len;
+
+ ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
+ &len);
+ if (ret)
+ dataLen += len;
+ }
+ if (ret)
+ {
+ CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+ bytesNeeded = 1 + lenBytes + dataLen;
+ if (!pbEncoded)
+ {
+ *pcbEncoded = bytesNeeded;
+ ret = TRUE;
+ }
+ else
+ {
+ if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+ pbEncoded, pcbEncoded, bytesNeeded)))
+ {
+ if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+ pbEncoded = *(BYTE **)pbEncoded;
+ *pbEncoded++ = ASN_SEQUENCEOF;
+ CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+ pbEncoded += lenBytes;
+ for (i = 0; ret && i < info->cAltEntry; i++)
+ {
+ DWORD len = dataLen;
+
+ ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
+ pbEncoded, &len);
+ if (ret)
+ {
+ pbEncoded += len;
+ dataLen -= len;
+ }
+ else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
+ {
+ /* CRYPT_AsnEncodeAltNameEntry encoded the index of
+ * the bad character, now set the index of the bad
+ * entry
+ */
+ *pcbEncoded |= (BYTE)i <<
+ CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT;
+ }
+ }
+ }
+ }
+ }
+ }
+ __EXCEPT(page_fault)
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ ret = FALSE;
+ }
+ __ENDTRY
+ return ret;
+}
+
static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
@@ -1905,10 +2230,9 @@
HMODULE lib = NULL;
CryptEncodeObjectExFunc encodeFunc = NULL;
- TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
- dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
- "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
- pcbEncoded);
+ TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
+ debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
+ pvEncoded, pcbEncoded);
if (!pvEncoded && !pcbEncoded)
{
@@ -1935,6 +2259,9 @@
case (WORD)X509_CERT_TO_BE_SIGNED:
encodeFunc = CRYPT_AsnEncodeCertInfo;
break;
+ case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
+ encodeFunc = CRYPT_AsnEncodeCRLInfo;
+ break;
case (WORD)X509_EXTENSIONS:
encodeFunc = CRYPT_AsnEncodeExtensions;
break;
@@ -1944,6 +2271,9 @@
case (WORD)X509_PUBLIC_KEY_INFO:
encodeFunc = CRYPT_AsnEncodePubKeyInfo;
break;
+ case (WORD)X509_ALTERNATE_NAME:
+ encodeFunc = CRYPT_AsnEncodeAltName;
+ break;
case (WORD)X509_BASIC_CONSTRAINTS2:
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
break;
@@ -1991,6 +2321,16 @@
encodeFunc = CRYPT_AsnEncodeOctets;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
+ else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
+ encodeFunc = CRYPT_AsnEncodeAltName;
+ else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
+ encodeFunc = CRYPT_AsnEncodeAltName;
+ else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
+ encodeFunc = CRYPT_AsnEncodeAltName;
+ else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
+ encodeFunc = CRYPT_AsnEncodeAltName;
+ else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
+ encodeFunc = CRYPT_AsnEncodeAltName;
else
TRACE("OID %s not found or unimplemented, looking for DLL\n",
debugstr_a(lpszStructType));
@@ -2015,10 +2355,9 @@
HMODULE lib;
CryptDecodeObjectFunc pCryptDecodeObject;
- TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
- dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
- "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
- pcbStructInfo);
+ TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
+ debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pcbStructInfo);
if (!pvStructInfo && !pcbStructInfo)
{
@@ -2142,6 +2481,9 @@
* 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.
* hasPointer, pointerOffset, minSize:
@@ -2165,6 +2507,9 @@
/* 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.
* FIXME: use to decode more sequences.
@@ -2172,10 +2517,13 @@
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 *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
{
BOOL ret;
+ TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld\n", items, cItem, pbEncoded,
+ cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo);
+
if (pbEncoded[0] == ASN_SEQUENCE)
{
DWORD dataLen;
@@ -2199,26 +2547,31 @@
{
BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
- ret = items[i].decodeFunc(dwCertEncodingType, NULL,
- ptr, 1 + nextItemLenBytes + nextItemLen,
- dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
- &items[i].size);
- if (ret)
+ if (items[i].decodeFunc)
{
- /* Account for alignment padding */
- bytesNeeded += items[i].size;
- if (items[i].size % sizeof(DWORD))
- bytesNeeded += sizeof(DWORD) -
- items[i].size % sizeof(DWORD);
- ptr += 1 + nextItemLenBytes + nextItemLen;
+ ret = items[i].decodeFunc(dwCertEncodingType, NULL,
+ ptr, 1 + nextItemLenBytes + nextItemLen,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
+ &items[i].size);
+ if (ret)
+ {
+ /* Account for alignment padding */
+ bytesNeeded += items[i].size;
+ if (items[i].size % sizeof(DWORD))
+ bytesNeeded += sizeof(DWORD) -
+ items[i].size % sizeof(DWORD);
+ ptr += 1 + nextItemLenBytes + nextItemLen;
+ }
+ else if (items[i].optional &&
+ GetLastError() == CRYPT_E_ASN1_BADTAG)
+ {
+ bytesNeeded += items[i].minSize;
+ SetLastError(NOERROR);
+ ret = TRUE;
+ }
}
- else if (items[i].optional &&
- GetLastError() == CRYPT_E_ASN1_BADTAG)
- {
+ else
bytesNeeded += items[i].minSize;
- SetLastError(NOERROR);
- ret = TRUE;
- }
}
}
else if (items[i].optional)
@@ -2240,7 +2593,10 @@
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
- nextData = (BYTE *)pvStructInfo + minSize;
+ if (startingPointer)
+ nextData = (BYTE *)startingPointer;
+ else
+ nextData = (BYTE *)pvStructInfo + minSize;
memset(pvStructInfo, 0, minSize);
ptr = pbEncoded + 1 + lenBytes;
for (i = 0; ret && i < cItem; i++)
@@ -2255,11 +2611,14 @@
if (items[i].hasPointer)
*(BYTE **)((BYTE *)pvStructInfo +
items[i].pointerOffset) = nextData;
- ret = items[i].decodeFunc(dwCertEncodingType, NULL,
- ptr, 1 + nextItemLenBytes + nextItemLen,
- dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
- (BYTE *)pvStructInfo + items[i].offset,
- &items[i].size);
+ if (items[i].decodeFunc)
+ ret = items[i].decodeFunc(dwCertEncodingType,
+ NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+ (BYTE *)pvStructInfo + items[i].offset,
+ &items[i].size);
+ else
+ items[i].size = items[i].minSize;
if (ret)
{
if (items[i].hasPointer &&
@@ -2296,6 +2655,7 @@
SetLastError(CRYPT_E_ASN1_BADTAG);
ret = FALSE;
}
+ TRACE("returning %d (%08lx)\n", ret, GetLastError());
return ret;
}
@@ -2379,6 +2739,9 @@
{
BOOL ret = TRUE;
+ TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+ pDecodePara, pvStructInfo, *pcbStructInfo);
+
__TRY
{
struct AsnDecodeSequenceItem items[] = {
@@ -2398,7 +2761,7 @@
items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo);
+ pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT(page_fault)
{
@@ -2451,7 +2814,7 @@
ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo);
+ pDecodePara, pvStructInfo, pcbStructInfo, NULL);
return ret;
}
@@ -2461,6 +2824,9 @@
{
BOOL ret = TRUE;
+ TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+ pDecodePara, pvStructInfo, *pcbStructInfo);
+
__TRY
{
struct AsnDecodeSequenceItem items[] = {
@@ -2489,14 +2855,14 @@
{ offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
SubjectUniqueId.pbData), 0 },
- { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeExtensions,
+ { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeExtensionsInternal,
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);
+ pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT(page_fault)
{
@@ -2507,6 +2873,188 @@
return ret;
}
+static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
+{
+ BOOL ret;
+ struct AsnDecodeSequenceItem items[] = {
+ { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
+ sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
+ SerialNumber.pbData), 0 },
+ { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
+ sizeof(FILETIME), FALSE, FALSE, 0 },
+ { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
+ sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
+ rgExtension), 0 },
+ };
+
+ TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
+ *pcbEntry);
+
+ ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
+ sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
+ NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
+ TRACE("Returning %d (%08lx)\n", ret, GetLastError());
+ return ret;
+}
+
+typedef struct _WINE_CRL_ENTRIES {
+ DWORD cCRLEntry;
+ PCRL_ENTRY rgCRLEntry;
+} WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
+
+/* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry 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;
+
+ TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+ pDecodePara, pvStructInfo, *pcbStructInfo);
+
+ if (pbEncoded[0] == ASN_SEQUENCEOF)
+ {
+ DWORD dataLen, bytesNeeded;
+
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ DWORD cCRLEntry = 0;
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+ bytesNeeded = sizeof(WINE_CRL_ENTRIES);
+ if (dataLen)
+ {
+ const BYTE *ptr;
+ DWORD size;
+
+ for (ptr = pbEncoded + 1 + lenBytes; ret &&
+ ptr - pbEncoded - 1 - lenBytes < dataLen; )
+ {
+ size = 0;
+ ret = CRYPT_AsnDecodeCRLEntry(ptr,
+ cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
+ if (ret)
+ {
+ DWORD nextLen;
+
+ cCRLEntry++;
+ bytesNeeded += size;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
+ if (ret)
+ ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+ }
+ }
+ }
+ if (ret)
+ {
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
+ pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
+ {
+ DWORD size, i;
+ BYTE *nextData;
+ const BYTE *ptr;
+ PWINE_CRL_ENTRIES entries;
+
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+ pvStructInfo = *(BYTE **)pvStructInfo;
+ *pcbStructInfo = bytesNeeded;
+ entries = (PWINE_CRL_ENTRIES)pvStructInfo;
+ entries->cCRLEntry = cCRLEntry;
+ assert(entries->rgCRLEntry);
+ nextData = (BYTE *)entries->rgCRLEntry +
+ entries->cCRLEntry * sizeof(CRL_ENTRY);
+ for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
+ i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
+ dataLen; i++)
+ {
+ entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
+ size = bytesNeeded;
+ ret = CRYPT_AsnDecodeCRLEntry(ptr,
+ cbEncoded - (ptr - pbEncoded), dwFlags,
+ &entries->rgCRLEntry[i], &size);
+ if (ret)
+ {
+ DWORD nextLen;
+
+ bytesNeeded -= size;
+ /* Increment nextData by the difference of the
+ * minimum size and the actual size.
+ */
+ if (size > sizeof(CRL_ENTRY))
+ nextData += size - sizeof(CRL_ENTRY);
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
+ if (ret)
+ ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ ret = FALSE;
+ }
+ 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[] = {
+ { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
+ sizeof(DWORD), TRUE, FALSE, 0, 0 },
+ { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
+ sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
+ SignatureAlgorithm.Parameters.pbData), 0 },
+ { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
+ sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
+ Issuer.pbData) },
+ { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
+ sizeof(FILETIME), FALSE, FALSE, 0 },
+ { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
+ sizeof(FILETIME), TRUE, FALSE, 0 },
+ { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
+ sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
+ rgCRLEntry), 0 },
+ /* Note that the extensions are ignored by MS, so I'll ignore them too
+ */
+ { 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;
+}
+
/* Warning: assumes ext->Value.pbData is set ahead of time! */
static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
@@ -2601,6 +3149,115 @@
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;
+
+ if (pbEncoded[0] == ASN_SEQUENCEOF)
+ {
+ DWORD dataLen, bytesNeeded;
+
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ DWORD cExtension = 0;
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+ bytesNeeded = sizeof(CERT_EXTENSIONS);
+ if (dataLen)
+ {
+ const BYTE *ptr;
+ DWORD size;
+
+ for (ptr = pbEncoded + 1 + lenBytes; ret &&
+ ptr - pbEncoded - 1 - lenBytes < dataLen; )
+ {
+ ret = CRYPT_AsnDecodeExtension(ptr,
+ cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
+ if (ret)
+ {
+ DWORD nextLen;
+
+ cExtension++;
+ bytesNeeded += size;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
+ if (ret)
+ ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+ }
+ }
+ }
+ if (ret)
+ {
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if (*pcbStructInfo < bytesNeeded)
+ {
+ SetLastError(ERROR_MORE_DATA);
+ *pcbStructInfo = bytesNeeded;
+ ret = FALSE;
+ }
+ else
+ {
+ DWORD size, i;
+ BYTE *nextData;
+ const BYTE *ptr;
+ CERT_EXTENSIONS *exts;
+
+ *pcbStructInfo = bytesNeeded;
+ exts = (CERT_EXTENSIONS *)pvStructInfo;
+ exts->cExtension = cExtension;
+ assert(exts->rgExtension);
+ nextData = (BYTE *)exts->rgExtension +
+ exts->cExtension * sizeof(CERT_EXTENSION);
+ for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
+ i < cExtension && ptr - pbEncoded - 1 - lenBytes <
+ dataLen; i++)
+ {
+ exts->rgExtension[i].Value.pbData = nextData;
+ size = bytesNeeded;
+ ret = CRYPT_AsnDecodeExtension(ptr,
+ cbEncoded - (ptr - pbEncoded), dwFlags,
+ &exts->rgExtension[i], &size);
+ if (ret)
+ {
+ DWORD nextLen;
+
+ bytesNeeded -= size;
+ /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
+ * data may not have been copied.
+ */
+ if (exts->rgExtension[i].Value.pbData ==
+ nextData)
+ nextData +=
+ exts->rgExtension[i].Value.cbData;
+ /* Ugly: the OID, if copied, is stored in
+ * memory after the value, so increment by its
+ * string length if it's set and points here.
+ */
+ if ((const BYTE *)exts->rgExtension[i].pszObjId
+ == nextData)
+ nextData += strlen(
+ exts->rgExtension[i].pszObjId) + 1;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
+ if (ret)
+ ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ ret = FALSE;
+ }
+ 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)
@@ -2609,104 +3266,28 @@
__TRY
{
- if (pbEncoded[0] == ASN_SEQUENCEOF)
+ ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
+ lpszStructType, pbEncoded, cbEncoded,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
+ if (ret && pvStructInfo)
{
- DWORD dataLen, bytesNeeded;
-
- if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
+ pcbStructInfo, *pcbStructInfo);
+ if (ret)
{
- DWORD cExtension = 0;
- BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+ CERT_EXTENSIONS *exts;
- bytesNeeded = sizeof(CERT_EXTENSIONS);
- if (dataLen)
- {
- const BYTE *ptr;
- DWORD size;
-
- for (ptr = pbEncoded + 1 + lenBytes; ret &&
- ptr - pbEncoded - 1 - lenBytes < dataLen; )
- {
- ret = CRYPT_AsnDecodeExtension(ptr,
- cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
- if (ret)
- {
- DWORD nextLen;
-
- cExtension++;
- bytesNeeded += size;
- ret = CRYPT_GetLen(ptr,
- cbEncoded - (ptr - pbEncoded), &nextLen);
- if (ret)
- ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
- }
- }
- }
- if (ret)
- {
- if (!pvStructInfo)
- *pcbStructInfo = bytesNeeded;
- else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
- {
- DWORD size, i;
- BYTE *nextData;
- const BYTE *ptr;
- CERT_EXTENSIONS *exts;
-
- if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
- pvStructInfo = *(BYTE **)pvStructInfo;
- *pcbStructInfo = bytesNeeded;
- exts = (CERT_EXTENSIONS *)pvStructInfo;
- exts->cExtension = cExtension;
- exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
- sizeof(CERT_EXTENSIONS));
- nextData = (BYTE *)exts->rgExtension +
- exts->cExtension * sizeof(CERT_EXTENSION);
- for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
- i < cExtension && ptr - pbEncoded - 1 - lenBytes <
- dataLen; i++)
- {
- exts->rgExtension[i].Value.pbData = nextData;
- size = bytesNeeded;
- ret = CRYPT_AsnDecodeExtension(ptr,
- cbEncoded - (ptr - pbEncoded), dwFlags,
- &exts->rgExtension[i], &size);
- if (ret)
- {
- DWORD nextLen;
-
- bytesNeeded -= size;
- /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
- * data may not have been copied.
- */
- if (exts->rgExtension[i].Value.pbData ==
- nextData)
- nextData +=
- exts->rgExtension[i].Value.cbData;
- /* Ugly: the OID, if copied, is stored in
- * memory after the value, so increment by its
- * string length if it's set and points here.
- */
- if ((const BYTE *)exts->rgExtension[i].pszObjId
- == nextData)
- nextData += strlen(
- exts->rgExtension[i].pszObjId) + 1;
- ret = CRYPT_GetLen(ptr,
- cbEncoded - (ptr - pbEncoded), &nextLen);
- if (ret)
- ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
- }
- }
- }
- }
+ 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);
}
}
- else
- {
- SetLastError(CRYPT_E_ASN1_BADTAG);
- ret = FALSE;
- }
}
__EXCEPT(page_fault)
{
@@ -3410,7 +3991,7 @@
ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo);
+ pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT(page_fault)
{
@@ -3466,6 +4047,211 @@
return ret;
}
+static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
+{
+ DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
+ BOOL ret;
+
+ 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)
+ *pcbEntry = bytesNeeded;
+ else if (*pcbEntry < bytesNeeded)
+ {
+ SetLastError(ERROR_MORE_DATA);
+ ret = FALSE;
+ }
+ else
+ {
+ /* 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;
+ 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_AsnDecodeAltName(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 dataLen;
+
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ DWORD bytesNeeded, cEntry = 0;
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+ bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
+ if (dataLen)
+ {
+ const BYTE *ptr;
+
+ for (ptr = pbEncoded + 1 + lenBytes; ret &&
+ ptr - pbEncoded - 1 - lenBytes < dataLen; )
+ {
+ DWORD size;
+
+ ret = CRYPT_AsnDecodeAltNameEntry(ptr,
+ cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
+ if (ret)
+ {
+ DWORD nextLen;
+
+ cEntry++;
+ bytesNeeded += size;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
+ if (ret)
+ ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+ }
+ }
+ }
+ if (ret)
+ {
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
+ pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
+ {
+ CERT_ALT_NAME_INFO *info;
+
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+ pvStructInfo = *(BYTE **)pvStructInfo;
+ info = (CERT_ALT_NAME_INFO *)pvStructInfo;
+ info->cAltEntry = 0;
+ if (cEntry == 0)
+ info->rgAltEntry = NULL;
+ else
+ {
+ DWORD size, i;
+ BYTE *nextData;
+ const BYTE *ptr;
+
+ info->rgAltEntry =
+ (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
+ sizeof(CERT_ALT_NAME_INFO));
+ nextData = (BYTE *)info->rgAltEntry +
+ cEntry * sizeof(CERT_ALT_NAME_ENTRY);
+ for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
+ i < cEntry && ptr - pbEncoded - 1 - lenBytes <
+ dataLen; i++)
+ {
+ info->rgAltEntry[i].u.pwszURL = (LPWSTR)nextData;
+ size = bytesNeeded;
+ ret = CRYPT_AsnDecodeAltNameEntry(ptr,
+ cbEncoded - (ptr - pbEncoded), dwFlags,
+ &info->rgAltEntry[i], &size);
+ if (ret)
+ {
+ DWORD nextLen;
+
+ info->cAltEntry++;
+ nextData += size -
+ sizeof(CERT_ALT_NAME_ENTRY);
+ bytesNeeded -= size;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
+ if (ret)
+ ptr += nextLen + 1 +
+ GET_LEN_BYTES(ptr[1]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ ret = FALSE;
+ }
+ }
+ __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)
@@ -3634,8 +4420,8 @@
{
BOOL ret;
- TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo);
+ TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
+ pDecodePara, pvStructInfo, *pcbStructInfo);
if (pbEncoded[0] == ASN_BITSTRING)
{
@@ -3825,8 +4611,10 @@
DWORD i;
for (i = 0; i < blob->cbData; i++)
+ {
blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
dataLen - i - 1);
+ }
}
}
}
@@ -4287,12 +5075,6 @@
{
BOOL ret;
- if (!pvStructInfo)
- {
- *pcbStructInfo = sizeof(FILETIME);
- return TRUE;
- }
-
__TRY
{
if (pbEncoded[0] == ASN_UTCTIME)
@@ -4430,9 +5212,8 @@
CryptDecodeObjectExFunc decodeFunc = NULL;
TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
- dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
- "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
- pvStructInfo, pcbStructInfo);
+ dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
+ cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
if (!pvStructInfo && !pcbStructInfo)
{
@@ -4469,6 +5250,9 @@
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;
@@ -4478,6 +5262,9 @@
case (WORD)X509_PUBLIC_KEY_INFO:
decodeFunc = CRYPT_AsnDecodePubKeyInfo;
break;
+ case (WORD)X509_ALTERNATE_NAME:
+ decodeFunc = CRYPT_AsnDecodeAltName;
+ break;
case (WORD)X509_BASIC_CONSTRAINTS2:
decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
break;
@@ -4525,6 +5312,16 @@
decodeFunc = CRYPT_AsnDecodeOctets;
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
TRACE("OID %s not found or unimplemented, looking for DLL\n",
debugstr_a(lpszStructType));
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
index bb67705..daa014f 100644
--- a/dlls/crypt32/tests/encode.c
+++ b/dlls/crypt32/tests/encode.c
@@ -833,6 +833,229 @@
}
}
+static const BYTE emptyAltName[] = { 0x30, 0x00 };
+static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
+static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
+ 'h','q','.','o','r','g',0 };
+static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
+ 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
+ 0x6f, 0x72, 0x67 };
+static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
+static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
+ 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
+static const BYTE localhost[] = { 127, 0, 0, 1 };
+static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
+ 0x01 };
+
+static void printBytes(const char *hdr, const BYTE *pb, size_t cb)
+{
+ size_t i;
+
+ printf("%s:\n", hdr);
+ for (i = 0; i < cb; i++)
+ printf("%02x ", pb[i]);
+ putchar('\n');
+}
+
+static void test_encodeAltName(DWORD dwEncoding)
+{
+ static const WCHAR nihongo[] = { 0x226f, 0x575b, 0 };
+ CERT_ALT_NAME_INFO info = { 0 };
+ CERT_ALT_NAME_ENTRY entry = { 0 };
+ BYTE *buf = NULL;
+ DWORD size = 0;
+ BOOL ret;
+
+ /* Test with empty info */
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ if (buf)
+ {
+ ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n",
+ sizeof(emptyAltName), size);
+ ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n");
+ LocalFree(buf);
+ }
+ /* Test with an empty entry */
+ info.cAltEntry = 1;
+ info.rgAltEntry = &entry;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
+ "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
+ GetLastError());
+ /* Test with an empty pointer */
+ entry.dwAltNameChoice = CERT_ALT_NAME_URL;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ if (buf)
+ {
+ ok(size == sizeof(emptyURL), "Expected size %d, got %ld\n",
+ sizeof(emptyURL), size);
+ ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
+ LocalFree(buf);
+ }
+ /* Test with a real URL */
+ U(entry).pwszURL = (LPWSTR)url;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ if (buf)
+ {
+ ok(size == sizeof(encodedURL), "Expected size %d, got %ld\n",
+ sizeof(encodedURL), size);
+ ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
+ LocalFree(buf);
+ }
+ /* Now with the URL containing an invalid IA5 char */
+ U(entry).pwszURL = (LPWSTR)nihongo;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
+ "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
+ /* Now with the URL missing a scheme */
+ U(entry).pwszURL = (LPWSTR)dnsName;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ /* This succeeds, but it shouldn't, so don't worry about conforming */
+ LocalFree(buf);
+ }
+ /* Now with a DNS name */
+ entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ ok(size == sizeof(encodedDnsName), "Expected size %d, got %ld\n",
+ sizeof(encodedDnsName), size);
+ ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
+ LocalFree(buf);
+ }
+ /* Test with an IP address */
+ entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
+ U(entry).IPAddress.cbData = sizeof(localhost);
+ U(entry).IPAddress.pbData = (LPBYTE)localhost;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ if (buf)
+ {
+ ok(size == sizeof(encodedIPAddr), "Expected size %d, got %ld\n",
+ sizeof(encodedIPAddr), size);
+ ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
+ LocalFree(buf);
+ }
+}
+
+static void test_decodeAltName(DWORD dwEncoding)
+{
+ static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
+ 0x00, 0x00, 0x01 };
+ static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
+ 0x01 };
+ BOOL ret;
+ BYTE *buf = NULL;
+ DWORD bufSize = 0;
+ CERT_ALT_NAME_INFO *info;
+
+ /* Test some bogus ones first */
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
+ unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
+ NULL, (BYTE *)&buf, &bufSize);
+ ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
+ "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
+ bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
+ &bufSize);
+ ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
+ "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
+ /* Now expected cases */
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName,
+ emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
+ &bufSize);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ info = (CERT_ALT_NAME_INFO *)buf;
+
+ ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
+ info->cAltEntry);
+ LocalFree(buf);
+ }
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
+ emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
+ &bufSize);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ info = (CERT_ALT_NAME_INFO *)buf;
+
+ ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
+ info->cAltEntry);
+ ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
+ "Expected CERT_ALT_NAME_URL, got %ld\n",
+ info->rgAltEntry[0].dwAltNameChoice);
+ ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
+ "Expected empty URL\n");
+ LocalFree(buf);
+ }
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
+ encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
+ &bufSize);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ info = (CERT_ALT_NAME_INFO *)buf;
+
+ ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
+ info->cAltEntry);
+ ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
+ "Expected CERT_ALT_NAME_URL, got %ld\n",
+ info->rgAltEntry[0].dwAltNameChoice);
+ ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
+ LocalFree(buf);
+ }
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
+ encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
+ &bufSize);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ info = (CERT_ALT_NAME_INFO *)buf;
+
+ ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
+ info->cAltEntry);
+ ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
+ "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
+ info->rgAltEntry[0].dwAltNameChoice);
+ ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
+ "Unexpected DNS name\n");
+ LocalFree(buf);
+ }
+ ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
+ encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
+ &bufSize);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ info = (CERT_ALT_NAME_INFO *)buf;
+
+ ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
+ info->cAltEntry);
+ ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
+ "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
+ info->rgAltEntry[0].dwAltNameChoice);
+ ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
+ "Unexpected IP address length %ld\n",
+ U(info->rgAltEntry[0]).IPAddress.cbData);
+ ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
+ sizeof(localhost)), "Unexpected IP address value\n");
+ LocalFree(buf);
+ }
+}
+
struct encodedOctets
{
const BYTE *val;
@@ -1589,13 +1812,16 @@
/* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
* minimum a cert must have a non-zero serial number, an issuer, and a
* subject.
+ * It's hard to match the errors precisely sometimes, so accept one
+ * that only wine gives as long as it fails
*/
for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
(BYTE *)&buf, &size);
- ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
+ ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT ||
+ GetLastError() == CRYPT_E_ASN1_BADTAG),
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
}
/* Now check with serial number, subject and issuer specified */
@@ -1695,6 +1921,244 @@
}
}
+static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
+ 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x5a };
+static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
+ 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x5a };
+static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
+ 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
+ 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
+ 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5a };
+static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
+ 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
+ 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
+ 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
+static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
+ 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
+ 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
+ 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
+static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
+ 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
+ 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
+ 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+ 0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
+ 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
+ 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
+ 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
+
+static void test_encodeCRLToBeSigned(DWORD dwEncoding)
+{
+ BOOL ret;
+ BYTE *buf = NULL;
+ DWORD size = 0;
+ CRL_INFO info = { 0 };
+ CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
+
+ /* Test with a V1 CRL */
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ ok(size == sizeof(v1CRL), "Expected size %d, got %ld\n",
+ sizeof(v1CRL), size);
+ ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
+ LocalFree(buf);
+ }
+ /* Test v2 CRL */
+ info.dwVersion = CRL_V2;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
+ v2CRL[1] + 2, size);
+ ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
+ LocalFree(buf);
+ }
+ /* v1 CRL with a name */
+ info.dwVersion = CRL_V1;
+ info.Issuer.cbData = sizeof(encodedCommonName);
+ info.Issuer.pbData = (BYTE *)encodedCommonName;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ ok(size == sizeof(v1CRLWithIssuer), "Expected size %d, got %ld\n",
+ sizeof(v1CRLWithIssuer), size);
+ ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
+ LocalFree(buf);
+ }
+ /* v1 CRL with a name and a NULL entry pointer */
+ info.cCRLEntry = 1;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
+ "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
+ /* now set an empty entry */
+ info.rgCRLEntry = &entry;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ if (buf)
+ {
+ ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
+ "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEmptyEntry),
+ size);
+ ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
+ "Got unexpected value\n");
+ LocalFree(buf);
+ }
+ /* an entry with a serial number */
+ entry.SerialNumber.cbData = sizeof(serialNum);
+ entry.SerialNumber.pbData = (BYTE *)serialNum;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ if (buf)
+ {
+ ok(size == sizeof(v1CRLWithIssuerAndEntry),
+ "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEntry), size);
+ ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
+ "Got unexpected value\n");
+ LocalFree(buf);
+ }
+ /* and finally, an entry with an extension */
+ entry.cExtension = 1;
+ entry.rgExtension = &criticalExt;
+ ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ ok(size == sizeof(v1CRLWithExt), "Expected size %d, got %ld\n",
+ sizeof(v1CRLWithExt), size);
+ ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
+ LocalFree(buf);
+ }
+}
+
+static void test_decodeCRLToBeSigned(DWORD dwEncoding)
+{
+ static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
+ BOOL ret;
+ BYTE *buf = NULL;
+ DWORD size = 0, i;
+
+ for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
+ {
+ ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
+ corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
+ (BYTE *)&buf, &size);
+ /* It's hard to match the errors precisely sometimes, so accept one
+ * that only wine gives as long as it fails
+ */
+ ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT ||
+ GetLastError() == CRYPT_E_ASN1_BADTAG),
+ "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
+ }
+ /* at a minimum, a CRL must contain an issuer: */
+ ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
+ v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
+ (BYTE *)&buf, &size);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ CRL_INFO *info = (CRL_INFO *)buf;
+
+ ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
+ sizeof(CRL_INFO), size);
+ ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
+ info->cCRLEntry);
+ ok(info->Issuer.cbData == sizeof(encodedCommonName),
+ "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
+ info->Issuer.cbData);
+ ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
+ "Unexpected issuer\n");
+ LocalFree(buf);
+ }
+ /* check decoding with an empty CRL entry */
+ ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
+ v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
+ "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
+ /* with a real CRL entry */
+ ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
+ v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ CRL_INFO *info = (CRL_INFO *)buf;
+ CRL_ENTRY *entry;
+
+ ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
+ sizeof(CRL_INFO), size);
+ ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
+ info->cCRLEntry);
+ ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
+ entry = info->rgCRLEntry;
+ ok(entry->SerialNumber.cbData == 1,
+ "Expected serial number size 1, got %ld\n",
+ entry->SerialNumber.cbData);
+ ok(*entry->SerialNumber.pbData == *serialNum,
+ "Expected serial number %d, got %d\n", *serialNum,
+ *entry->SerialNumber.pbData);
+ ok(info->Issuer.cbData == sizeof(encodedCommonName),
+ "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
+ info->Issuer.cbData);
+ ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
+ "Unexpected issuer\n");
+ if (memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData))
+ {
+ printBytes("Expected", encodedCommonName,
+ sizeof(encodedCommonName));
+ printBytes("Got", info->Issuer.pbData, info->Issuer.cbData);
+ }
+ }
+ /* and finally, with an extension */
+ ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
+ v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
+ NULL, (BYTE *)&buf, &size);
+ ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
+ if (buf)
+ {
+ CRL_INFO *info = (CRL_INFO *)buf;
+ CRL_ENTRY *entry;
+
+ ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
+ sizeof(CRL_INFO), size);
+ ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
+ info->cCRLEntry);
+ ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
+ entry = info->rgCRLEntry;
+ ok(entry->SerialNumber.cbData == 1,
+ "Expected serial number size 1, got %ld\n",
+ entry->SerialNumber.cbData);
+ ok(*entry->SerialNumber.pbData == *serialNum,
+ "Expected serial number %d, got %d\n", *serialNum,
+ *entry->SerialNumber.pbData);
+ ok(info->Issuer.cbData == sizeof(encodedCommonName),
+ "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
+ info->Issuer.cbData);
+ ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
+ "Unexpected issuer\n");
+ /* Oddly, the extensions don't seem to be decoded. Is this just an MS
+ * bug, or am I missing something?
+ */
+ ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
+ info->cExtension);
+ }
+}
+
static void test_registerOIDFunction(void)
{
static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
@@ -1765,6 +2229,8 @@
test_decodeFiletime(encodings[i]);
test_encodeName(encodings[i]);
test_decodeName(encodings[i]);
+ test_encodeAltName(encodings[i]);
+ test_decodeAltName(encodings[i]);
test_encodeOctets(encodings[i]);
test_decodeOctets(encodings[i]);
test_encodeBits(encodings[i]);
@@ -1781,6 +2247,8 @@
test_decodeCertToBeSigned(encodings[i]);
test_encodeCert(encodings[i]);
test_decodeCert(encodings[i]);
+ test_encodeCRLToBeSigned(encodings[i]);
+ test_decodeCRLToBeSigned(encodings[i]);
}
test_registerOIDFunction();
}