typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
+typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
+ DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
needed = bytes + pad_bytes + 1;
- needed += (needed / 64 + 1) * strlen(sep);
+ if (sep)
+ needed += (needed / 64 + 1) * strlen(sep);
if (needed > *out_len)
{
i = 0;
while (div > 0)
{
- if (i && i % 64 == 0)
+ if (sep && i && i % 64 == 0)
{
strcpy(ptr, sep);
ptr += strlen(sep);
*ptr++ = '=';
break;
}
- strcpy(ptr, sep);
+ if (sep)
+ strcpy(ptr, sep);
return ERROR_SUCCESS;
}
{
static const char crlf[] = "\r\n", lf[] = "\n";
BOOL ret = TRUE;
- LPCSTR header = NULL, trailer = NULL, sep = NULL;
+ LPCSTR header = NULL, trailer = NULL, sep;
DWORD charsNeeded;
if (dwFlags & CRYPT_STRING_NOCR)
sep = lf;
+ else if (dwFlags & CRYPT_STRING_NOCRLF)
+ sep = NULL;
else
sep = crlf;
- switch (dwFlags & 0x7fffffff)
+ switch (dwFlags & 0x0fffffff)
{
case CRYPT_STRING_BASE64:
/* no header or footer */
charsNeeded = 0;
encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
- charsNeeded += strlen(sep);
+ if (sep)
+ charsNeeded += strlen(sep);
if (header)
charsNeeded += strlen(header) + strlen(sep);
if (trailer)
{
strcpy(ptr, header);
ptr += strlen(ptr);
- strcpy(ptr, sep);
- ptr += strlen(sep);
+ if (sep)
+ {
+ strcpy(ptr, sep);
+ ptr += strlen(sep);
+ }
}
encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
ptr += size - 1;
{
strcpy(ptr, trailer);
ptr += strlen(ptr);
- strcpy(ptr, sep);
- ptr += strlen(sep);
+ if (sep)
+ {
+ strcpy(ptr, sep);
+ ptr += strlen(sep);
+ }
}
*pcchString = charsNeeded - 1;
}
return FALSE;
}
- switch (dwFlags & 0x7fffffff)
+ switch (dwFlags & 0x0fffffff)
{
case CRYPT_STRING_BINARY:
encoder = EncodeBinaryToBinaryA;
case CRYPT_STRING_HEXASCII:
case CRYPT_STRING_HEXADDR:
case CRYPT_STRING_HEXASCIIADDR:
- FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
+ FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
+ /* fall through */
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
+}
+
+static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
+ WCHAR* 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;
+ LPWSTR ptr;
+
+ TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
+ needed = bytes + pad_bytes + 1;
+ if (sep)
+ needed += (needed / 64 + 1) * strlenW(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 (sep && i && i % 64 == 0)
+ {
+ strcpyW(ptr, sep);
+ ptr += strlenW(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;
+ }
+ if (sep)
+ strcpyW(ptr, sep);
+
+ return ERROR_SUCCESS;
+}
+
+static BOOL BinaryToBase64W(const BYTE *pbBinary,
+ DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
+{
+ static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 };
+ BOOL ret = TRUE;
+ LPCWSTR header = NULL, trailer = NULL, sep;
+ DWORD charsNeeded;
+
+ if (dwFlags & CRYPT_STRING_NOCR)
+ sep = lf;
+ else if (dwFlags & CRYPT_STRING_NOCRLF)
+ sep = NULL;
+ else
+ sep = crlf;
+ switch (dwFlags & 0x0fffffff)
+ {
+ case CRYPT_STRING_BASE64:
+ /* no header or footer */
+ break;
+ case CRYPT_STRING_BASE64HEADER:
+ header = CERT_HEADER_W;
+ trailer = CERT_TRAILER_W;
+ break;
+ case CRYPT_STRING_BASE64REQUESTHEADER:
+ header = CERT_REQUEST_HEADER_W;
+ trailer = CERT_REQUEST_TRAILER_W;
+ break;
+ case CRYPT_STRING_BASE64X509CRLHEADER:
+ header = X509_HEADER_W;
+ trailer = X509_TRAILER_W;
+ break;
+ }
+
+ charsNeeded = 0;
+ encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
+ if (sep)
+ charsNeeded += strlenW(sep);
+ if (header)
+ charsNeeded += strlenW(header) + strlenW(sep);
+ if (trailer)
+ charsNeeded += strlenW(trailer) + strlenW(sep);
+ if (charsNeeded <= *pcchString)
+ {
+ LPWSTR ptr = pszString;
+ DWORD size = charsNeeded;
+
+ if (header)
+ {
+ strcpyW(ptr, header);
+ ptr += strlenW(ptr);
+ if (sep)
+ {
+ strcpyW(ptr, sep);
+ ptr += strlenW(sep);
+ }
+ }
+ encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
+ ptr += size - 1;
+ if (trailer)
+ {
+ strcpyW(ptr, trailer);
+ ptr += strlenW(ptr);
+ if (sep)
+ {
+ strcpyW(ptr, sep);
+ ptr += strlenW(sep);
+ }
+ }
+ *pcchString = charsNeeded - 1;
+ }
+ else if (pszString)
+ {
+ *pcchString = charsNeeded;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ ret = FALSE;
+ }
+ else
+ *pcchString = charsNeeded;
+ return ret;
+}
+
+BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
+ DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
+{
+ BinaryToStringWFunc encoder = NULL;
+
+ TRACE("(%p, %d, %08x, %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 & 0x0fffffff)
+ {
+ case CRYPT_STRING_BASE64:
+ case CRYPT_STRING_BASE64HEADER:
+ case CRYPT_STRING_BASE64REQUESTHEADER:
+ case CRYPT_STRING_BASE64X509CRLHEADER:
+ encoder = BinaryToBase64W;
+ break;
+ case CRYPT_STRING_BINARY:
+ case CRYPT_STRING_HEX:
+ case CRYPT_STRING_HEXASCII:
+ case CRYPT_STRING_HEXADDR:
+ case CRYPT_STRING_HEXASCIIADDR:
+ FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
/* fall through */
default:
SetLastError(ERROR_INVALID_PARAMETER);
return ret;
}
+BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
+ const BYTE *pbCertEncoded, DWORD cbCertEncoded)
+{
+ HCERTSTORE store;
+ BOOL ret = FALSE;
+
+ TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
+ cbCertEncoded);
+
+ store = CertOpenSystemStoreA(0, pszCertStoreName);
+ if (store)
+ {
+ ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
+ pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
+ CertCloseStore(store, 0);
+ }
+ return ret;
+}
+
+BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
+ const BYTE *pbCertEncoded, DWORD cbCertEncoded)
+{
+ HCERTSTORE store;
+ BOOL ret = FALSE;
+
+ TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
+ cbCertEncoded);
+
+ store = CertOpenSystemStoreW(0, pszCertStoreName);
+ if (store)
+ {
+ ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
+ pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
+ CertCloseStore(store, 0);
+ }
+ return ret;
+}
+
+BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
+ PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
+ PCCERT_CONTEXT *ppCertContext)
+{
+ FIXME("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition,
+ ppCertContext);
+ return FALSE;
+}
+
PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
const BYTE *pbCertEncoded, DWORD cbCertEncoded)
{
BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
{
+ BOOL ret = TRUE;
+
TRACE("(%p)\n", pCertContext);
if (pCertContext)
- Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
+ ret = Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
CertDataContext_Free);
- return TRUE;
+ return ret;
}
DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
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)
{
/* Matching serial number and subject match.. */
ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
- &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
+ &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
if (ret)
ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
&pCertInfo->SerialNumber);
&pCertInfo->SerialNumber);
if (ret)
ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
- &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer);
+ &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
}
TRACE("returning %d\n", ret);
return ret;
return ret;
}
-static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType,
+static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
DWORD dwFlags, const void *pvPara)
{
- BOOL ret = FALSE;
- PCCERT_CONTEXT subject = pvPara;
+ PCCERT_CONTEXT toCompare = pvPara;
+ return CertCompareCertificate(pCertContext->dwCertEncodingType,
+ pCertContext->pCertInfo, toCompare->pCertInfo);
+}
+
+static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
+ DWORD dwFlags, const void *pvPara)
+{
+ const CRYPT_HASH_BLOB *hash = pvPara;
+ DWORD size = 0;
+ BOOL ret;
+
+ ret = CertGetCertificateContextProperty(pCertContext,
+ CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
+ if (ret && size == hash->cbData)
+ {
+ LPBYTE buf = CryptMemAlloc(size);
+
+ if (buf)
+ {
+ CertGetCertificateContextProperty(pCertContext,
+ CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
+ ret = !memcmp(buf, hash->pbData, size);
+ CryptMemFree(buf);
+ }
+ }
+ else
+ ret = FALSE;
+ return ret;
+}
+
+static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
+ PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
+ const void *pvPara)
+{
+ BOOL matches = FALSE;
+ PCCERT_CONTEXT ret;
+
+ ret = prev;
+ do {
+ ret = CertEnumCertificatesInStore(store, ret);
+ if (ret)
+ matches = compare(ret, dwType, dwFlags, pvPara);
+ } while (ret != NULL && !matches);
+ return ret;
+}
+
+typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
+ DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
+
+static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
+ DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
+{
+ return CertEnumCertificatesInStore(store, prev);
+}
+
+static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
+ DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
+{
+ BOOL ret;
+ PCCERT_CONTEXT found = NULL, subject = pvPara;
PCERT_EXTENSION ext;
DWORD size;
sizeof(CERT_NAME_BLOB));
memcpy(&id.u.IssuerSerialNumber.SerialNumber,
&info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
- ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
- &id);
}
else if (info->KeyId.cbData)
{
id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
- ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
- &id);
}
else
ret = FALSE;
+ if (ret)
+ found = cert_compare_certs_in_store(store, prev,
+ compare_cert_by_cert_id, dwType, dwFlags, &id);
LocalFree(info);
}
}
memcpy(&id.u.IssuerSerialNumber.SerialNumber,
&info->AuthorityCertSerialNumber,
sizeof(CRYPT_INTEGER_BLOB));
- ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
- &id);
}
else
{
{
id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
- ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
- &id);
}
else
ret = FALSE;
+ if (ret)
+ found = cert_compare_certs_in_store(store, prev,
+ compare_cert_by_cert_id, dwType, dwFlags, &id);
LocalFree(info);
}
}
else
- ret = compare_cert_by_name(pCertContext,
- CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, dwFlags,
- &subject->pCertInfo->Issuer);
- return ret;
+ found = cert_compare_certs_in_store(store, prev,
+ compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
+ dwFlags, &subject->pCertInfo->Issuer);
+ return found;
}
-static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara)
+static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
+ DWORD dwType, DWORD dwFlags, const void *pvPara)
{
- PCCERT_CONTEXT toCompare = pvPara;
- return CertCompareCertificate(pCertContext->dwCertEncodingType,
- pCertContext->pCertInfo, toCompare->pCertInfo);
+ PCERT_NAME_BLOB name;
+ DWORD len;
+ BOOL ret = FALSE;
+
+ if (dwType & CERT_INFO_SUBJECT_FLAG)
+ name = &pCertContext->pCertInfo->Subject;
+ else
+ name = &pCertContext->pCertInfo->Issuer;
+ len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
+ CERT_SIMPLE_NAME_STR, NULL, 0);
+ if (len)
+ {
+ LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
+
+ if (str)
+ {
+ LPWSTR ptr;
+
+ CertNameToStrW(pCertContext->dwCertEncodingType, name,
+ CERT_SIMPLE_NAME_STR, str, len);
+ for (ptr = str; *ptr; ptr++)
+ *ptr = tolowerW(*ptr);
+ if (strstrW(str, pvPara))
+ ret = TRUE;
+ CryptMemFree(str);
+ }
+ }
+ return ret;
}
-static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara)
+static PCCERT_CONTEXT find_cert_by_name_str(HCERTSTORE store, DWORD dwType,
+ DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
{
- const CRYPT_HASH_BLOB *hash = pvPara;
- DWORD size = 0;
- BOOL ret;
+ PCCERT_CONTEXT found = NULL;
- ret = CertGetCertificateContextProperty(pCertContext,
- CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
- if (ret && size == hash->cbData)
+ TRACE("%s\n", debugstr_w(pvPara));
+
+ if (pvPara)
{
- LPBYTE buf = CryptMemAlloc(size);
+ DWORD len = strlenW(pvPara);
+ LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
- if (buf)
+ if (str)
{
- CertGetCertificateContextProperty(pCertContext,
- CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
- ret = !memcmp(buf, hash->pbData, size);
- CryptMemFree(buf);
+ LPCWSTR src;
+ LPWSTR dst;
+
+ for (src = pvPara, dst = str; *src; src++, dst++)
+ *dst = tolowerW(*src);
+ *dst = 0;
+ found = cert_compare_certs_in_store(store, prev,
+ compare_cert_by_name_str, dwType, dwFlags, str);
+ CryptMemFree(str);
}
}
else
- ret = FALSE;
- return ret;
+ found = find_cert_any(store, dwType, dwFlags, NULL, prev);
+ return found;
}
PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
PCCERT_CONTEXT pPrevCertContext)
{
PCCERT_CONTEXT ret;
- CertCompareFunc compare;
+ CertFindFunc find = NULL;
+ CertCompareFunc compare = NULL;
TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
dwFlags, dwType, pvPara, pPrevCertContext);
switch (dwType >> CERT_COMPARE_SHIFT)
{
case CERT_COMPARE_ANY:
- compare = compare_cert_any;
+ find = find_cert_any;
break;
case CERT_COMPARE_MD5_HASH:
compare = compare_cert_by_md5_hash;
case CERT_COMPARE_PUBLIC_KEY:
compare = compare_cert_by_public_key;
break;
+ case CERT_COMPARE_NAME_STR_W:
+ find = find_cert_by_name_str;
+ break;
case CERT_COMPARE_SUBJECT_CERT:
compare = compare_cert_by_subject_cert;
break;
compare = compare_cert_by_cert_id;
break;
case CERT_COMPARE_ISSUER_OF:
- compare = compare_cert_by_issuer;
+ find = find_cert_by_issuer;
break;
case CERT_COMPARE_EXISTING:
compare = compare_existing_cert;
break;
default:
FIXME("find type %08x 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);
- }
+ if (find)
+ ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
+ else if (compare)
+ ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
+ compare, dwType, dwFlags, pvPara);
else
- {
- SetLastError(CRYPT_E_NOT_FOUND);
ret = NULL;
- }
+ if (!ret)
+ SetLastError(CRYPT_E_NOT_FOUND);
TRACE("returning %p\n", ret);
return ret;
}
hCryptProv = CRYPT_GetDefaultProvider();
if (!Algid)
Algid = CALG_MD5;
+ if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return FALSE;
+ }
if (ret)
{
BYTE *buf;
DWORD size = 0;
- ret = CryptEncodeObjectEx(dwCertEncodingType, X509_PUBLIC_KEY_INFO,
- pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
+ ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
+ X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
+ (LPBYTE)&buf, &size);
if (ret)
{
ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
return ret;
}
+BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
+ PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
+{
+ PCERT_EXTENSION ext;
+ BOOL ret = FALSE;
+
+ TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
+ cbKeyUsage);
+
+ ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
+ pCertInfo->rgExtension);
+ if (ext)
+ {
+ CRYPT_BIT_BLOB usage;
+ DWORD size = sizeof(usage);
+
+ ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
+ ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
+ &usage, &size);
+ if (ret)
+ {
+ if (cbKeyUsage < usage.cbData)
+ ret = FALSE;
+ else
+ {
+ memcpy(pbKeyUsage, usage.pbData, usage.cbData);
+ if (cbKeyUsage > usage.cbData)
+ memset(pbKeyUsage + usage.cbData, 0,
+ cbKeyUsage - usage.cbData);
+ }
+ }
+ }
+ else
+ SetLastError(0);
+ return ret;
+}
+
BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
{
assert(pSubjectIssuerBlob);
assert(pubKey);
- info->dwVersion = CERT_V3;
+ if (pExtensions && pExtensions->cExtension)
+ info->dwVersion = CERT_V3;
+ else
+ info->dwVersion = CERT_V1;
info->SerialNumber.cbData = pSerialNumber->cbData;
info->SerialNumber.pbData = pSerialNumber->pbData;
if (pSignatureAlgorithm)
static const WCHAR rootW[] = { 'R','o','o','t',0 };
+/* Finds cert in store by comparing the cert's hashes. */
+static PCCERT_CONTEXT CRYPT_FindCertInStore(HCERTSTORE store,
+ PCCERT_CONTEXT cert)
+{
+ PCCERT_CONTEXT matching = NULL;
+ BYTE hash[20];
+ DWORD size = sizeof(hash);
+
+ if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash, &size))
+ {
+ CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
+
+ matching = CertFindCertificateInStore(store, cert->dwCertEncodingType,
+ 0, CERT_FIND_SHA1_HASH, &blob, NULL);
+ }
+ return matching;
+}
+
static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store)
{
BOOL ret = TRUE;
{
HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW);
PCCERT_CONTEXT cert = NULL, check;
- BYTE hash[20];
- DWORD size;
do {
cert = CertEnumCertificatesInStore(store, cert);
if (cert)
{
- size = sizeof(hash);
-
- ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
- hash, &size);
- if (ret)
- {
- CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
-
- check = CertFindCertificateInStore(rootStore,
- cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
- NULL);
- if (!check)
- ret = FALSE;
- else
- CertFreeCertificateContext(check);
- }
+ if (!(check = CRYPT_FindCertInStore(rootStore, cert)))
+ ret = FALSE;
+ else
+ CertFreeCertificateContext(check);
}
} while (ret && cert);
if (cert)
static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot,
PCERT_CHAIN_ELEMENT rootElement)
{
- BYTE hash[20];
- DWORD size = sizeof(hash);
- CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
- PCCERT_CONTEXT trustedRoot;
-
- CertGetCertificateContextProperty(rootElement->pCertContext,
- CERT_HASH_PROP_ID, hash, &size);
- trustedRoot = CertFindCertificateInStore(hRoot,
- rootElement->pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
- &blob, NULL);
+ PCCERT_CONTEXT trustedRoot = CRYPT_FindCertInStore(hRoot,
+ rootElement->pCertContext);
+
if (!trustedRoot)
rootElement->TrustStatus.dwErrorStatus |=
CERT_TRUST_IS_UNTRUSTED_ROOT;
}
/* Checks element's basic constraints to see if it can act as a CA, with
- * remainingCAs CAs left in this chain. A root certificate is assumed to be
- * allowed to be a CA whether or not the basic constraints extension is present,
- * whereas an intermediate CA cert is not. This matches the expected usage in
- * RFC 3280: a conforming intermediate CA MUST contain the basic constraints
- * extension. It also appears to match Microsoft's implementation.
+ * remainingCAs CAs left in this chain. In general, a cert must include the
+ * basic constraints extension, with the CA flag asserted, in order to be
+ * allowed to be a CA. A V1 or V2 cert, which has no extensions, is also
+ * allowed to be a CA if it's installed locally (in the engine's world store.)
+ * This matches the expected usage in RFC 5280, section 4.2.1.9: a conforming
+ * CA MUST include the basic constraints extension in all certificates that are
+ * used to validate digital signatures on certificates. It also matches
+ * section 6.1.4(k): "If a certificate is a v1 or v2 certificate, then the
+ * application MUST either verify that the certificate is a CA certificate
+ * through out-of-band means or reject the certificate." Rejecting the
+ * certificate prohibits a large number of commonly used certificates, so
+ * accepting locally installed ones is a compromise.
+ * Root certificates are also allowed to be CAs even without a basic
+ * constraints extension. This is implied by RFC 5280, section 6.1: the
+ * root of a certificate chain's only requirement is that it was used to issue
+ * the next certificate in the chain.
* Updates chainConstraints with the element's constraints, if:
* 1. chainConstraints doesn't have a path length constraint, or
* 2. element's path length constraint is smaller than chainConstraints's
* Returns TRUE if the element can be a CA, and the length of the remaining
* chain is valid.
*/
-static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
- CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
- BOOL isRoot, BOOL *pathLengthConstraintViolated)
+static BOOL CRYPT_CheckBasicConstraintsForCA(PCertificateChainEngine engine,
+ PCCERT_CONTEXT cert, CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints,
+ DWORD remainingCAs, BOOL isRoot, BOOL *pathLengthConstraintViolated)
{
- BOOL validBasicConstraints;
+ BOOL validBasicConstraints, implicitCA = FALSE;
CERT_BASIC_CONSTRAINTS2_INFO constraints;
+ if (isRoot)
+ implicitCA = TRUE;
+ else if (cert->pCertInfo->dwVersion == CERT_V1 ||
+ cert->pCertInfo->dwVersion == CERT_V2)
+ {
+ BYTE hash[20];
+ DWORD size = sizeof(hash);
+
+ if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
+ hash, &size))
+ {
+ CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
+ PCCERT_CONTEXT localCert = CertFindCertificateInStore(
+ engine->hWorld, cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
+ &blob, NULL);
+
+ if (localCert)
+ {
+ CertFreeCertificateContext(localCert);
+ implicitCA = TRUE;
+ }
+ }
+ }
if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
- &constraints, isRoot)))
+ &constraints, implicitCA)))
{
+ chainConstraints->fCA = constraints.fCA;
if (!constraints.fCA)
{
TRACE_(chain)("chain element %d can't be a CA\n", remainingCAs + 1);
TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData,
name->cbData, name->pbData);
- if (constraint->cbData != sizeof(DWORD) * 2)
+ /* RFC5280, section 4.2.1.10, iPAddress syntax: either 8 or 32 bytes, for
+ * IPv4 or IPv6 addresses, respectively.
+ */
+ if (constraint->cbData != sizeof(DWORD) * 2 && constraint->cbData != 32)
*trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
- else if (name->cbData == sizeof(DWORD))
+ else if (name->cbData == sizeof(DWORD) &&
+ constraint->cbData == sizeof(DWORD) * 2)
{
DWORD subnet, mask, addr;
*/
match = (subnet & mask) == (addr & mask);
}
+ else if (name->cbData == 16 && constraint->cbData == 32)
+ {
+ const BYTE *subnet, *mask, *addr;
+ DWORD i;
+
+ subnet = constraint->pbData;
+ mask = constraint->pbData + 16;
+ addr = name->pbData;
+ match = TRUE;
+ for (i = 0; match && i < 16; i++)
+ if ((subnet[i] & mask[i]) != (addr[i] & mask[i]))
+ match = FALSE;
+ }
/* else: name is wrong size, no match */
return match;
*trustErrorStatus |= match ? errorIfFound : errorIfNotFound;
}
+static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert)
+{
+ PCERT_EXTENSION ext;
+
+ ext = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
+ cert->cExtension, cert->rgExtension);
+ if (!ext)
+ ext = CertFindExtension(szOID_SUBJECT_ALT_NAME,
+ cert->cExtension, cert->rgExtension);
+ return ext;
+}
+
static void CRYPT_CheckNameConstraints(
const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
DWORD *trustErrorStatus)
/* If there aren't any existing constraints, don't bother checking */
if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree)
{
- CERT_EXTENSION *ext;
+ CERT_EXTENSION *ext = get_subject_alt_name_ext(cert);
- if ((ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, cert->cExtension,
- cert->rgExtension)))
+ if (ext)
{
CERT_ALT_NAME_INFO *subjectName;
DWORD size;
for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
CRYPT_FindMatchingNameEntry(
&nameConstraints->rgPermittedSubtree[i].Base, subjectName,
- trustErrorStatus,
- 0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT);
+ trustErrorStatus, 0,
+ CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT);
LocalFree(subjectName);
}
+ else
+ *trustErrorStatus |=
+ CERT_TRUST_INVALID_EXTENSION |
+ CERT_TRUST_INVALID_NAME_CONSTRAINTS;
}
else
{
if (nameConstraints->cPermittedSubtree)
*trustErrorStatus |=
+ CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT |
CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
if (nameConstraints->cExcludedSubtree)
*trustErrorStatus |=
return info;
}
+static BOOL CRYPT_IsValidNameConstraint(const CERT_NAME_CONSTRAINTS_INFO *info)
+{
+ DWORD i;
+ BOOL ret = TRUE;
+
+ /* Check that none of the constraints specifies a minimum or a maximum.
+ * See RFC 5280, section 4.2.1.10:
+ * "Within this profile, the minimum and maximum fields are not used with
+ * any name forms, thus, the minimum MUST be zero, and maximum MUST be
+ * absent. However, if an application encounters a critical name
+ * constraints extension that specifies other values for minimum or
+ * maximum for a name form that appears in a subsequent certificate, the
+ * application MUST either process these fields or reject the
+ * certificate."
+ * Since it gives no guidance as to how to process these fields, we
+ * reject any name constraint that contains them.
+ */
+ for (i = 0; ret && i < info->cPermittedSubtree; i++)
+ if (info->rgPermittedSubtree[i].dwMinimum ||
+ info->rgPermittedSubtree[i].fMaximum)
+ {
+ TRACE_(chain)("found a minimum or maximum in permitted subtrees\n");
+ ret = FALSE;
+ }
+ for (i = 0; ret && i < info->cExcludedSubtree; i++)
+ if (info->rgExcludedSubtree[i].dwMinimum ||
+ info->rgExcludedSubtree[i].fMaximum)
+ {
+ TRACE_(chain)("found a minimum or maximum in excluded subtrees\n");
+ ret = FALSE;
+ }
+ return ret;
+}
+
static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
{
int i, j;
if ((nameConstraints = CRYPT_GetNameConstraints(
chain->rgpElement[i]->pCertContext->pCertInfo)))
{
- for (j = i - 1; j >= 0; j--)
+ if (!CRYPT_IsValidNameConstraint(nameConstraints))
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
+ else
{
- DWORD errorStatus = 0;
-
- /* According to RFC 3280, self-signed certs don't have name
- * constraints checked unless they're the end cert.
- */
- if (j == 0 || !CRYPT_IsCertificateSelfSigned(
- chain->rgpElement[j]->pCertContext))
+ for (j = i - 1; j >= 0; j--)
{
- CRYPT_CheckNameConstraints(nameConstraints,
- chain->rgpElement[i]->pCertContext->pCertInfo,
- &errorStatus);
- chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
- errorStatus;
+ DWORD errorStatus = 0;
+
+ /* According to RFC 3280, self-signed certs don't have name
+ * constraints checked unless they're the end cert.
+ */
+ if (j == 0 || !CRYPT_IsCertificateSelfSigned(
+ chain->rgpElement[j]->pCertContext))
+ {
+ CRYPT_CheckNameConstraints(nameConstraints,
+ chain->rgpElement[j]->pCertContext->pCertInfo,
+ &errorStatus);
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ errorStatus;
+ }
}
}
LocalFree(nameConstraints);
}
}
+static LPWSTR name_value_to_str(const CERT_NAME_BLOB *name)
+{
+ DWORD len = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name,
+ CERT_SIMPLE_NAME_STR, NULL, 0);
+ LPWSTR str = NULL;
+
+ if (len)
+ {
+ str = CryptMemAlloc(len * sizeof(WCHAR));
+ if (str)
+ cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name,
+ CERT_SIMPLE_NAME_STR, str, len);
+ }
+ return str;
+}
+
+static void dump_alt_name_entry(const CERT_ALT_NAME_ENTRY *entry)
+{
+ LPWSTR str;
+
+ switch (entry->dwAltNameChoice)
+ {
+ case CERT_ALT_NAME_OTHER_NAME:
+ TRACE_(chain)("CERT_ALT_NAME_OTHER_NAME, oid = %s\n",
+ debugstr_a(entry->u.pOtherName->pszObjId));
+ break;
+ case CERT_ALT_NAME_RFC822_NAME:
+ TRACE_(chain)("CERT_ALT_NAME_RFC822_NAME: %s\n",
+ debugstr_w(entry->u.pwszRfc822Name));
+ break;
+ case CERT_ALT_NAME_DNS_NAME:
+ TRACE_(chain)("CERT_ALT_NAME_DNS_NAME: %s\n",
+ debugstr_w(entry->u.pwszDNSName));
+ break;
+ case CERT_ALT_NAME_DIRECTORY_NAME:
+ str = name_value_to_str(&entry->u.DirectoryName);
+ TRACE_(chain)("CERT_ALT_NAME_DIRECTORY_NAME: %s\n", debugstr_w(str));
+ CryptMemFree(str);
+ break;
+ case CERT_ALT_NAME_URL:
+ TRACE_(chain)("CERT_ALT_NAME_URL: %s\n", debugstr_w(entry->u.pwszURL));
+ break;
+ case CERT_ALT_NAME_IP_ADDRESS:
+ TRACE_(chain)("CERT_ALT_NAME_IP_ADDRESS: %d bytes\n",
+ entry->u.IPAddress.cbData);
+ break;
+ case CERT_ALT_NAME_REGISTERED_ID:
+ TRACE_(chain)("CERT_ALT_NAME_REGISTERED_ID: %s\n",
+ debugstr_a(entry->u.pszRegisteredID));
+ break;
+ default:
+ TRACE_(chain)("dwAltNameChoice = %d\n", entry->dwAltNameChoice);
+ }
+}
+
+static void dump_alt_name(LPCSTR type, const CERT_EXTENSION *ext)
+{
+ CERT_ALT_NAME_INFO *name;
+ DWORD size;
+
+ TRACE_(chain)("%s:\n", type);
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
+ ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size))
+ {
+ DWORD i;
+
+ TRACE_(chain)("%d alt name entries:\n", name->cAltEntry);
+ for (i = 0; i < name->cAltEntry; i++)
+ dump_alt_name_entry(&name->rgAltEntry[i]);
+ LocalFree(name);
+ }
+}
+
static void dump_basic_constraints(const CERT_EXTENSION *ext)
{
CERT_BASIC_CONSTRAINTS_INFO *info;
}
}
+static void dump_key_usage(const CERT_EXTENSION *ext)
+{
+ CRYPT_BIT_BLOB usage;
+ DWORD size = sizeof(usage);
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData,
+ ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
+ {
+#define trace_usage_bit(bits, bit) \
+ if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
+ if (usage.cbData)
+ {
+ trace_usage_bit(usage.pbData[0], CERT_DIGITAL_SIGNATURE_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_NON_REPUDIATION_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_KEY_ENCIPHERMENT_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_DATA_ENCIPHERMENT_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_KEY_AGREEMENT_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_KEY_CERT_SIGN_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_CRL_SIGN_KEY_USAGE);
+ trace_usage_bit(usage.pbData[0], CERT_ENCIPHER_ONLY_KEY_USAGE);
+ }
+#undef trace_usage_bit
+ if (usage.cbData > 1 && usage.pbData[1] & CERT_DECIPHER_ONLY_KEY_USAGE)
+ TRACE_(chain)("CERT_DECIPHER_ONLY_KEY_USAGE\n");
+ }
+}
+
+static void dump_general_subtree(const CERT_GENERAL_SUBTREE *subtree)
+{
+ dump_alt_name_entry(&subtree->Base);
+ TRACE_(chain)("dwMinimum = %d, fMaximum = %d, dwMaximum = %d\n",
+ subtree->dwMinimum, subtree->fMaximum, subtree->dwMaximum);
+}
+
+static void dump_name_constraints(const CERT_EXTENSION *ext)
+{
+ CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
+ DWORD size;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
+ ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &nameConstraints,
+ &size))
+ {
+ DWORD i;
+
+ TRACE_(chain)("%d permitted subtrees:\n",
+ nameConstraints->cPermittedSubtree);
+ for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
+ dump_general_subtree(&nameConstraints->rgPermittedSubtree[i]);
+ TRACE_(chain)("%d excluded subtrees:\n",
+ nameConstraints->cExcludedSubtree);
+ for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
+ dump_general_subtree(&nameConstraints->rgExcludedSubtree[i]);
+ LocalFree(nameConstraints);
+ }
+}
+
+static void dump_cert_policies(const CERT_EXTENSION *ext)
+{
+ CERT_POLICIES_INFO *policies;
+ DWORD size;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
+ ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
+ &policies, &size))
+ {
+ DWORD i, j;
+
+ TRACE_(chain)("%d policies:\n", policies->cPolicyInfo);
+ for (i = 0; i < policies->cPolicyInfo; i++)
+ {
+ TRACE_(chain)("policy identifier: %s\n",
+ debugstr_a(policies->rgPolicyInfo[i].pszPolicyIdentifier));
+ TRACE_(chain)("%d policy qualifiers:\n",
+ policies->rgPolicyInfo[i].cPolicyQualifier);
+ for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
+ TRACE_(chain)("%s\n", debugstr_a(
+ policies->rgPolicyInfo[i].rgPolicyQualifier[j].
+ pszPolicyQualifierId));
+ }
+ LocalFree(policies);
+ }
+}
+
+static void dump_enhanced_key_usage(const CERT_EXTENSION *ext)
+{
+ CERT_ENHKEY_USAGE *usage;
+ DWORD size;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
+ ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
+ &usage, &size))
+ {
+ DWORD i;
+
+ TRACE_(chain)("%d usages:\n", usage->cUsageIdentifier);
+ for (i = 0; i < usage->cUsageIdentifier; i++)
+ TRACE_(chain)("%s\n", usage->rgpszUsageIdentifier[i]);
+ LocalFree(usage);
+ }
+}
+
+static void dump_netscape_cert_type(const CERT_EXTENSION *ext)
+{
+ CRYPT_BIT_BLOB usage;
+ DWORD size = sizeof(usage);
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData,
+ ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
+ {
+#define trace_cert_type_bit(bits, bit) \
+ if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
+ if (usage.cbData)
+ {
+ trace_cert_type_bit(usage.pbData[0],
+ NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE);
+ trace_cert_type_bit(usage.pbData[0],
+ NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE);
+ trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CERT_TYPE);
+ trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CERT_TYPE);
+ trace_cert_type_bit(usage.pbData[0], NETSCAPE_SSL_CA_CERT_TYPE);
+ trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CA_CERT_TYPE);
+ trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CA_CERT_TYPE);
+ }
+#undef trace_cert_type_bit
+ }
+}
+
static void dump_extension(const CERT_EXTENSION *ext)
{
TRACE_(chain)("%s (%scritical)\n", debugstr_a(ext->pszObjId),
ext->fCritical ? "" : "not ");
- if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS))
+ if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME))
+ dump_alt_name("subject alt name", ext);
+ else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME))
+ dump_alt_name("issuer alt name", ext);
+ else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS))
dump_basic_constraints(ext);
+ else if (!strcmp(ext->pszObjId, szOID_KEY_USAGE))
+ dump_key_usage(ext);
+ else if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME2))
+ dump_alt_name("subject alt name 2", ext);
+ else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME2))
+ dump_alt_name("issuer alt name 2", ext);
else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS2))
dump_basic_constraints2(ext);
+ else if (!strcmp(ext->pszObjId, szOID_NAME_CONSTRAINTS))
+ dump_name_constraints(ext);
+ else if (!strcmp(ext->pszObjId, szOID_CERT_POLICIES))
+ dump_cert_policies(ext);
+ else if (!strcmp(ext->pszObjId, szOID_ENHANCED_KEY_USAGE))
+ dump_enhanced_key_usage(ext);
+ else if (!strcmp(ext->pszObjId, szOID_NETSCAPE_CERT_TYPE))
+ dump_netscape_cert_type(ext);
}
static LPCWSTR filetime_to_str(const FILETIME *time)
LPWSTR name = NULL;
DWORD len, i;
- TRACE_(chain)("%p\n", cert);
+ TRACE_(chain)("%p: version %d\n", cert, cert->pCertInfo->dwVersion);
len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
name = CryptMemAlloc(len * sizeof(WCHAR));
dump_extension(&cert->pCertInfo->rgExtension[i]);
}
+static BOOL CRYPT_KeyUsageValid(PCertificateChainEngine engine,
+ PCCERT_CONTEXT cert, BOOL isRoot, BOOL isCA, DWORD index)
+{
+ PCERT_EXTENSION ext;
+ BOOL ret;
+ BYTE usageBits = 0;
+
+ ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension,
+ cert->pCertInfo->rgExtension);
+ if (ext)
+ {
+ CRYPT_BIT_BLOB usage;
+ DWORD size = sizeof(usage);
+
+ ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS,
+ ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
+ &usage, &size);
+ if (!ret)
+ return FALSE;
+ else if (usage.cbData > 2)
+ {
+ /* The key usage extension only defines 9 bits => no more than 2
+ * bytes are needed to encode all known usages.
+ */
+ return FALSE;
+ }
+ else
+ {
+ /* The only bit relevant to chain validation is the keyCertSign
+ * bit, which is always in the least significant byte of the
+ * key usage bits.
+ */
+ usageBits = usage.pbData[usage.cbData - 1];
+ }
+ }
+ if (isCA)
+ {
+ if (!ext)
+ {
+ /* MS appears to violate RFC 5280, section 4.2.1.3 (Key Usage)
+ * here. Quoting the RFC:
+ * "This [key usage] extension MUST appear in certificates that
+ * contain public keys that are used to validate digital signatures
+ * on other public key certificates or CRLs."
+ * MS appears to accept certs that do not contain key usage
+ * extensions as CA certs. V1 and V2 certificates did not have
+ * extensions, and many root certificates are V1 certificates, so
+ * perhaps this is prudent. On the other hand, MS also accepts V3
+ * certs without key usage extensions. We are more restrictive:
+ * we accept locally installed V1 or V2 certs as CA certs.
+ * We also accept a lack of key usage extension on root certs,
+ * which is implied in RFC 5280, section 6.1: the trust anchor's
+ * only requirement is that it was used to issue the next
+ * certificate in the chain.
+ */
+ if (isRoot)
+ ret = TRUE;
+ else if (cert->pCertInfo->dwVersion == CERT_V1 ||
+ cert->pCertInfo->dwVersion == CERT_V2)
+ {
+ PCCERT_CONTEXT localCert = CRYPT_FindCertInStore(
+ engine->hWorld, cert);
+
+ ret = localCert != NULL;
+ CertFreeCertificateContext(localCert);
+ }
+ else
+ ret = FALSE;
+ if (!ret)
+ WARN_(chain)("no key usage extension on a CA cert\n");
+ }
+ else
+ {
+ if (!(usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE))
+ {
+ WARN_(chain)("keyCertSign not asserted on a CA cert\n");
+ ret = FALSE;
+ }
+ else
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ if (ext && (usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE))
+ {
+ WARN_(chain)("keyCertSign asserted on a non-CA cert\n");
+ ret = FALSE;
+ }
+ else
+ ret = TRUE;
+ }
+ return ret;
+}
+
+static BOOL CRYPT_ExtendedKeyUsageValidForCA(PCCERT_CONTEXT cert)
+{
+ PCERT_EXTENSION ext;
+ BOOL ret;
+
+ /* RFC 5280, section 4.2.1.12: "In general, this extension will only
+ * appear in end entity certificates." And, "If a certificate contains
+ * both a key usage extension and an extended key usage extension, then
+ * both extensions MUST be processed independently and the certificate MUST
+ * only be used for a purpose consistent with both extensions." This seems
+ * to imply that it should be checked if present, and ignored if not.
+ * Unfortunately some CAs, e.g. the Thawte SGC CA, don't include the code
+ * signing extended key usage, whereas they do include the keyCertSign
+ * key usage. Thus, when checking for a CA, we only require the
+ * code signing extended key usage if the extended key usage is critical.
+ */
+ ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
+ cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+ if (ext && ext->fCritical)
+ {
+ CERT_ENHKEY_USAGE *usage;
+ DWORD size;
+
+ ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
+ X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size);
+ if (ret)
+ {
+ DWORD i;
+
+ /* Explicitly require the code signing extended key usage for a CA
+ * with an extended key usage extension. That is, don't assume
+ * a cert is allowed to be a CA if it specifies the
+ * anyExtendedKeyUsage usage oid. See again RFC 5280, section
+ * 4.2.1.12: "Applications that require the presence of a
+ * particular purpose MAY reject certificates that include the
+ * anyExtendedKeyUsage OID but not the particular OID expected for
+ * the application."
+ */
+ ret = FALSE;
+ for (i = 0; !ret && i < usage->cUsageIdentifier; i++)
+ if (!strcmp(usage->rgpszUsageIdentifier[i],
+ szOID_PKIX_KP_CODE_SIGNING))
+ ret = TRUE;
+ LocalFree(usage);
+ }
+ }
+ else
+ ret = TRUE;
+ return ret;
+}
+
+static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
+{
+ BOOL ret = TRUE;
+ DWORD i;
+
+ for (i = 0; ret && i < cert->pCertInfo->cExtension; i++)
+ {
+ if (cert->pCertInfo->rgExtension[i].fCritical)
+ {
+ LPCSTR oid = cert->pCertInfo->rgExtension[i].pszObjId;
+
+ if (!strcmp(oid, szOID_BASIC_CONSTRAINTS))
+ ret = TRUE;
+ else if (!strcmp(oid, szOID_BASIC_CONSTRAINTS2))
+ ret = TRUE;
+ else if (!strcmp(oid, szOID_NAME_CONSTRAINTS))
+ ret = TRUE;
+ else if (!strcmp(oid, szOID_KEY_USAGE))
+ ret = TRUE;
+ else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME))
+ ret = TRUE;
+ else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME2))
+ ret = TRUE;
+ else if (!strcmp(oid, szOID_ENHANCED_KEY_USAGE))
+ ret = TRUE;
+ else
+ {
+ FIXME("unsupported critical extension %s\n",
+ debugstr_a(oid));
+ ret = FALSE;
+ }
+ }
+ }
+ return ret;
+}
+
+static BOOL CRYPT_IsCertVersionValid(PCCERT_CONTEXT cert)
+{
+ BOOL ret = TRUE;
+
+ /* Checks whether the contents of the cert match the cert's version. */
+ switch (cert->pCertInfo->dwVersion)
+ {
+ case CERT_V1:
+ /* A V1 cert may not contain unique identifiers. See RFC 5280,
+ * section 4.1.2.8:
+ * "These fields MUST only appear if the version is 2 or 3 (Section
+ * 4.1.2.1). These fields MUST NOT appear if the version is 1."
+ */
+ if (cert->pCertInfo->IssuerUniqueId.cbData ||
+ cert->pCertInfo->SubjectUniqueId.cbData)
+ ret = FALSE;
+ /* A V1 cert may not contain extensions. See RFC 5280, section 4.1.2.9:
+ * "This field MUST only appear if the version is 3 (Section 4.1.2.1)."
+ */
+ if (cert->pCertInfo->cExtension)
+ ret = FALSE;
+ break;
+ case CERT_V2:
+ /* A V2 cert may not contain extensions. See RFC 5280, section 4.1.2.9:
+ * "This field MUST only appear if the version is 3 (Section 4.1.2.1)."
+ */
+ if (cert->pCertInfo->cExtension)
+ ret = FALSE;
+ break;
+ case CERT_V3:
+ /* Do nothing, all fields are allowed for V3 certs */
+ break;
+ default:
+ WARN_(chain)("invalid cert version %d\n", cert->pCertInfo->dwVersion);
+ ret = FALSE;
+ }
+ return ret;
+}
+
static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
{
PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1];
int i;
BOOL pathLengthConstraintViolated = FALSE;
- CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 };
+ CERT_BASIC_CONSTRAINTS2_INFO constraints = { FALSE, FALSE, 0 };
TRACE_(chain)("checking chain with %d elements for time %s\n",
chain->cElement, debugstr_w(filetime_to_str(time)));
for (i = chain->cElement - 1; i >= 0; i--)
{
+ BOOL isRoot;
+
if (TRACE_ON(chain))
dump_element(chain->rgpElement[i]->pCertContext);
+ if (i == chain->cElement - 1)
+ isRoot = CRYPT_IsCertificateSelfSigned(
+ chain->rgpElement[i]->pCertContext);
+ else
+ isRoot = FALSE;
+ if (!CRYPT_IsCertVersionValid(chain->rgpElement[i]->pCertContext))
+ {
+ /* MS appears to accept certs whose versions don't match their
+ * contents, so there isn't an appropriate error code.
+ */
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_INVALID_EXTENSION;
+ }
if (CertVerifyTimeValidity(time,
chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
CERT_TRUST_IS_NOT_TIME_VALID;
if (i != 0)
{
- BOOL isRoot;
-
- if (i == chain->cElement - 1)
- isRoot = CRYPT_IsCertificateSelfSigned(
- chain->rgpElement[i]->pCertContext);
- else
- isRoot = FALSE;
/* Check the signature of the cert this issued */
if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
if (pathLengthConstraintViolated)
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
- else if (!CRYPT_CheckBasicConstraintsForCA(
- chain->rgpElement[i]->pCertContext, &constraints, i - 1,
- isRoot, &pathLengthConstraintViolated))
+ else if (!CRYPT_CheckBasicConstraintsForCA(engine,
+ chain->rgpElement[i]->pCertContext, &constraints, i - 1, isRoot,
+ &pathLengthConstraintViolated))
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
else if (constraints.fPathLenConstraint &&
constraints.dwPathLenConstraint--;
}
}
+ else
+ {
+ /* Check whether end cert has a basic constraints extension */
+ if (!CRYPT_DecodeBasicConstraints(
+ chain->rgpElement[i]->pCertContext, &constraints, FALSE))
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
+ }
+ if (!CRYPT_KeyUsageValid(engine, chain->rgpElement[i]->pCertContext,
+ isRoot, constraints.fCA, i))
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
+ if (i != 0)
+ if (!CRYPT_ExtendedKeyUsageValidForCA(
+ chain->rgpElement[i]->pCertContext))
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
if (CRYPT_IsSimpleChainCyclic(chain))
{
/* If the chain is cyclic, then the path length constraints
CERT_TRUST_IS_PARTIAL_CHAIN |
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
}
- /* FIXME: check valid usages */
+ /* Check whether every critical extension is supported */
+ if (!CRYPT_CriticalExtensionsSupported(
+ chain->rgpElement[i]->pCertContext))
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_INVALID_EXTENSION;
CRYPT_CombineTrustStatus(&chain->TrustStatus,
&chain->rgpElement[i]->TrustStatus);
}
return alternate;
}
-#define CHAIN_QUALITY_SIGNATURE_VALID 8
-#define CHAIN_QUALITY_TIME_VALID 4
-#define CHAIN_QUALITY_COMPLETE_CHAIN 2
-#define CHAIN_QUALITY_TRUSTED_ROOT 1
+#define CHAIN_QUALITY_SIGNATURE_VALID 0x16
+#define CHAIN_QUALITY_TIME_VALID 8
+#define CHAIN_QUALITY_COMPLETE_CHAIN 4
+#define CHAIN_QUALITY_BASIC_CONSTRAINTS 2
+#define CHAIN_QUALITY_TRUSTED_ROOT 1
#define CHAIN_QUALITY_HIGHEST \
CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
- CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT
+ CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_BASIC_CONSTRAINTS | \
+ CHAIN_QUALITY_TRUSTED_ROOT
#define IS_TRUST_ERROR_SET(TrustStatus, bits) \
(TrustStatus)->dwErrorStatus & (bits)
if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
CERT_TRUST_IS_UNTRUSTED_ROOT))
quality &= ~CHAIN_QUALITY_TRUSTED_ROOT;
+ if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
+ CERT_TRUST_INVALID_BASIC_CONSTRAINTS))
+ quality &= ~CHAIN_QUALITY_BASIC_CONSTRAINTS;
if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
CERT_TRUST_IS_PARTIAL_CHAIN))
- if (chain->context.TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN;
if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED))
}
}
+static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch)
+{
+ DWORD i;
+
+ TRACE_(chain)("%s: %s\n", name,
+ usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR");
+ for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++)
+ TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]);
+}
+
+static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara)
+{
+ TRACE_(chain)("%d\n", pChainPara->cbSize);
+ if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS))
+ dump_usage_match("RequestedUsage", &pChainPara->RequestedUsage);
+ if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA))
+ {
+ dump_usage_match("RequestedIssuancePolicy",
+ &pChainPara->RequestedIssuancePolicy);
+ TRACE_(chain)("%d\n", pChainPara->dwUrlRetrievalTimeout);
+ TRACE_(chain)("%d\n", pChainPara->fCheckRevocationFreshnessTime);
+ TRACE_(chain)("%d\n", pChainPara->dwRevocationFreshnessTime);
+ }
+}
+
BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
if (!hChainEngine)
hChainEngine = CRYPT_GetDefaultChainEngine();
+ if (TRACE_ON(chain))
+ dump_chain_para(pChainPara);
/* FIXME: what about HCCE_LOCAL_MACHINE? */
ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime,
hAdditionalStore, &chain);
return TRUE;
}
+static BOOL match_dns_to_subject_alt_name(PCERT_EXTENSION ext,
+ LPCWSTR server_name)
+{
+ BOOL matches = FALSE;
+ CERT_ALT_NAME_INFO *subjectName;
+ DWORD size;
+
+ TRACE_(chain)("%s\n", debugstr_w(server_name));
+ /* This could be spoofed by the embedded NULL vulnerability, since the
+ * returned CERT_ALT_NAME_INFO doesn't have a way to indicate the
+ * encoded length of a name. Fortunately CryptDecodeObjectEx fails if
+ * the encoded form of the name contains a NULL.
+ */
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
+ ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+ &subjectName, &size))
+ {
+ DWORD i;
+
+ /* RFC 5280 states that multiple instances of each name type may exist,
+ * in section 4.2.1.6:
+ * "Multiple name forms, and multiple instances of each name form,
+ * MAY be included."
+ * It doesn't specify the behavior in such cases, but common usage is
+ * to accept a certificate if any name matches.
+ */
+ for (i = 0; !matches && i < subjectName->cAltEntry; i++)
+ {
+ if (subjectName->rgAltEntry[i].dwAltNameChoice ==
+ CERT_ALT_NAME_DNS_NAME)
+ {
+ TRACE_(chain)("dNSName: %s\n", debugstr_w(
+ subjectName->rgAltEntry[i].u.pwszDNSName));
+ if (!strcmpiW(server_name,
+ subjectName->rgAltEntry[i].u.pwszDNSName))
+ matches = TRUE;
+ }
+ }
+ LocalFree(subjectName);
+ }
+ return matches;
+}
+
+static BOOL find_matching_domain_component(CERT_NAME_INFO *name,
+ LPCWSTR component)
+{
+ BOOL matches = FALSE;
+ DWORD i, j;
+
+ for (i = 0; !matches && i < name->cRDN; i++)
+ for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
+ if (!strcmp(szOID_DOMAIN_COMPONENT,
+ name->rgRDN[i].rgRDNAttr[j].pszObjId))
+ {
+ PCERT_RDN_ATTR attr;
+
+ attr = &name->rgRDN[i].rgRDNAttr[j];
+ /* Compare with memicmpW rather than strcmpiW in order to avoid
+ * a match with a string with an embedded NULL. The component
+ * must match one domain component attribute's entire string
+ * value with a case-insensitive match.
+ */
+ matches = !memicmpW(component, (LPWSTR)attr->Value.pbData,
+ attr->Value.cbData / sizeof(WCHAR));
+ }
+ return matches;
+}
+
+static BOOL match_domain_component(LPCWSTR allowed_component, DWORD allowed_len,
+ LPCWSTR server_component, DWORD server_len, BOOL allow_wildcards,
+ BOOL *see_wildcard)
+{
+ LPCWSTR allowed_ptr, server_ptr;
+ BOOL matches = TRUE;
+
+ *see_wildcard = FALSE;
+ if (server_len < allowed_len)
+ {
+ WARN_(chain)("domain component %s too short for %s\n",
+ debugstr_wn(server_component, server_len),
+ debugstr_wn(allowed_component, allowed_len));
+ /* A domain component can't contain a wildcard character, so a domain
+ * component shorter than the allowed string can't produce a match.
+ */
+ return FALSE;
+ }
+ for (allowed_ptr = allowed_component, server_ptr = server_component;
+ matches && allowed_ptr - allowed_component < allowed_len;
+ allowed_ptr++, server_ptr++)
+ {
+ if (*allowed_ptr == '*')
+ {
+ if (allowed_ptr - allowed_component < allowed_len - 1)
+ {
+ WARN_(chain)("non-wildcard characters after wildcard not supported\n");
+ matches = FALSE;
+ }
+ else if (!allow_wildcards)
+ {
+ WARN_(chain)("wildcard after non-wildcard component\n");
+ matches = FALSE;
+ }
+ else
+ {
+ /* the preceding characters must have matched, so the rest of
+ * the component also matches.
+ */
+ *see_wildcard = TRUE;
+ break;
+ }
+ }
+ matches = tolowerW(*allowed_ptr) == tolowerW(*server_ptr);
+ }
+ if (matches && server_ptr - server_component < server_len)
+ {
+ /* If there are unmatched characters in the server domain component,
+ * the server domain only matches if the allowed string ended in a '*'.
+ */
+ matches = *allowed_ptr == '*';
+ }
+ return matches;
+}
+
+static BOOL match_common_name(LPCWSTR server_name, PCERT_RDN_ATTR nameAttr)
+{
+ LPCWSTR allowed = (LPCWSTR)nameAttr->Value.pbData;
+ LPCWSTR allowed_component = allowed;
+ DWORD allowed_len = nameAttr->Value.cbData / sizeof(WCHAR);
+ LPCWSTR server_component = server_name;
+ DWORD server_len = strlenW(server_name);
+ BOOL matches = TRUE, allow_wildcards = TRUE;
+
+ TRACE_(chain)("CN = %s\n", debugstr_wn(allowed_component, allowed_len));
+
+ /* From RFC 2818 (HTTP over TLS), section 3.1:
+ * "Names may contain the wildcard character * which is considered to match
+ * any single domain name component or component fragment. E.g.,
+ * *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com
+ * but not bar.com."
+ *
+ * And from RFC 2595 (Using TLS with IMAP, POP3 and ACAP), section 2.4:
+ * "A "*" wildcard character MAY be used as the left-most name component in
+ * the certificate. For example, *.example.com would match a.example.com,
+ * foo.example.com, etc. but would not match example.com."
+ *
+ * There are other protocols which use TLS, and none of them is
+ * authoritative. This accepts certificates in common usage, e.g.
+ * *.domain.com matches www.domain.com but not domain.com, and
+ * www*.domain.com matches www1.domain.com but not mail.domain.com.
+ */
+ do {
+ LPCWSTR allowed_dot, server_dot;
+
+ allowed_dot = memchrW(allowed_component, '.',
+ allowed_len - (allowed_component - allowed));
+ server_dot = memchrW(server_component, '.',
+ server_len - (server_component - server_name));
+ /* The number of components must match */
+ if ((!allowed_dot && server_dot) || (allowed_dot && !server_dot))
+ {
+ if (!allowed_dot)
+ WARN_(chain)("%s: too many components for CN=%s\n",
+ debugstr_w(server_name), debugstr_wn(allowed, allowed_len));
+ else
+ WARN_(chain)("%s: not enough components for CN=%s\n",
+ debugstr_w(server_name), debugstr_wn(allowed, allowed_len));
+ matches = FALSE;
+ }
+ else
+ {
+ LPCWSTR allowed_end, server_end;
+ BOOL has_wildcard;
+
+ allowed_end = allowed_dot ? allowed_dot : allowed + allowed_len;
+ server_end = server_dot ? server_dot : server_name + server_len;
+ matches = match_domain_component(allowed_component,
+ allowed_end - allowed_component, server_component,
+ server_end - server_component, allow_wildcards, &has_wildcard);
+ /* Once a non-wildcard component is seen, no wildcard components
+ * may follow
+ */
+ if (!has_wildcard)
+ allow_wildcards = FALSE;
+ if (matches)
+ {
+ allowed_component = allowed_dot ? allowed_dot + 1 : allowed_end;
+ server_component = server_dot ? server_dot + 1 : server_end;
+ }
+ }
+ } while (matches && allowed_component &&
+ allowed_component - allowed < allowed_len &&
+ server_component && server_component - server_name < server_len);
+ TRACE_(chain)("returning %d\n", matches);
+ return matches;
+}
+
+static BOOL match_dns_to_subject_dn(PCCERT_CONTEXT cert, LPCWSTR server_name)
+{
+ BOOL matches = FALSE;
+ CERT_NAME_INFO *name;
+ DWORD size;
+
+ TRACE_(chain)("%s\n", debugstr_w(server_name));
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME,
+ cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+ &name, &size))
+ {
+ /* If the subject distinguished name contains any name components,
+ * make sure all of them are present.
+ */
+ if (CertFindRDNAttr(szOID_DOMAIN_COMPONENT, name))
+ {
+ LPCWSTR ptr = server_name;
+
+ matches = TRUE;
+ do {
+ LPCWSTR dot = strchrW(ptr, '.'), end;
+ /* 254 is the maximum DNS label length, see RFC 1035 */
+ WCHAR component[255];
+ DWORD len;
+
+ end = dot ? dot : ptr + strlenW(ptr);
+ len = end - ptr;
+ if (len >= sizeof(component) / sizeof(component[0]))
+ {
+ WARN_(chain)("domain component %s too long\n",
+ debugstr_wn(ptr, len));
+ matches = FALSE;
+ }
+ else
+ {
+ memcpy(component, ptr, len * sizeof(WCHAR));
+ component[len] = 0;
+ matches = find_matching_domain_component(name, component);
+ }
+ ptr = dot ? dot + 1 : end;
+ } while (matches && ptr && *ptr);
+ }
+ else
+ {
+ PCERT_RDN_ATTR attr;
+
+ /* If the certificate isn't using a DN attribute in the name, make
+ * make sure the common name matches.
+ */
+ if ((attr = CertFindRDNAttr(szOID_COMMON_NAME, name)))
+ matches = match_common_name(server_name, attr);
+ }
+ LocalFree(name);
+ }
+ return matches;
+}
+
+static BOOL WINAPI verify_ssl_policy(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
+{
+ pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
+ if (pChainContext->TrustStatus.dwErrorStatus &
+ CERT_TRUST_IS_NOT_SIGNATURE_VALID)
+ {
+ pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
+ find_element_with_error(pChainContext,
+ CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
+ &pPolicyStatus->lElementIndex);
+ }
+ else if (pChainContext->TrustStatus.dwErrorStatus &
+ CERT_TRUST_IS_UNTRUSTED_ROOT)
+ {
+ pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
+ find_element_with_error(pChainContext,
+ CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
+ &pPolicyStatus->lElementIndex);
+ }
+ else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
+ {
+ pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
+ find_element_with_error(pChainContext,
+ CERT_TRUST_IS_CYCLIC, &pPolicyStatus->lChainIndex,
+ &pPolicyStatus->lElementIndex);
+ /* For a cyclic chain, which element is a cycle isn't meaningful */
+ pPolicyStatus->lElementIndex = -1;
+ }
+ else if (pChainContext->TrustStatus.dwErrorStatus &
+ CERT_TRUST_IS_NOT_TIME_VALID)
+ {
+ pPolicyStatus->dwError = CERT_E_EXPIRED;
+ find_element_with_error(pChainContext,
+ CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex,
+ &pPolicyStatus->lElementIndex);
+ }
+ else
+ pPolicyStatus->dwError = NO_ERROR;
+ /* We only need bother checking whether the name in the end certificate
+ * matches if the chain is otherwise okay.
+ */
+ if (!pPolicyStatus->dwError && pPolicyPara &&
+ pPolicyPara->cbSize >= sizeof(CERT_CHAIN_POLICY_PARA))
+ {
+ HTTPSPolicyCallbackData *sslPara = pPolicyPara->pvExtraPolicyPara;
+
+ if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData))
+ {
+ if (sslPara->dwAuthType == AUTHTYPE_SERVER &&
+ sslPara->pwszServerName)
+ {
+ PCCERT_CONTEXT cert;
+ PCERT_EXTENSION altNameExt;
+ BOOL matches;
+
+ cert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
+ altNameExt = get_subject_alt_name_ext(cert->pCertInfo);
+ /* If the alternate name extension exists, the name it contains
+ * is bound to the certificate, so make sure the name matches
+ * it. Otherwise, look for the server name in the subject
+ * distinguished name. RFC5280, section 4.2.1.6:
+ * "Whenever such identities are to be bound into a
+ * certificate, the subject alternative name (or issuer
+ * alternative name) extension MUST be used; however, a DNS
+ * name MAY also be represented in the subject field using the
+ * domainComponent attribute."
+ */
+ if (altNameExt)
+ matches = match_dns_to_subject_alt_name(altNameExt,
+ sslPara->pwszServerName);
+ else
+ matches = match_dns_to_subject_dn(cert,
+ sslPara->pwszServerName);
+ if (!matches)
+ {
+ pPolicyStatus->dwError = CERT_E_CN_NO_MATCH;
+ pPolicyStatus->lChainIndex = 0;
+ pPolicyStatus->lElementIndex = 0;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
static BYTE msPubKey1[] = {
0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE):
verifyPolicy = verify_authenticode_policy;
break;
+ case LOWORD(CERT_CHAIN_POLICY_SSL):
+ verifyPolicy = verify_ssl_policy;
+ break;
case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS):
verifyPolicy = verify_basic_constraints_policy;
break;
pPolicyStatus);
if (hFunc)
CryptFreeOIDFunctionAddress(hFunc, 0);
+ TRACE("returning %d (%08x)\n", ret, pPolicyStatus->dwError);
return ret;
}
void *pCertContext)
{
BOOL ret;
+ PCCERT_CONTEXT linked;
TRACE("(%p, %p)\n", store, pCertContext);
- ret = CertDeleteCertificateFromStore(
- Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
+ /* Deleting the linked context results in its ref count getting
+ * decreased, but the caller of this (CertDeleteCertificateFromStore) also
+ * decreases pCertContext's ref count, by calling
+ * CertFreeCertificateContext. Increase ref count of linked context to
+ * compensate.
+ */
+ linked = Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT));
+ CertDuplicateCertificateContext(linked);
+ ret = CertDeleteCertificateFromStore(linked);
return ret;
}
void *pCrlContext)
{
BOOL ret;
+ PCCRL_CONTEXT linked;
TRACE("(%p, %p)\n", store, pCrlContext);
- ret = CertDeleteCRLFromStore(
- Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
+ /* Deleting the linked context results in its ref count getting
+ * decreased, but the caller of this (CertDeleteCRLFromStore) also
+ * decreases pCrlContext's ref count, by calling CertFreeCRLContext.
+ * Increase ref count of linked context to compensate.
+ */
+ linked = Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT));
+ CertDuplicateCRLContext(linked);
+ ret = CertDeleteCRLFromStore(linked);
return ret;
}
void *pCtlContext)
{
BOOL ret;
+ PCCTL_CONTEXT linked;
TRACE("(%p, %p)\n", store, pCtlContext);
- ret = CertDeleteCTLFromStore(
- Context_GetLinkedContext(pCtlContext, sizeof(CTL_CONTEXT)));
+ /* Deleting the linked context results in its ref count getting
+ * decreased, but the caller of this (CertDeleteCTLFromStore) also
+ * decreases pCtlContext's ref count, by calling CertFreeCTLContext.
+ * Increase ref count of linked context to compensate.
+ */
+ linked = Context_GetLinkedContext(pCtlContext, sizeof(CTL_CONTEXT));
+ CertDuplicateCTLContext(linked);
+ ret = CertDeleteCTLFromStore(linked);
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_CollectionControl(HCERTSTORE hCertStore, DWORD dwFlags,
+ DWORD dwCtrlType, void const *pvCtrlPara)
+{
+ BOOL ret;
+ PWINE_COLLECTIONSTORE store = hCertStore;
+ PWINE_STORE_LIST_ENTRY entry;
+
+ TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
+ pvCtrlPara);
+
+ if (!store)
+ return TRUE;
+ if (store->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ if (store->hdr.type != StoreTypeCollection)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+
+ ret = TRUE;
+ EnterCriticalSection(&store->cs);
+ LIST_FOR_EACH_ENTRY(entry, &store->stores, WINE_STORE_LIST_ENTRY, entry)
+ {
+ if (entry->store->control)
+ {
+ ret = entry->store->control(entry->store, dwFlags, dwCtrlType,
+ pvCtrlPara);
+ if (!ret)
+ break;
+ }
+ }
+ LeaveCriticalSection(&store->cs);
return ret;
}
store->hdr.ctls.addContext = CRYPT_CollectionAddCTL;
store->hdr.ctls.enumContext = CRYPT_CollectionEnumCTL;
store->hdr.ctls.deleteContext = CRYPT_CollectionDeleteCTL;
+ store->hdr.control = CRYPT_CollectionControl;
InitializeCriticalSection(&store->cs);
store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs");
list_init(&store->stores);
#include "wine/list.h"
#include "crypt32_private.h"
-WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+WINE_DEFAULT_DEBUG_CHANNEL(context);
typedef enum _ContextType {
ContextTypeData,
linkContext->type = ContextTypeLink;
linkContext->linked = linkedBase;
if (addRef)
- InterlockedIncrement(&linkedBase->ref);
+ Context_AddRef(linked, contextSize);
TRACE("%p's ref count is %d\n", context, linkContext->ref);
}
TRACE("returning %p\n", context);
PBASE_CONTEXT baseContext = BASE_CONTEXT_FROM_CONTEXT(context, contextSize);
InterlockedIncrement(&baseContext->ref);
+ TRACE("%p's ref count is %d\n", context, baseContext->ref);
+ if (baseContext->type == ContextTypeLink)
+ {
+ void *linkedContext = Context_GetLinkedContext(context, contextSize);
+ PBASE_CONTEXT linkedBase = BASE_CONTEXT_FROM_CONTEXT(linkedContext,
+ contextSize);
+
+ /* Add-ref the linked contexts too */
+ while (linkedContext && linkedBase->type == ContextTypeLink)
+ {
+ InterlockedIncrement(&linkedBase->ref);
+ TRACE("%p's ref count is %d\n", linkedContext, linkedBase->ref);
+ linkedContext = Context_GetLinkedContext(linkedContext,
+ contextSize);
+ if (linkedContext)
+ linkedBase = BASE_CONTEXT_FROM_CONTEXT(linkedContext,
+ contextSize);
+ else
+ linkedBase = NULL;
+ }
+ if (linkedContext)
+ {
+ /* It's not a link context, so it wasn't add-ref'ed in the while
+ * loop, so add-ref it here.
+ */
+ linkedBase = BASE_CONTEXT_FROM_CONTEXT(linkedContext,
+ contextSize);
+ InterlockedIncrement(&linkedBase->ref);
+ TRACE("%p's ref count is %d\n", linkedContext, linkedBase->ref);
+ }
+ }
}
void *Context_GetExtra(const void *context, size_t contextSize)
((PDATA_CONTEXT)ptr)->properties : NULL;
}
-void Context_Release(void *context, size_t contextSize,
+BOOL Context_Release(void *context, size_t contextSize,
ContextFreeFunc dataContextFree)
{
PBASE_CONTEXT base = BASE_CONTEXT_FROM_CONTEXT(context, contextSize);
+ BOOL ret = TRUE;
+ if (base->ref <= 0)
+ {
+ ERR("%p's ref count is %d\n", context, base->ref);
+ return FALSE;
+ }
+ if (base->type == ContextTypeLink)
+ {
+ /* The linked context is of the same type as this, so release
+ * it as well, using the same offset and data free function.
+ */
+ ret = Context_Release(CONTEXT_FROM_BASE_CONTEXT(
+ ((PLINK_CONTEXT)base)->linked, contextSize), contextSize,
+ dataContextFree);
+ }
if (InterlockedDecrement(&base->ref) == 0)
{
TRACE("freeing %p\n", context);
- switch (base->type)
+ if (base->type == ContextTypeData)
{
- 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 %d\n", context, base->ref);
+ return ret;
}
void Context_CopyProperties(const void *to, const void *from,
return ret;
}
-void ContextList_Delete(struct ContextList *list, void *context)
+BOOL ContextList_Remove(struct ContextList *list, void *context)
{
struct list *entry = ContextList_ContextToEntry(list, context);
+ BOOL inList = FALSE;
EnterCriticalSection(&list->cs);
- list_remove(entry);
+ if (!list_empty(entry))
+ {
+ list_remove(entry);
+ inList = TRUE;
+ }
LeaveCriticalSection(&list->cs);
- list->contextInterface->free(context);
+ if (inList)
+ list_init(entry);
+ return inList;
}
static void ContextList_Empty(struct ContextList *list)
PCCRL_CONTEXT WINAPI CertDuplicateCRLContext(PCCRL_CONTEXT pCrlContext)
{
TRACE("(%p)\n", pCrlContext);
- Context_AddRef((void *)pCrlContext, sizeof(CRL_CONTEXT));
+ if (pCrlContext)
+ Context_AddRef((void *)pCrlContext, sizeof(CRL_CONTEXT));
return pCrlContext;
}
BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
{
+ BOOL ret = TRUE;
+
TRACE("(%p)\n", pCrlContext);
if (pCrlContext)
- Context_Release((void *)pCrlContext, sizeof(CRL_CONTEXT),
+ ret = Context_Release((void *)pCrlContext, sizeof(CRL_CONTEXT),
CrlDataContext_Free);
- return TRUE;
+ return ret;
}
DWORD WINAPI CertEnumCRLContextProperties(PCCRL_CONTEXT pCRLContext,
-@ stdcall CertAddCRLContextToStore(long ptr long ptr)
-@ stdcall CertAddCTLContextToStore(long ptr long ptr)
-@ stdcall CertAddCertificateContextToStore(long ptr long ptr)
-@ stdcall CertAddEncodedCRLToStore(long long ptr long long ptr)
-@ stdcall CertAddEncodedCTLToStore(long long ptr long long ptr)
-@ stdcall CertAddEncodedCertificateToStore(long long ptr long long ptr)
-@ stub CertAddEncodedCertificateToSystemStoreA
-@ stub CertAddEncodedCertificateToSystemStoreW
+@ stdcall CertAddCRLContextToStore(ptr ptr long ptr)
+@ stdcall CertAddCTLContextToStore(ptr ptr long ptr)
+@ stdcall CertAddCertificateContextToStore(ptr ptr long ptr)
+@ stdcall CertAddCertificateLinkToStore(ptr ptr long ptr)
+@ stdcall CertAddEncodedCRLToStore(ptr long ptr long long ptr)
+@ stdcall CertAddEncodedCTLToStore(ptr long ptr long long ptr)
+@ stdcall CertAddEncodedCertificateToStore(ptr long ptr long long ptr)
+@ stdcall CertAddEncodedCertificateToSystemStoreA(str ptr long)
+@ stdcall CertAddEncodedCertificateToSystemStoreW(wstr ptr long)
@ stdcall CertAddEnhancedKeyUsageIdentifier(ptr str)
@ stdcall CertAddSerializedElementToStore(ptr ptr long long long long ptr ptr)
@ stdcall CertAddStoreToCollection(ptr ptr long long)
@ stdcall CertCompareCertificateName(long ptr ptr)
@ stdcall CertCompareIntegerBlob(ptr ptr)
@ stdcall CertComparePublicKeyInfo(long ptr ptr)
-@ stdcall CertControlStore(long long long ptr)
+@ stdcall CertControlStore(ptr long long ptr)
@ stdcall CertCreateCRLContext(long ptr long)
@ stdcall CertCreateCTLContext(long ptr long)
@ stdcall CertCreateCertificateChainEngine(ptr ptr)
@ stdcall CertEnumCTLContextProperties(ptr long)
@ stdcall CertEnumCTLsInStore(ptr ptr)
@ stdcall CertEnumCertificateContextProperties(ptr long)
-@ stdcall CertEnumCertificatesInStore(long ptr)
+@ stdcall CertEnumCertificatesInStore(ptr ptr)
@ stdcall CertEnumPhysicalStore(ptr long ptr ptr)
@ stdcall CertEnumSystemStore(long ptr ptr ptr)
@ stdcall CertFindAttribute(str long ptr)
-@ stdcall CertFindCRLInStore(long long long long ptr ptr)
-@ stdcall CertFindCTLInStore(long long long long ptr ptr)
-@ stdcall CertFindCertificateInStore(long long long long ptr ptr)
+@ stdcall CertFindCRLInStore(ptr long long long ptr ptr)
+@ stdcall CertFindCTLInStore(ptr long long long ptr ptr)
+@ stdcall CertFindCertificateInStore(ptr long long long ptr ptr)
@ stdcall CertFindCertificateInCRL(ptr ptr long ptr ptr)
@ stdcall CertFindExtension(str long ptr)
@ stdcall CertFindRDNAttr(str ptr)
@ stdcall CertGetCertificateChain(ptr ptr ptr ptr ptr long ptr ptr)
@ stdcall CertGetCertificateContextProperty(ptr long ptr ptr)
@ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr)
-@ stub CertGetIntendedKeyUsage
-@ stdcall CertGetIssuerCertificateFromStore(long ptr ptr ptr)
+@ stdcall CertGetIntendedKeyUsage(long ptr ptr long)
+@ stdcall CertGetIssuerCertificateFromStore(ptr ptr ptr ptr)
@ stdcall CertGetNameStringA(ptr long long ptr ptr long)
@ stdcall CertGetNameStringW(ptr long long ptr ptr long)
@ stdcall CertGetPublicKeyLength(long ptr)
-@ stdcall CertGetStoreProperty(long long ptr ptr)
+@ stdcall CertGetStoreProperty(ptr long ptr ptr)
@ stdcall CertGetSubjectCertificateFromStore(ptr long ptr)
@ stdcall CertGetValidUsages(long ptr ptr ptr ptr)
@ stub CertIsRDNAttrsInCertificateName
@ stdcall CertRDNValueToStrA(long ptr ptr long)
@ stdcall CertRDNValueToStrW(long ptr ptr long)
@ stdcall CertRemoveEnhancedKeyUsageIdentifier(ptr str)
-@ stdcall CertRemoveStoreFromCollection(long long)
-@ stdcall CertSaveStore(long long long long ptr long)
+@ stdcall CertRemoveStoreFromCollection(ptr ptr)
+@ stdcall CertSaveStore(ptr long long long ptr long)
@ stdcall CertSerializeCRLStoreElement(ptr long ptr ptr)
@ stdcall CertSerializeCTLStoreElement(ptr long ptr ptr)
@ stdcall CertSerializeCertificateStoreElement(ptr long ptr ptr)
@ stdcall CertVerifyValidityNesting(ptr ptr)
@ stdcall CreateFileU(wstr long long ptr long long ptr) kernel32.CreateFileW
@ stdcall CryptBinaryToStringA(ptr long long ptr ptr)
-@ stub CryptBinaryToStringW # (ptr long long ptr ptr)
+@ stdcall CryptBinaryToStringW(ptr long long ptr ptr)
@ stdcall CryptStringToBinaryA(str long long ptr ptr ptr ptr)
@ stdcall CryptStringToBinaryW (wstr long long ptr ptr ptr ptr)
@ stdcall CryptAcquireContextU(ptr wstr wstr long long) advapi32.CryptAcquireContextW
IDS_ENHANCED_KEY_USAGE "Erweiterte Schlüsselbenutzung"
IDS_AUTHORITY_INFO_ACCESS "Autoritätsinformationszugriff"
IDS_CERT_EXTENSIONS "Zertifikatserweiterung"
- IDS_NEXT_UPDATE_LOCATION "Next Update Location"
+ IDS_NEXT_UPDATE_LOCATION "nächster Aktualisierungsort"
IDS_YES_OR_NO_TRUST "Vertrauen oder nicht vertrauen"
IDS_EMAIL_ADDRESS "E-Mail-Adresse"
IDS_UNSTRUCTURED_NAME "Unstrukturierter Name"
DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
CRYPT_DIGESTED_DATA *digestedData, DWORD *pcbDigestedData);
+BOOL WINAPI CRYPT_AsnEncodePubKeyInfoNoNull(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
+
/* The following aren't defined in wincrypt.h, as they're "reserved" */
#define CERT_CERT_PROP_ID 32
#define CERT_CRL_PROP_ID 33
*/
BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store);
+/* Reads contexts serialized in the blob into the memory store. Returns FALSE
+ * if the file is not of the expected format.
+ */
+BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
+ HCERTSTORE store);
+
/* Fixes up the pointers in info, where 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
*/
DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indent,
- PCERT_NAME_BLOB pName, DWORD dwStrType, LPWSTR psz, DWORD csz);
+ const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz);
/**
* Context functions
/* 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.
+ * Returns FALSE if the reference count is <= 0 when called.
*/
-void Context_Release(void *context, size_t contextSize,
+BOOL Context_Release(void *context, size_t contextSize,
ContextFreeFunc dataContextFree);
/**
void *ContextList_Enum(struct ContextList *list, void *pPrev);
-void ContextList_Delete(struct ContextList *list, void *context);
+/* Removes a context from the list. Returns TRUE if the context was removed,
+ * or FALSE if not. (The context may have been duplicated, so subsequent
+ * removes have no effect.)
+ */
+BOOL ContextList_Remove(struct ContextList *list, void *context);
void ContextList_Free(struct ContextList *list);
if (!pCtlContext)
ret = TRUE;
else if (!pCtlContext->hCertStore)
- {
- ret = TRUE;
- CertFreeCTLContext(pCtlContext);
- }
+ ret = CertFreeCTLContext(pCtlContext);
else
{
PWINECRYPT_CERTSTORE hcs = pCtlContext->hCertStore;
ret = FALSE;
else
ret = hcs->ctls.deleteContext(hcs, (void *)pCtlContext);
- CertFreeCTLContext(pCtlContext);
+ if (ret)
+ ret = CertFreeCTLContext(pCtlContext);
}
return ret;
}
PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
{
TRACE("(%p)\n", pCtlContext);
- Context_AddRef((void *)pCtlContext, sizeof(CTL_CONTEXT));
+ if (pCtlContext)
+ Context_AddRef((void *)pCtlContext, sizeof(CTL_CONTEXT));
return pCtlContext;
}
BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
{
+ BOOL ret = TRUE;
+
TRACE("(%p)\n", pCTLContext);
if (pCTLContext)
- Context_Release((void *)pCTLContext, sizeof(CTL_CONTEXT),
+ ret = Context_Release((void *)pCTLContext, sizeof(CTL_CONTEXT),
CTLDataContext_Free);
- return TRUE;
+ return ret;
}
DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
/*
- * Copyright 2005-2008 Juan Lang
+ * Copyright 2005-2009 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
WINE_DECLARE_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 *,
static BOOL CRYPT_AsnDecodePubKeyInfoInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded);
-/* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
- * time, doesn't do memory allocation, and doesn't do exception handling.
+/* Assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set ahead of time.
*/
-static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
- DWORD *pcbDecoded);
+static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
/* Assumes algo->Parameters.pbData is set ahead of time. */
static BOOL CRYPT_AsnDecodeAlgorithmId(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded);
-static BOOL CRYPT_AsnDecodePKCSAttributesInternal(const BYTE *pbEncoded,
+static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded);
DWORD size;
};
+#define FINALMEMBERSIZE(s, member) (sizeof(s) - offsetof(s, member))
+#define MEMBERSIZE(s, member, nextmember) \
+ (offsetof(s, nextmember) - offsetof(s, member))
+
/* Decodes the items in a sequence, where the items are described in items,
* the encoded data are in pbEncoded with length cbEncoded. Decodes into
* pvStructInfo. nextData is a pointer to the memory location at which the
: NULL, &items[i].size, &itemDecoded);
if (ret)
{
- /* Account for alignment padding */
- items[i].size = ALIGN_DWORD_PTR(items[i].size);
+ if (items[i].size < items[i].minSize)
+ items[i].size = items[i].minSize;
+ else if (items[i].size > items[i].minSize)
+ {
+ /* Account for alignment padding */
+ items[i].size = ALIGN_DWORD_PTR(items[i].size);
+ }
TRACE("item %d size: %d\n", i, items[i].size);
if (nextData && items[i].hasPointer &&
items[i].size > items[i].minSize)
* The expected tag of the entire encoded array (usually a variant
* of ASN_SETOF or ASN_SEQUENCEOF.) If tag is 0, decodeFunc is called
* regardless of the tag seen.
+ * countOffset:
+ * The offset within the outer structure at which the count exists.
+ * For example, a structure such as CRYPT_ATTRIBUTES has countOffset == 0,
+ * while CRYPT_ATTRIBUTE has countOffset ==
+ * offsetof(CRYPT_ATTRIBUTE, cValue).
+ * arrayOffset:
+ * The offset within the outer structure at which the array pointer exists.
+ * For example, CRYPT_ATTRIBUTES has arrayOffset ==
+ * offsetof(CRYPT_ATTRIBUTES, rgAttr).
+ * minArraySize:
+ * The minimum size of the decoded array. On WIN32, this is always 8:
+ * sizeof(DWORD) + sizeof(void *). On WIN64, it can be larger due to
+ * alignment.
* decodeFunc:
* used to decode each item in the array
* itemSize:
struct AsnArrayDescriptor
{
BYTE tag;
+ DWORD countOffset;
+ DWORD arrayOffset;
+ DWORD minArraySize;
InternalDecodeFunc decodeFunc;
DWORD itemSize;
BOOL hasPointer;
DWORD size;
};
-/* Decodes an array of like types into a struct GenericArray.
- * The layout and decoding of the array are described by a struct
+/* Decodes an array of like types into a structure 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,
- DWORD *pcbDecoded, void *startingPointer)
+ DWORD *pcbDecoded)
{
BOOL ret = TRUE;
- TRACE("%p, %p, %d, %08x, %p, %p, %d, %p\n", arrayDesc, pbEncoded,
- cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
- startingPointer);
+ TRACE("%p, %p, %d, %p, %d\n", arrayDesc, pbEncoded,
+ cbEncoded, pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
- if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag)
+ if (!cbEncoded)
+ {
+ SetLastError(CRYPT_E_ASN1_EOD);
+ ret = FALSE;
+ }
+ else if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag)
{
DWORD dataLen;
if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen)))
{
- DWORD bytesNeeded, cItems = 0, decoded;
+ DWORD bytesNeeded = arrayDesc->minArraySize, cItems = 0, decoded;
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;
decoded = 1 + lenBytes;
- bytesNeeded = sizeof(struct GenericArray);
if (dataLen)
{
const BYTE *ptr;
*pcbDecoded = decoded;
if (!pvStructInfo)
*pcbStructInfo = bytesNeeded;
- else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+ pvStructInfo, pcbStructInfo, bytesNeeded)))
{
- DWORD i;
+ DWORD i, *pcItems;
BYTE *nextData;
const BYTE *ptr;
- struct GenericArray *array;
+ void *rgItems;
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
- pvStructInfo = *(BYTE **)pvStructInfo;
- array = pvStructInfo;
- array->cItems = cItems;
- if (startingPointer)
- array->rgItems = startingPointer;
+ pvStructInfo = *(void **)pvStructInfo;
+ pcItems = pvStructInfo;
+ *pcItems = cItems;
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+ {
+ rgItems = (BYTE *)pvStructInfo +
+ arrayDesc->minArraySize;
+ *(void **)((BYTE *)pcItems -
+ arrayDesc->countOffset + arrayDesc->arrayOffset) =
+ rgItems;
+ }
else
- array->rgItems = (BYTE *)array +
- sizeof(struct GenericArray);
- nextData = array->rgItems +
- array->cItems * arrayDesc->itemSize;
+ rgItems = *(void **)((BYTE *)pcItems -
+ arrayDesc->countOffset + arrayDesc->arrayOffset);
+ nextData = (BYTE *)rgItems + cItems * arrayDesc->itemSize;
for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
i < cItems && ptr - pbEncoded - 1 - lenBytes <
dataLen; i++)
DWORD itemDecoded;
if (arrayDesc->hasPointer)
- *(BYTE **)(array->rgItems + i * arrayDesc->itemSize
+ *(BYTE **)((BYTE *)rgItems + i * arrayDesc->itemSize
+ arrayDesc->pointerOffset) = nextData;
ret = arrayDesc->decodeFunc(ptr,
itemSizes[i].encodedLen,
dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
- array->rgItems + i * arrayDesc->itemSize,
+ (BYTE *)rgItems + i * arrayDesc->itemSize,
&itemSizes[i].size, &itemDecoded);
if (ret)
{
ptr += itemDecoded;
}
}
- if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG))
- CRYPT_FreeSpace(pDecodePara, pvStructInfo);
}
}
if (itemSizes != &itemSize)
return ret;
}
+static BOOL CRYPT_AsnDecodeCertExtensionsInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret = TRUE;
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_INFO, cExtension), offsetof(CERT_INFO, rgExtension),
+ FINALMEMBERSIZE(CERT_INFO, cExtension),
+ CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
+ offsetof(CERT_EXTENSION, pszObjId) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
static BOOL CRYPT_AsnDecodeCertExtensions(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
- ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded + 1 + lenBytes,
+ ret = CRYPT_AsnDecodeCertExtensionsInternal(pbEncoded + 1 + lenBytes,
dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL);
if (ret && pcbDecoded)
*pcbDecoded = 1 + lenBytes + dataLen;
CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO),
FALSE, TRUE, offsetof(CERT_INFO,
SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
- { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId),
+ { ASN_CONTEXT | 1, offsetof(CERT_INFO, IssuerUniqueId),
CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 },
- { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId),
+ { ASN_CONTEXT | 2, 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 },
+ CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(CERT_INFO, cExtension),
+ TRUE, TRUE, offsetof(CERT_INFO, rgExtension), 0 },
};
TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
return ret;
}
+static BOOL CRYPT_AsnDecodeCRLEntryExtensions(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret = TRUE;
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CRL_ENTRY, cExtension), offsetof(CRL_ENTRY, rgExtension),
+ FINALMEMBERSIZE(CRL_ENTRY, cExtension),
+ CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
+ offsetof(CERT_EXTENSION, pszObjId) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
{ 0, offsetof(CRL_ENTRY, RevocationDate),
CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 },
{ ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension),
- CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
+ CRYPT_AsnDecodeCRLEntryExtensions,
+ FINALMEMBERSIZE(CRL_ENTRY, cExtension), TRUE, TRUE,
offsetof(CRL_ENTRY, rgExtension), 0 },
};
PCRL_ENTRY entry = pvStructInfo;
return ret;
}
-/* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has
- * been set prior to calling.
+/* Warning: assumes pvStructInfo points to the cCRLEntry member of a CRL_INFO
+ * whose rgCRLEntry member has been set prior to calling.
*/
static BOOL CRYPT_AsnDecodeCRLEntries(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
BOOL ret;
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CRL_INFO, cCRLEntry), offsetof(CRL_INFO, rgCRLEntry),
+ MEMBERSIZE(CRL_INFO, cCRLEntry, cExtension),
CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE,
offsetof(CRL_ENTRY, SerialNumber.pbData) };
- struct GenericArray *entries = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- entries ? entries->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
TRACE("Returning %d (%08x)\n", ret, GetLastError());
return ret;
}
+static BOOL CRYPT_AsnDecodeCRLExtensionsInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret = TRUE;
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CRL_INFO, cExtension), offsetof(CRL_INFO, rgExtension),
+ FINALMEMBERSIZE(CRL_INFO, cExtension),
+ CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
+ offsetof(CERT_EXTENSION, pszObjId) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeCRLExtensions(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ DWORD dataLen;
+
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+ ret = CRYPT_AsnDecodeCRLExtensionsInternal(pbEncoded + 1 + lenBytes,
+ dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL);
+ if (ret && pcbDecoded)
+ *pcbDecoded = 1 + lenBytes + dataLen;
+ }
+ return ret;
+}
+
static BOOL CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{ 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTimeInternal,
sizeof(FILETIME), TRUE, FALSE, 0 },
{ ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry),
- CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE,
- offsetof(CRL_INFO, rgCRLEntry), 0 },
+ CRYPT_AsnDecodeCRLEntries, MEMBERSIZE(CRL_INFO, cCRLEntry, cExtension),
+ 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 },
+ CRYPT_AsnDecodeCRLExtensions, FINALMEMBERSIZE(CRL_INFO, cExtension),
+ TRUE, TRUE, offsetof(CRL_INFO, rgExtension), 0 },
};
BOOL ret = TRUE;
return ret;
}
-/* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set
- * ahead of time!
- */
static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
return ret;
}
-static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
- DWORD *pcbDecoded)
-{
- BOOL ret = TRUE;
- struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
- CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
- offsetof(CERT_EXTENSION, pszObjId) };
- PCERT_EXTENSIONS exts = pvStructInfo;
-
- TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
- pvStructInfo, *pcbStructInfo, pcbDecoded);
-
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- 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;
+ TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
+
__TRY
{
- ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded,
- dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL);
- if (ret && pvStructInfo)
- {
- ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
- pcbStructInfo, *pcbStructInfo);
- if (ret)
- {
- CERT_EXTENSIONS *exts;
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_EXTENSIONS, cExtension),
+ offsetof(CERT_EXTENSIONS, rgExtension),
+ sizeof(CERT_EXTENSIONS),
+ CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
+ offsetof(CERT_EXTENSION, pszObjId) };
- if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
- pvStructInfo = *(BYTE **)pvStructInfo;
- exts = pvStructInfo;
- exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
- sizeof(CERT_EXTENSIONS));
- ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded,
- dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
- pcbStructInfo, NULL);
- }
- }
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
{
BOOL ret = TRUE;
struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
+ offsetof(CERT_RDN, cRDNAttr), offsetof(CERT_RDN, rgRDNAttr),
+ sizeof(CERT_RDN),
CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
offsetof(CERT_RDN_ATTR, pszObjId) };
- PCERT_RDN rdn = pvStructInfo;
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- rdn ? rdn->rgRDNAttr : NULL);
+ NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_NAME_INFO, cRDN), offsetof(CERT_NAME_INFO, rgRDN),
+ sizeof(CERT_NAME_INFO),
CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE,
offsetof(CERT_RDN, rgRDNAttr) };
+ DWORD bytesNeeded;
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded,
+ NULL);
+ if (ret)
+ {
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+ pvStructInfo, pcbStructInfo, bytesNeeded)))
+ {
+ CERT_NAME_INFO *info;
+
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+ pvStructInfo = *(BYTE **)pvStructInfo;
+ info = pvStructInfo;
+ info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
+ sizeof(CERT_NAME_INFO));
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
+ &bytesNeeded, NULL);
+ }
+ }
}
__EXCEPT_PAGE_FAULT
{
{
BOOL ret = TRUE;
struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
+ offsetof(CERT_RDN, cRDNAttr), offsetof(CERT_RDN, rgRDNAttr),
+ sizeof(CERT_RDN),
CRYPT_AsnDecodeUnicodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
offsetof(CERT_RDN_ATTR, pszObjId) };
- PCERT_RDN rdn = pvStructInfo;
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- rdn ? rdn->rgRDNAttr : NULL);
+ NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_NAME_INFO, cRDN), offsetof(CERT_NAME_INFO, rgRDN),
+ sizeof(CERT_NAME_INFO),
CRYPT_AsnDecodeUnicodeRdn, sizeof(CERT_RDN), TRUE,
offsetof(CERT_RDN, rgRDNAttr) };
+ DWORD bytesNeeded;
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded,
+ NULL);
+ if (ret)
+ {
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+ pvStructInfo, pcbStructInfo, bytesNeeded)))
+ {
+ CERT_NAME_INFO *info;
+
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+ pvStructInfo = *(BYTE **)pvStructInfo;
+ info = pvStructInfo;
+ info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
+ sizeof(CERT_NAME_INFO));
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
+ &bytesNeeded, NULL);
+ }
+ }
}
__EXCEPT_PAGE_FAULT
{
return ret;
}
-static BOOL CRYPT_DecodeDERArray(const BYTE *pbEncoded, DWORD cbEncoded,
+static BOOL CRYPT_AsnDecodeCTLUsage(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
BOOL ret;
- struct AsnArrayDescriptor arrayDesc = { 0, CRYPT_AsnDecodeCopyBytes,
- sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) };
- struct GenericArray *array = pvStructInfo;
-
- TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
- pvStructInfo, *pcbStructInfo, pcbDecoded);
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CTL_USAGE, cUsageIdentifier),
+ offsetof(CTL_USAGE, rgpszUsageIdentifier),
+ sizeof(CTL_USAGE),
+ CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 };
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- array ? array->rgItems : NULL);
+ NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
-static BOOL CRYPT_AsnDecodeCTLUsage(const BYTE *pbEncoded, DWORD cbEncoded,
- DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
+static BOOL CRYPT_AsnDecodeCTLEntryAttributes(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
{
+ struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CTL_ENTRY, cAttribute), offsetof(CTL_ENTRY, rgAttribute),
+ FINALMEMBERSIZE(CTL_ENTRY, cAttribute),
+ CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), TRUE,
+ offsetof(CRYPT_ATTRIBUTE, pszObjId) };
BOOL ret;
- struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
- CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 };
- CTL_USAGE *usage = pvStructInfo;
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- usage ? usage->rgpszUsageIdentifier : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DATA_BLOB), FALSE, TRUE,
offsetof(CTL_ENTRY, SubjectIdentifier.pbData), 0 },
{ ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CTL_ENTRY, cAttribute),
- CRYPT_AsnDecodePKCSAttributesInternal, sizeof(CRYPT_ATTRIBUTES), FALSE,
- TRUE, offsetof(CTL_ENTRY, rgAttribute), 0 },
+ CRYPT_AsnDecodeCTLEntryAttributes,
+ FINALMEMBERSIZE(CTL_ENTRY, cAttribute), FALSE, TRUE,
+ offsetof(CTL_ENTRY, rgAttribute), 0 },
};
BOOL ret = TRUE;
CTL_ENTRY *entry = pvStructInfo;
{
BOOL ret;
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CTL_INFO, cCTLEntry), offsetof(CTL_INFO, rgCTLEntry),
+ FINALMEMBERSIZE(CTL_INFO, cExtension),
CRYPT_AsnDecodeCTLEntry, sizeof(CTL_ENTRY), TRUE,
offsetof(CTL_ENTRY, SubjectIdentifier.pbData) };
- struct GenericArray *entries = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- entries ? entries->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeCTLExtensionsInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret = TRUE;
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CTL_INFO, cExtension), offsetof(CTL_INFO, rgExtension),
+ FINALMEMBERSIZE(CTL_INFO, cExtension),
+ CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
+ offsetof(CERT_EXTENSION, pszObjId) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeCTLExtensions(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ DWORD dataLen;
+
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+ ret = CRYPT_AsnDecodeCTLExtensionsInternal(pbEncoded + 1 + lenBytes,
+ dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL);
+ if (ret && pcbDecoded)
+ *pcbDecoded = 1 + lenBytes + dataLen;
+ }
return ret;
}
CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
FALSE, TRUE, offsetof(CTL_INFO, SubjectAlgorithm.pszObjId), 0 },
{ ASN_SEQUENCEOF, offsetof(CTL_INFO, cCTLEntry),
- CRYPT_AsnDecodeCTLEntries, sizeof(struct GenericArray),
+ CRYPT_AsnDecodeCTLEntries,
+ MEMBERSIZE(CTL_INFO, cCTLEntry, cExtension),
TRUE, TRUE, offsetof(CTL_INFO, rgCTLEntry), 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CTL_INFO, cExtension),
- CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
- offsetof(CTL_INFO, rgExtension), 0 },
+ CRYPT_AsnDecodeCTLExtensions, FINALMEMBERSIZE(CTL_INFO, cExtension),
+ TRUE, TRUE, offsetof(CTL_INFO, rgExtension), 0 },
};
- TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, *pcbStructInfo);
-
ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
pcbStructInfo, NULL, NULL);
return ret;
}
-static BOOL CRYPT_AsnDecodeSMIMECapabilitiesInternal(const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
- DWORD *pcbDecoded)
-{
- struct AsnArrayDescriptor arrayDesc = { 0,
- CRYPT_AsnDecodeSMIMECapability, sizeof(CRYPT_SMIME_CAPABILITY), TRUE,
- offsetof(CRYPT_SMIME_CAPABILITY, pszObjId) };
- PCRYPT_SMIME_CAPABILITIES capabilities = pvStructInfo;
- BOOL ret;
-
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- capabilities ? capabilities->rgCapability : NULL);
- return ret;
-}
-
static BOOL WINAPI CRYPT_AsnDecodeSMIMECapabilities(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
__TRY
{
- DWORD bytesNeeded;
-
- if (!cbEncoded)
- SetLastError(CRYPT_E_ASN1_EOD);
- else if (pbEncoded[0] != ASN_SEQUENCEOF)
- SetLastError(CRYPT_E_ASN1_CORRUPT);
- else if ((ret = CRYPT_AsnDecodeSMIMECapabilitiesInternal(pbEncoded,
- cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded,
- NULL)))
- {
- if (!pvStructInfo)
- *pcbStructInfo = bytesNeeded;
- else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
- pvStructInfo, pcbStructInfo, bytesNeeded)))
- {
- PCRYPT_SMIME_CAPABILITIES capabilities;
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CRYPT_SMIME_CAPABILITIES, cCapability),
+ offsetof(CRYPT_SMIME_CAPABILITIES, rgCapability),
+ sizeof(CRYPT_SMIME_CAPABILITIES),
+ CRYPT_AsnDecodeSMIMECapability, sizeof(CRYPT_SMIME_CAPABILITY), TRUE,
+ offsetof(CRYPT_SMIME_CAPABILITY, pszObjId) };
- if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
- pvStructInfo = *(BYTE **)pvStructInfo;
- capabilities = pvStructInfo;
- capabilities->rgCapability =
- (PCRYPT_SMIME_CAPABILITY)((BYTE *)pvStructInfo +
- sizeof(CRYPT_SMIME_CAPABILITIES));
- ret = CRYPT_AsnDecodeSMIMECapabilitiesInternal(pbEncoded,
- cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
- &bytesNeeded, NULL);
- }
- }
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
return ret;
}
-static BOOL CRYPT_AsnDecodeIntArray(const BYTE *pbEncoded,
+static BOOL CRYPT_AsnDecodeNoticeNumbers(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, cNoticeNumbers),
+ offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, rgNoticeNumbers),
+ FINALMEMBERSIZE(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, cNoticeNumbers),
CRYPT_AsnDecodeIntInternal, sizeof(int), FALSE, 0 };
- struct GenericArray *array = pvStructInfo;
BOOL ret;
TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, pvStructInfo ? *pcbDecoded : 0);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- array ? array->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
TRACE("returning %d\n", ret);
return ret;
}
pszOrganization), CRYPT_AsnDecodeIA5String, sizeof(LPSTR), FALSE, TRUE,
offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, pszOrganization), 0 },
{ ASN_SEQUENCEOF, offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE,
- cNoticeNumbers), CRYPT_AsnDecodeIntArray, sizeof(struct GenericArray),
+ cNoticeNumbers), CRYPT_AsnDecodeNoticeNumbers,
+ FINALMEMBERSIZE(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, cNoticeNumbers),
FALSE, TRUE, offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE,
rgNoticeNumbers), 0 },
};
return ret;
}
+static BOOL CRYPT_AsnDecodePKCSAttributeValue(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CRYPT_ATTRIBUTE, cValue), offsetof(CRYPT_ATTRIBUTE, rgValue),
+ FINALMEMBERSIZE(CRYPT_ATTRIBUTE, cValue),
+ CRYPT_AsnDecodeCopyBytes,
+ sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pvStructInfo ? *pcbStructInfo : 0, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
offsetof(CRYPT_ATTRIBUTE, pszObjId), 0 },
{ ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_ATTRIBUTE, cValue),
- CRYPT_DecodeDERArray, sizeof(struct GenericArray), FALSE, TRUE,
- offsetof(CRYPT_ATTRIBUTE, rgValue), 0 },
+ CRYPT_AsnDecodePKCSAttributeValue,
+ FINALMEMBERSIZE(CRYPT_ATTRIBUTE, cValue), FALSE,
+ TRUE, offsetof(CRYPT_ATTRIBUTE, rgValue), 0 },
};
PCRYPT_ATTRIBUTE attr = pvStructInfo;
DWORD *pcbDecoded)
{
struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CRYPT_ATTRIBUTES, cAttr), offsetof(CRYPT_ATTRIBUTES, rgAttr),
+ sizeof(CRYPT_ATTRIBUTES),
CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), TRUE,
offsetof(CRYPT_ATTRIBUTE, pszObjId) };
- PCRYPT_ATTRIBUTES attrs = pvStructInfo;
BOOL ret;
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded, attrs ? attrs->rgAttr :
- NULL);
+ NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
__TRY
{
- DWORD bytesNeeded;
+ struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
+ offsetof(CRYPT_ATTRIBUTES, cAttr), offsetof(CRYPT_ATTRIBUTES, rgAttr),
+ sizeof(CRYPT_ATTRIBUTES),
+ CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE),
+ TRUE, offsetof(CRYPT_ATTRIBUTE, pszObjId) };
- if (!cbEncoded)
- SetLastError(CRYPT_E_ASN1_EOD);
- else if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
- SetLastError(CRYPT_E_ASN1_CORRUPT);
- else if ((ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded,
- cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded,
- NULL)))
- {
- if (!pvStructInfo)
- *pcbStructInfo = bytesNeeded;
- else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
- pvStructInfo, pcbStructInfo, bytesNeeded)))
- {
- PCRYPT_ATTRIBUTES attrs;
-
- if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
- pvStructInfo = *(BYTE **)pvStructInfo;
- attrs = pvStructInfo;
- attrs->rgAttr = (PCRYPT_ATTRIBUTE)((BYTE *)pvStructInfo +
- sizeof(CRYPT_ATTRIBUTES));
- ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded,
- cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
- &bytesNeeded, NULL);
- }
- }
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
case 1: /* rfc822Name */
case 2: /* dNSName */
case 6: /* uniformResourceIdentifier */
- bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
+ if (memchr(pbEncoded + 1 + lenBytes, 0, dataLen))
+ {
+ SetLastError(CRYPT_E_ASN1_RULE);
+ ret = FALSE;
+ }
+ else
+ bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
break;
case 4: /* directoryName */
case 7: /* iPAddress */
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
- BOOL ret = TRUE;
+ BOOL ret;
struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CERT_ALT_NAME_INFO, cAltEntry),
+ offsetof(CERT_ALT_NAME_INFO, rgAltEntry),
+ sizeof(CERT_ALT_NAME_INFO),
CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
- PCERT_ALT_NAME_INFO info = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
- if (info)
- TRACE("info->rgAltEntry is %p\n", info->rgAltEntry);
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- info ? info->rgAltEntry : NULL);
+ NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_AUTHORITY_INFO_ACCESS, cAccDescr),
+ offsetof(CERT_AUTHORITY_INFO_ACCESS, rgAccDescr),
+ sizeof(CERT_AUTHORITY_INFO_ACCESS),
CRYPT_AsnDecodeAccessDescription, sizeof(CERT_ACCESS_DESCRIPTION),
TRUE, offsetof(CERT_ACCESS_DESCRIPTION, pszAccessMethod) };
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
{
BOOL ret;
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint),
+ offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint),
+ FINALMEMBERSIZE(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint),
CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE,
offsetof(CERT_NAME_BLOB, pbData) };
- struct GenericArray *entries = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- entries ? entries->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
TRACE("Returning %d (%08x)\n", ret, GetLastError());
return ret;
}
sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
{ ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints,
- sizeof(struct GenericArray), TRUE, TRUE,
+ FINALMEMBERSIZE(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint),
+ TRUE, TRUE,
offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 },
};
{
BOOL ret;
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_POLICY_INFO, cPolicyQualifier),
+ offsetof(CERT_POLICY_INFO, rgPolicyQualifier),
+ FINALMEMBERSIZE(CERT_POLICY_INFO, cPolicyQualifier),
CRYPT_AsnDecodePolicyQualifier, sizeof(CERT_POLICY_QUALIFIER_INFO), TRUE,
offsetof(CERT_POLICY_QUALIFIER_INFO, pszPolicyQualifierId) };
- struct GenericArray *entries = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- entries ? entries->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
TRACE("Returning %d (%08x)\n", ret, GetLastError());
return ret;
}
CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
offsetof(CERT_POLICY_INFO, pszPolicyIdentifier), 0 },
{ ASN_SEQUENCEOF, offsetof(CERT_POLICY_INFO, cPolicyQualifier),
- CRYPT_AsnDecodePolicyQualifiers, sizeof(struct GenericArray), TRUE,
+ CRYPT_AsnDecodePolicyQualifiers,
+ FINALMEMBERSIZE(CERT_POLICY_INFO, cPolicyQualifier), TRUE,
TRUE, offsetof(CERT_POLICY_INFO, rgPolicyQualifier), 0 },
};
CERT_POLICY_INFO *info = pvStructInfo;
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_POLICIES_INFO, cPolicyInfo),
+ offsetof(CERT_POLICIES_INFO, rgPolicyInfo),
+ sizeof(CERT_POLICIES_INFO),
CRYPT_AsnDecodeCertPolicy, sizeof(CERT_POLICY_INFO), TRUE,
offsetof(CERT_POLICY_INFO, pszPolicyIdentifier) };
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ }
+ __ENDTRY
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeCertPolicyMapping(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ struct AsnDecodeSequenceItem items[] = {
+ { ASN_OBJECTIDENTIFIER, offsetof(CERT_POLICY_MAPPING,
+ pszIssuerDomainPolicy), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR),
+ FALSE, TRUE, offsetof(CERT_POLICY_MAPPING, pszIssuerDomainPolicy), 0 },
+ { ASN_OBJECTIDENTIFIER, offsetof(CERT_POLICY_MAPPING,
+ pszSubjectDomainPolicy), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR),
+ FALSE, TRUE, offsetof(CERT_POLICY_MAPPING, pszSubjectDomainPolicy), 0 },
+ };
+ CERT_POLICY_MAPPING *mapping = pvStructInfo;
+ BOOL ret;
+
+ TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
+
+ ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+ pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+ pcbDecoded, mapping ? mapping->pszIssuerDomainPolicy : NULL);
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodeCertPolicyMappings(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+ BOOL ret = FALSE;
+
+ TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+ pDecodePara, pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
+
+ __TRY
+ {
+ struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_POLICY_MAPPINGS_INFO, cPolicyMapping),
+ offsetof(CERT_POLICY_MAPPINGS_INFO, rgPolicyMapping),
+ sizeof(CERT_POLICY_MAPPING),
+ CRYPT_AsnDecodeCertPolicyMapping, sizeof(CERT_POLICY_MAPPING), TRUE,
+ offsetof(CERT_POLICY_MAPPING, pszIssuerDomainPolicy) };
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ }
+ __ENDTRY
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeRequireExplicit(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ DWORD skip, size = sizeof(skip);
+
+ if (!cbEncoded)
+ {
+ SetLastError(CRYPT_E_ASN1_EOD);
+ return FALSE;
+ }
+ if (pbEncoded[0] != (ASN_CONTEXT | 0))
+ {
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ return FALSE;
+ }
+ if ((ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags,
+ &skip, &size, pcbDecoded)))
+ {
+ DWORD bytesNeeded = MEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO,
+ fRequireExplicitPolicy, fInhibitPolicyMapping);
+
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if (*pcbStructInfo < bytesNeeded)
+ {
+ *pcbStructInfo = bytesNeeded;
+ SetLastError(ERROR_MORE_DATA);
+ ret = FALSE;
+ }
+ else
+ {
+ CERT_POLICY_CONSTRAINTS_INFO *info =
+ (CERT_POLICY_CONSTRAINTS_INFO *)((BYTE *)pvStructInfo -
+ offsetof(CERT_POLICY_CONSTRAINTS_INFO, fRequireExplicitPolicy));
+
+ *pcbStructInfo = bytesNeeded;
+ /* The BOOL is implicit: if the integer is present, then it's
+ * TRUE.
+ */
+ info->fRequireExplicitPolicy = TRUE;
+ info->dwRequireExplicitPolicySkipCerts = skip;
+ }
+ }
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeInhibitMapping(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ DWORD skip, size = sizeof(skip);
+
+ if (!cbEncoded)
+ {
+ SetLastError(CRYPT_E_ASN1_EOD);
+ return FALSE;
+ }
+ if (pbEncoded[0] != (ASN_CONTEXT | 1))
+ {
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ return FALSE;
+ }
+ if ((ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags,
+ &skip, &size, pcbDecoded)))
+ {
+ DWORD bytesNeeded = FINALMEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO,
+ fInhibitPolicyMapping);
+
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if (*pcbStructInfo < bytesNeeded)
+ {
+ *pcbStructInfo = bytesNeeded;
+ SetLastError(ERROR_MORE_DATA);
+ ret = FALSE;
+ }
+ else
+ {
+ CERT_POLICY_CONSTRAINTS_INFO *info =
+ (CERT_POLICY_CONSTRAINTS_INFO *)((BYTE *)pvStructInfo -
+ offsetof(CERT_POLICY_CONSTRAINTS_INFO, fInhibitPolicyMapping));
+
+ *pcbStructInfo = bytesNeeded;
+ /* The BOOL is implicit: if the integer is present, then it's
+ * TRUE.
+ */
+ info->fInhibitPolicyMapping = TRUE;
+ info->dwInhibitPolicyMappingSkipCerts = skip;
+ }
+ }
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodeCertPolicyConstraints(
+ DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ void *pvStructInfo, DWORD *pcbStructInfo)
+{
+ BOOL ret = FALSE;
+
+ TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+ pDecodePara, pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
+
+ __TRY
+ {
+ struct AsnDecodeSequenceItem items[] = {
+ { ASN_CONTEXT | 0,
+ offsetof(CERT_POLICY_CONSTRAINTS_INFO, fRequireExplicitPolicy),
+ CRYPT_AsnDecodeRequireExplicit,
+ MEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO, fRequireExplicitPolicy,
+ fInhibitPolicyMapping), TRUE, FALSE, 0, 0 },
+ { ASN_CONTEXT | 1,
+ offsetof(CERT_POLICY_CONSTRAINTS_INFO, fInhibitPolicyMapping),
+ CRYPT_AsnDecodeInhibitMapping,
+ FINALMEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO, fInhibitPolicyMapping),
+ TRUE, FALSE, 0, 0 },
+ };
+
+ ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+ pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
+ pcbStructInfo, NULL, NULL);
}
__EXCEPT_PAGE_FAULT
{
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
BOOL ret;
- BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
- CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
- DWORD size = sizeof(buf);
+ DWORD dataLen;
- blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
- ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, 0, buf,
- &size, pcbDecoded);
- if (ret)
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
- if (!pvStructInfo)
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+ if (pcbDecoded)
+ *pcbDecoded = 1 + lenBytes + dataLen;
+ if (dataLen > sizeof(int))
+ {
+ SetLastError(CRYPT_E_ASN1_LARGE);
+ ret = FALSE;
+ }
+ else if (!pvStructInfo)
*pcbStructInfo = sizeof(int);
else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, sizeof(int))))
{
int val, i;
- if (blob->pbData[blob->cbData - 1] & 0x80)
+ if (dataLen && pbEncoded[1 + lenBytes] & 0x80)
{
/* initialize to a negative value to sign-extend */
val = -1;
}
else
val = 0;
- for (i = 0; i < blob->cbData; i++)
+ for (i = 0; i < dataLen; i++)
{
val <<= 8;
- val |= blob->pbData[blob->cbData - i - 1];
+ val |= pbEncoded[1 + lenBytes + i];
}
memcpy(pvStructInfo, &val, sizeof(int));
}
}
- else if (GetLastError() == ERROR_MORE_DATA)
- SetLastError(CRYPT_E_ASN1_LARGE);
return ret;
}
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
struct AsnArrayDescriptor arrayDesc = {
- ASN_CONTEXT | ASN_CONSTRUCTOR | 0, CRYPT_AsnDecodeAltNameEntry,
- sizeof(CERT_ALT_NAME_ENTRY), TRUE,
+ ASN_CONTEXT | ASN_CONSTRUCTOR | 0,
+ offsetof(CRL_DIST_POINT_NAME, u.FullName.cAltEntry),
+ offsetof(CRL_DIST_POINT_NAME, u.FullName.rgAltEntry),
+ FINALMEMBERSIZE(CRL_DIST_POINT_NAME, u),
+ CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
DWORD nameLen;
{
ret = CRYPT_AsnDecodeArray(&arrayDesc,
pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
- 0, NULL, NULL, &nameLen, NULL, NULL);
- /* The CERT_ALT_NAME_INFO's size is included by CRYPT_AsnDecodeArray
- * as the sizeof(struct GenericArray), so don't include it in the
- * total bytes needed.
- */
+ dwFlags, NULL, NULL, &nameLen, NULL);
bytesNeeded = sizeof(CRL_DIST_POINT_NAME) + nameLen -
- sizeof(CERT_ALT_NAME_INFO);
+ FINALMEMBERSIZE(CRL_DIST_POINT_NAME, u);
}
else
bytesNeeded = sizeof(CRL_DIST_POINT_NAME);
name->dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
ret = CRYPT_AsnDecodeArray(&arrayDesc,
pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
- 0, NULL, &name->u.FullName, &nameLen, NULL,
- name->u.FullName.rgAltEntry);
+ dwFlags, NULL, &name->u.FullName.cAltEntry, &nameLen,
+ NULL);
}
else
name->dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CRL_DIST_POINTS_INFO, cDistPoint),
+ offsetof(CRL_DIST_POINTS_INFO, rgDistPoint),
+ sizeof(CRL_DIST_POINTS_INFO),
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, NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+ offsetof(CERT_ENHKEY_USAGE, cUsageIdentifier),
+ offsetof(CERT_ENHKEY_USAGE, rgpszUsageIdentifier),
+ sizeof(CERT_ENHKEY_USAGE),
CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 };
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
- BOOL ret = FALSE;
+ BOOL ret;
+ DWORD max, size = sizeof(max);
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
- /* The BOOL is implicit: if the integer is present, then it's TRUE */
- ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags,
- pvStructInfo ? (BYTE *)pvStructInfo + sizeof(BOOL) : NULL, pcbStructInfo,
- pcbDecoded);
- if (ret && pvStructInfo)
- *(BOOL *)pvStructInfo = TRUE;
+ if ((ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags,
+ &max, &size, pcbDecoded)))
+ {
+ DWORD bytesNeeded = FINALMEMBERSIZE(CERT_GENERAL_SUBTREE, fMaximum);
+
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if (*pcbStructInfo < bytesNeeded)
+ {
+ *pcbStructInfo = bytesNeeded;
+ SetLastError(ERROR_MORE_DATA);
+ ret = FALSE;
+ }
+ else
+ {
+ CERT_GENERAL_SUBTREE *subtree = (CERT_GENERAL_SUBTREE *)
+ ((BYTE *)pvStructInfo - offsetof(CERT_GENERAL_SUBTREE, fMaximum));
+
+ *pcbStructInfo = bytesNeeded;
+ /* The BOOL is implicit: if the integer is present, then it's
+ * TRUE.
+ */
+ subtree->fMaximum = TRUE;
+ subtree->dwMaximum = max;
+ }
+ }
TRACE("returning %d\n", ret);
return ret;
}
{ ASN_CONTEXT | 0, offsetof(CERT_GENERAL_SUBTREE, dwMinimum),
CRYPT_AsnDecodeIntInternal, sizeof(DWORD), TRUE, FALSE, 0, 0 },
{ ASN_CONTEXT | 1, offsetof(CERT_GENERAL_SUBTREE, fMaximum),
- CRYPT_AsnDecodeMaximum, sizeof(BOOL) + sizeof(DWORD), TRUE, FALSE, 0,
- 0 },
+ CRYPT_AsnDecodeMaximum, FINALMEMBERSIZE(CERT_GENERAL_SUBTREE, fMaximum),
+ TRUE, FALSE, 0, 0 },
};
CERT_GENERAL_SUBTREE *subtree = pvStructInfo;
return ret;
}
-static BOOL CRYPT_AsnDecodeSubtreeArray(const BYTE *pbEncoded,
+static BOOL CRYPT_AsnDecodePermittedSubtree(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
BOOL ret = TRUE;
struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree),
+ offsetof(CERT_NAME_CONSTRAINTS_INFO, rgPermittedSubtree),
+ MEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree,
+ cExcludedSubtree),
CRYPT_AsnDecodeSubtree, sizeof(CERT_GENERAL_SUBTREE), TRUE,
offsetof(CERT_GENERAL_SUBTREE, Base.u.pwszURL) };
- struct GenericArray *array = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- array ? array->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
+static BOOL CRYPT_AsnDecodeExcludedSubtree(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret = TRUE;
+ struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree),
+ offsetof(CERT_NAME_CONSTRAINTS_INFO, rgExcludedSubtree),
+ FINALMEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree),
+ CRYPT_AsnDecodeSubtree, sizeof(CERT_GENERAL_SUBTREE), TRUE,
+ offsetof(CERT_GENERAL_SUBTREE, Base.u.pwszURL) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
static BOOL WINAPI CRYPT_AsnDecodeNameConstraints(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
struct AsnDecodeSequenceItem items[] = {
{ ASN_CONTEXT | ASN_CONSTRUCTOR | 0,
offsetof(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree),
- CRYPT_AsnDecodeSubtreeArray, sizeof(struct GenericArray), TRUE, TRUE,
+ CRYPT_AsnDecodePermittedSubtree,
+ MEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree,
+ cExcludedSubtree), TRUE, TRUE,
offsetof(CERT_NAME_CONSTRAINTS_INFO, rgPermittedSubtree), 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR | 1,
offsetof(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree),
- CRYPT_AsnDecodeSubtreeArray, sizeof(struct GenericArray), TRUE, TRUE,
+ CRYPT_AsnDecodeExcludedSubtree,
+ FINALMEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree),
+ TRUE, TRUE,
offsetof(CERT_NAME_CONSTRAINTS_INFO, rgExcludedSubtree), 0 },
};
return ret;
}
+static BOOL CRYPT_AsnDecodeCMSCertEncoded(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CRYPT_SIGNED_INFO, cCertEncoded),
+ offsetof(CRYPT_SIGNED_INFO, rgCertEncoded),
+ MEMBERSIZE(CRYPT_SIGNED_INFO, cCertEncoded, cCrlEncoded),
+ CRYPT_AsnDecodeCopyBytes,
+ sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pvStructInfo ? *pcbStructInfo : 0, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
+static BOOL CRYPT_AsnDecodeCMSCrlEncoded(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret;
+ struct AsnArrayDescriptor arrayDesc = { 0,
+ offsetof(CRYPT_SIGNED_INFO, cCrlEncoded),
+ offsetof(CRYPT_SIGNED_INFO, rgCrlEncoded),
+ MEMBERSIZE(CRYPT_SIGNED_INFO, cCrlEncoded, content),
+ CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DER_BLOB),
+ TRUE, offsetof(CRYPT_DER_BLOB, pbData) };
+
+ TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pvStructInfo ? *pcbStructInfo : 0, pcbDecoded);
+
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
+ return ret;
+}
+
static BOOL CRYPT_AsnDecodeCMSSignerId(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
BOOL ret;
struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
+ offsetof(CRYPT_SIGNED_INFO, cSignerInfo),
+ offsetof(CRYPT_SIGNED_INFO, rgSignerInfo),
+ FINALMEMBERSIZE(CRYPT_SIGNED_INFO, cSignerInfo),
CRYPT_AsnDecodeCMSSignerInfoInternal, sizeof(CMSG_CMS_SIGNER_INFO), TRUE,
offsetof(CMSG_CMS_SIGNER_INFO, SignerId.u.KeyId.pbData) };
- struct GenericArray *array = pvStructInfo;
TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
pvStructInfo, *pcbStructInfo, pcbDecoded);
- ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
- NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
- array ? array->rgItems : NULL);
+ ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
+ dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
return ret;
}
CRYPT_AsnDecodePKCSContentInfoInternal, sizeof(CRYPT_CONTENT_INFO),
FALSE, TRUE, offsetof(CRYPT_SIGNED_INFO, content.pszObjId), 0 },
{ ASN_CONSTRUCTOR | ASN_CONTEXT | 0,
- offsetof(CRYPT_SIGNED_INFO, cCertEncoded),
- CRYPT_DecodeDERArray, sizeof(struct GenericArray), TRUE, TRUE,
+ offsetof(CRYPT_SIGNED_INFO, cCertEncoded), CRYPT_AsnDecodeCMSCertEncoded,
+ MEMBERSIZE(CRYPT_SIGNED_INFO, cCertEncoded, cCrlEncoded), TRUE, TRUE,
offsetof(CRYPT_SIGNED_INFO, rgCertEncoded), 0 },
{ ASN_CONSTRUCTOR | ASN_CONTEXT | 1,
- offsetof(CRYPT_SIGNED_INFO, cCrlEncoded), CRYPT_DecodeDERArray,
- sizeof(struct GenericArray), TRUE, TRUE,
+ offsetof(CRYPT_SIGNED_INFO, cCrlEncoded), CRYPT_AsnDecodeCMSCrlEncoded,
+ MEMBERSIZE(CRYPT_SIGNED_INFO, cCrlEncoded, content), TRUE, TRUE,
offsetof(CRYPT_SIGNED_INFO, rgCrlEncoded), 0 },
{ ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_SIGNED_INFO, cSignerInfo),
- CRYPT_DecodeSignerArray, sizeof(struct GenericArray), TRUE, TRUE,
+ CRYPT_DecodeSignerArray,
+ FINALMEMBERSIZE(CRYPT_SIGNED_INFO, cSignerInfo), TRUE, TRUE,
offsetof(CRYPT_SIGNED_INFO, rgSignerInfo), 0 },
};
case LOWORD(X509_NAME_CONSTRAINTS):
decodeFunc = CRYPT_AsnDecodeNameConstraints;
break;
+ case LOWORD(X509_POLICY_MAPPINGS):
+ decodeFunc = CRYPT_AsnDecodeCertPolicyMappings;
+ break;
+ case LOWORD(X509_POLICY_CONSTRAINTS):
+ decodeFunc = CRYPT_AsnDecodeCertPolicyConstraints;
+ break;
case LOWORD(PKCS7_SIGNER_INFO):
decodeFunc = CRYPT_AsnDecodePKCSSignerInfo;
break;
decodeFunc = CRYPT_AsnDecodeSMIMECapabilities;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
decodeFunc = CRYPT_AsnDecodeAuthorityKeyId;
+ else if (!strcmp(lpszStructType, szOID_LEGACY_POLICY_MAPPINGS))
+ decodeFunc = CRYPT_AsnDecodeCertPolicyMappings;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2;
else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
else if (!strcmp(lpszStructType, szOID_CERT_POLICIES))
decodeFunc = CRYPT_AsnDecodeCertPolicies;
+ else if (!strcmp(lpszStructType, szOID_POLICY_MAPPINGS))
+ decodeFunc = CRYPT_AsnDecodeCertPolicyMappings;
+ else if (!strcmp(lpszStructType, szOID_POLICY_CONSTRAINTS))
+ decodeFunc = CRYPT_AsnDecodeCertPolicyConstraints;
else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
{
const CERT_PUBLIC_KEY_INFO *info = pvStructInfo;
struct AsnEncodeSequenceItem items[] = {
- { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
+ { &info->Algorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
{ &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
};
return ret;
}
+BOOL WINAPI CRYPT_AsnEncodePubKeyInfoNoNull(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+ const CERT_PUBLIC_KEY_INFO *info = pvStructInfo;
+ struct AsnEncodeSequenceItem items[] = {
+ { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
+ { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
+ };
+
+ TRACE("Encoding public key with OID %s\n",
+ debugstr_a(info->Algorithm.pszObjId));
+ ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
+ sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
+ pcbEncoded);
+ return ret;
+}
+
/* Like in Windows, this blithely ignores the validity of the passed-in
* CERT_INFO, and just encodes it as-is. The resulting encoded data may not
* decode properly, see CRYPT_AsnDecodeCertInfo.
{ &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
{ &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
{ &info->Subject, CRYPT_CopyEncodedBlob, 0 },
- { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
+ { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfoNoNull, 0 },
{ 0 }
};
- struct AsnConstructedItem constructed[3] = { { 0 } };
- DWORD cItem = 7, cConstructed = 0;
+ struct AsnConstructedItem constructed = { 0 };
+ struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
+ DWORD cItem = 7, cSwapped = 0;
if (info->IssuerUniqueId.cbData)
{
- constructed[cConstructed].tag = 1;
- constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
- constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
- items[cItem].pvStructInfo = &constructed[cConstructed];
- items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
- cConstructed++;
+ swapped[cSwapped].tag = ASN_CONTEXT | 1;
+ swapped[cSwapped].pvStructInfo = &info->IssuerUniqueId;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
+ items[cItem].pvStructInfo = &swapped[cSwapped];
+ items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+ cSwapped++;
cItem++;
}
if (info->SubjectUniqueId.cbData)
{
- constructed[cConstructed].tag = 2;
- constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
- constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
- items[cItem].pvStructInfo = &constructed[cConstructed];
- items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
- cConstructed++;
+ swapped[cSwapped].tag = ASN_CONTEXT | 2;
+ swapped[cSwapped].pvStructInfo = &info->SubjectUniqueId;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
+ items[cItem].pvStructInfo = &swapped[cSwapped];
+ items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+ cSwapped++;
cItem++;
}
if (info->cExtension)
{
- constructed[cConstructed].tag = 3;
- constructed[cConstructed].pvStructInfo = &info->cExtension;
- constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
- items[cItem].pvStructInfo = &constructed[cConstructed];
+ constructed.tag = 3;
+ constructed.pvStructInfo = &info->cExtension;
+ constructed.encodeFunc = CRYPT_AsnEncodeExtensions;
+ items[cItem].pvStructInfo = &constructed;
items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
- cConstructed++;
cItem++;
}
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
- DWORD cPolicyQualifier = *(DWORD *)pvStructInfo;
- const CERT_POLICY_QUALIFIER_INFO *rgPolicyQualifier =
- *(const CERT_POLICY_QUALIFIER_INFO **)
- ((LPBYTE)pvStructInfo + sizeof(DWORD));
+ const CERT_POLICY_INFO *info = pvStructInfo;
BOOL ret;
- if (!cPolicyQualifier)
+ if (!info->cPolicyQualifier)
{
*pcbEncoded = 0;
ret = TRUE;
DWORD bytesNeeded = 0, lenBytes, size, i;
ret = TRUE;
- for (i = 0; ret && i < cPolicyQualifier; i++)
+ for (i = 0; ret && i < info->cPolicyQualifier; i++)
{
- items[0].pvStructInfo = rgPolicyQualifier[i].pszPolicyQualifierId;
- items[1].pvStructInfo = &rgPolicyQualifier[i].Qualifier;
+ items[0].pvStructInfo =
+ info->rgPolicyQualifier[i].pszPolicyQualifierId;
+ items[1].pvStructInfo = &info->rgPolicyQualifier[i].Qualifier;
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]),
dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
&lenBytes);
pbEncoded += lenBytes;
- for (i = 0; ret && i < cPolicyQualifier; i++)
+ for (i = 0; ret && i < info->cPolicyQualifier; i++)
{
items[0].pvStructInfo =
- rgPolicyQualifier[i].pszPolicyQualifierId;
+ info->rgPolicyQualifier[i].pszPolicyQualifierId;
items[1].pvStructInfo =
- &rgPolicyQualifier[i].Qualifier;
+ &info->rgPolicyQualifier[i].Qualifier;
size = bytesNeeded;
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]),
{
struct AsnEncodeSequenceItem items[2] = {
{ info->pszPolicyIdentifier, CRYPT_AsnEncodeOid, 0 },
- { &info->cPolicyQualifier, CRYPT_AsnEncodeCertPolicyQualifiers, 0 },
+ { info, CRYPT_AsnEncodeCertPolicyQualifiers, 0 },
};
BOOL ret;
return ret;
}
+static BOOL CRYPT_AsnEncodeCertPolicyMapping(DWORD dwCertEncodingType,
+ const CERT_POLICY_MAPPING *mapping, DWORD dwFlags, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+ struct AsnEncodeSequenceItem items[] = {
+ { mapping->pszIssuerDomainPolicy, CRYPT_AsnEncodeOid, 0 },
+ { mapping->pszSubjectDomainPolicy, CRYPT_AsnEncodeOid, 0 },
+ };
+
+ if (!mapping->pszIssuerDomainPolicy || !mapping->pszSubjectDomainPolicy)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
+ sizeof(items) / sizeof(items[0]), dwFlags, NULL, pbEncoded, pcbEncoded);
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeCertPolicyMappings(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret = FALSE;
+
+ __TRY
+ {
+ const CERT_POLICY_MAPPINGS_INFO *info = pvStructInfo;
+ DWORD bytesNeeded = 0, lenBytes, size, i;
+
+ ret = TRUE;
+ for (i = 0; ret && i < info->cPolicyMapping; i++)
+ {
+ ret = CRYPT_AsnEncodeCertPolicyMapping(dwCertEncodingType,
+ &info->rgPolicyMapping[i], dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
+ NULL, &size);
+ if (ret)
+ bytesNeeded += size;
+ }
+ CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
+ bytesNeeded += 1 + lenBytes;
+ if (ret)
+ {
+ 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(bytesNeeded - lenBytes - 1, pbEncoded,
+ &lenBytes);
+ pbEncoded += lenBytes;
+ for (i = 0; ret && i < info->cPolicyMapping; i++)
+ {
+ size = bytesNeeded;
+ ret = CRYPT_AsnEncodeCertPolicyMapping(
+ dwCertEncodingType, &info->rgPolicyMapping[i],
+ dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pbEncoded, &size);
+ if (ret)
+ {
+ pbEncoded += size;
+ bytesNeeded -= size;
+ }
+ }
+ }
+ }
+ }
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ }
+ __ENDTRY
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeCertPolicyConstraints(
+ DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+ BOOL ret = FALSE;
+
+ __TRY
+ {
+ const CERT_POLICY_CONSTRAINTS_INFO *info = pvStructInfo;
+ struct AsnEncodeSequenceItem items[2];
+ struct AsnEncodeTagSwappedItem swapped[2];
+ DWORD cItem = 0, cSwapped = 0;
+
+ if (info->fRequireExplicitPolicy)
+ {
+ swapped[cSwapped].tag = ASN_CONTEXT | 0;
+ swapped[cSwapped].pvStructInfo =
+ &info->dwRequireExplicitPolicySkipCerts;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
+ items[cItem].pvStructInfo = &swapped[cSwapped];
+ items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+ cSwapped++;
+ cItem++;
+ }
+ if (info->fInhibitPolicyMapping)
+ {
+ swapped[cSwapped].tag = ASN_CONTEXT | 1;
+ swapped[cSwapped].pvStructInfo =
+ &info->dwInhibitPolicyMappingSkipCerts;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
+ items[cItem].pvStructInfo = &swapped[cSwapped];
+ items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+ cSwapped++;
+ cItem++;
+ }
+ ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
+ dwFlags, NULL, pbEncoded, pcbEncoded);
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ }
+ __ENDTRY
+ return ret;
+}
+
static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
case LOWORD(X509_NAME_CONSTRAINTS):
encodeFunc = CRYPT_AsnEncodeNameConstraints;
break;
+ case LOWORD(X509_POLICY_MAPPINGS):
+ encodeFunc = CRYPT_AsnEncodeCertPolicyMappings;
+ break;
+ case LOWORD(X509_POLICY_CONSTRAINTS):
+ encodeFunc = CRYPT_AsnEncodeCertPolicyConstraints;
+ break;
case LOWORD(PKCS7_SIGNER_INFO):
encodeFunc = CRYPT_AsnEncodePKCSSignerInfo;
break;
encodeFunc = CRYPT_AsnEncodeUtcTime;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
+ else if (!strcmp(lpszStructType, szOID_LEGACY_POLICY_MAPPINGS))
+ encodeFunc = CRYPT_AsnEncodeCertPolicyMappings;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
else if (!strcmp(lpszStructType, szOID_CERT_POLICIES))
encodeFunc = CRYPT_AsnEncodeCertPolicies;
+ else if (!strcmp(lpszStructType, szOID_POLICY_MAPPINGS))
+ encodeFunc = CRYPT_AsnEncodeCertPolicyMappings;
+ else if (!strcmp(lpszStructType, szOID_POLICY_CONSTRAINTS))
+ encodeFunc = CRYPT_AsnEncodeCertPolicyConstraints;
else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
}
else
{
+ *pcbInfo = sizeNeeded;
pInfo->Algorithm.pszObjId = (char *)pInfo +
sizeof(CERT_PUBLIC_KEY_INFO);
lstrcpyA(pInfo->Algorithm.pszObjId,
if (store->dirty)
CertSaveStore(store->memStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0);
- CertCloseStore(store->memStore, dwFlags);
CloseHandle(store->file);
CryptMemFree(store);
}
{
HCRYPTPROV prov;
- CryptAcquireContextW(&prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT);
+ if (!CryptAcquireContextW(&prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ return hDefProv;
InterlockedCompareExchangePointer((PVOID *)&hDefProv, (PVOID)prov,
NULL);
if (hDefProv != prov)
return ret;
}
-typedef struct _BlobArray
-{
- DWORD cBlobs;
- PCRYPT_DATA_BLOB blobs;
-} BlobArray;
-
-static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in)
+static BOOL CRYPT_ConstructBlobArray(DWORD *outCBlobs,
+ PCRYPT_DATA_BLOB *outPBlobs, DWORD cBlobs, const PCRYPT_DATA_BLOB pBlobs)
{
BOOL ret = TRUE;
- out->cBlobs = in->cBlobs;
- if (out->cBlobs)
+ *outCBlobs = cBlobs;
+ if (cBlobs)
{
- out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
- if (out->blobs)
+ *outPBlobs = CryptMemAlloc(cBlobs * sizeof(CRYPT_DATA_BLOB));
+ if (*outPBlobs)
{
DWORD i;
- memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
- for (i = 0; ret && i < out->cBlobs; i++)
- ret = CRYPT_ConstructBlob(&out->blobs[i], &in->blobs[i]);
+ memset(*outPBlobs, 0, cBlobs * sizeof(CRYPT_DATA_BLOB));
+ for (i = 0; ret && i < cBlobs; i++)
+ ret = CRYPT_ConstructBlob(&(*outPBlobs)[i], &pBlobs[i]);
}
else
ret = FALSE;
return ret;
}
-static void CRYPT_FreeBlobArray(BlobArray *array)
+static void CRYPT_FreeBlobArray(DWORD cBlobs, PCRYPT_DATA_BLOB blobs)
{
DWORD i;
- for (i = 0; i < array->cBlobs; i++)
- CryptMemFree(array->blobs[i].pbData);
- CryptMemFree(array->blobs);
+ for (i = 0; i < cBlobs; i++)
+ CryptMemFree(blobs[i].pbData);
+ CryptMemFree(blobs);
}
static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out,
if (out->pszObjId)
{
strcpy(out->pszObjId, in->pszObjId);
- ret = CRYPT_ConstructBlobArray((BlobArray *)&out->cValue,
- (const BlobArray *)&in->cValue);
+ ret = CRYPT_ConstructBlobArray(&out->cValue, &out->rgValue,
+ in->cValue, in->rgValue);
}
else
ret = FALSE;
CryptMemFree(msg->innerOID);
CryptMemFree(msg->data.pbData);
- CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded);
- CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded);
+ CRYPT_FreeBlobArray(msg->msg_data.info->cCertEncoded,
+ msg->msg_data.info->rgCertEncoded);
+ CRYPT_FreeBlobArray(msg->msg_data.info->cCrlEncoded,
+ msg->msg_data.info->rgCrlEncoded);
for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
CSignedMsgData_CloseHandles(&msg->msg_data);
}
}
if (ret)
- ret = CRYPT_ConstructBlobArray(
- (BlobArray *)&msg->msg_data.info->cCertEncoded,
- (const BlobArray *)&info->cCertEncoded);
+ ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCertEncoded,
+ &msg->msg_data.info->rgCertEncoded, info->cCertEncoded,
+ info->rgCertEncoded);
if (ret)
- ret = CRYPT_ConstructBlobArray(
- (BlobArray *)&msg->msg_data.info->cCrlEncoded,
- (const BlobArray *)&info->cCrlEncoded);
+ ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCrlEncoded,
+ &msg->msg_data.info->rgCrlEncoded, info->cCrlEncoded,
+ info->rgCrlEncoded);
if (!ret)
{
CSignedEncodeMsg_Close(msg);
return ret;
}
-static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
- const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
+static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
+ DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
{
- LPCWSTR fileName = pvObject;
HANDLE file;
BOOL ret = FALSE;
- if (dwObjectType != CERT_QUERY_OBJECT_FILE)
- {
- FIXME("unimplemented for non-file type %d\n", dwObjectType);
- SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
- return FALSE;
- }
TRACE("%s\n", debugstr_w(fileName));
file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
return ret;
}
+static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
+ DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
+ HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
+{
+ HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
+ CERT_STORE_CREATE_NEW_FLAG, NULL);
+ BOOL ret;
+
+ TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
+
+ ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
+ if (ret)
+ {
+ if (pdwMsgAndCertEncodingType)
+ *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
+ if (pdwContentType)
+ *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
+ if (phCertStore)
+ *phCertStore = CertDuplicateStore(store);
+ }
+ CertCloseStore(store, 0);
+ TRACE("returning %d\n", ret);
+ return ret;
+}
+
+static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
+ const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
+ HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
+{
+ switch (dwObjectType)
+ {
+ case CERT_QUERY_OBJECT_FILE:
+ return CRYPT_QuerySerializedStoreFromFile(pvObject,
+ pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
+ case CERT_QUERY_OBJECT_BLOB:
+ return CRYPT_QuerySerializedStoreFromBlob(pvObject,
+ pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
+ default:
+ FIXME("unimplemented for type %d\n", dwObjectType);
+ SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
+ return FALSE;
+ }
+}
+
static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
{
{
if (pdwFormatType)
*pdwFormatType = formatType;
- if (phMsg)
- *phMsg = msg;
if (phCertStore)
*phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
0, msg);
+ if (phMsg)
+ *phMsg = msg;
+ else
+ CryptMsgClose(msg);
}
if (blob == &fileBlob)
CryptMemFree(blob->pbData);
{
DWORD len = CRYPT_GetMultiStringCharacterLen(multi);
- /* Copy remainder of string "left" */
- memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1,
- (len - (spotToRemove - multi)) * sizeof(WCHAR));
+ if (spotToRemove + lstrlenW(toRemove) + 2 >= multi + len)
+ {
+ /* Removing last string in list, terminate multi string directly */
+ *spotToRemove = 0;
+ *(spotToRemove + 1) = 0;
+ }
+ else
+ {
+ /* Copy remainder of string "left" */
+ memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1,
+ (len - (spotToRemove - multi)) * sizeof(WCHAR));
+ }
ret = TRUE;
}
else
"chain creation failed");
else
{
- /* The only allowed error is CERT_TRUST_IS_UNTRUSTED_ROOT */
- if (chain->TrustStatus.dwErrorStatus &
- ~CERT_TRUST_IS_UNTRUSTED_ROOT)
+ DWORD allowedErrors = CERT_TRUST_IS_UNTRUSTED_ROOT |
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE |
+ CERT_TRUST_INVALID_BASIC_CONSTRAINTS |
+ CERT_TRUST_IS_NOT_TIME_VALID;
+
+ /* The certificate chain verification only allows certain
+ * invalid CA certs if they're installed locally: CA
+ * certs missing the key usage extension, and CA certs
+ * missing the basic constraints extension. Of course
+ * there's a chicken and egg problem: we have to accept
+ * them here in order for them to be accepted later.
+ * Expired, locally installed certs are also allowed here,
+ * because we don't know (yet) what date will be checked
+ * for an item signed by one of these certs.
+ * Thus, accept certs with any of the allowed errors.
+ */
+ if (chain->TrustStatus.dwErrorStatus & ~allowedErrors)
TRACE("rejecting %s: %s\n", get_cert_common_name(cert),
trust_status_to_str(chain->TrustStatus.dwErrorStatus &
~CERT_TRUST_IS_UNTRUSTED_ROOT));
ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE);
check_and_store_certs(from, store);
}
+ CertCloseStore(from, 0);
}
static HCERTSTORE create_root_store(void)
static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
-BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
+typedef BOOL (*read_serialized_func)(void *handle, void *buffer,
+ DWORD bytesToRead, DWORD *bytesRead);
+
+static BOOL CRYPT_ReadSerializedStore(void *handle,
+ read_serialized_func read_func, HCERTSTORE store)
{
BYTE fileHeaderBuf[sizeof(fileHeader)];
DWORD read;
BOOL ret;
/* Failure reading is non-critical, we'll leave the store empty */
- ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL);
+ ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read);
if (ret)
{
if (!read)
DWORD bufSize = 0;
do {
- ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL);
+ ret = read_func(handle, &propHdr, sizeof(propHdr), &read);
if (ret && read == sizeof(propHdr))
{
if (contextInterface && context &&
}
if (buf)
{
- ret = ReadFile(file, buf, propHdr.cb, &read, NULL);
+ ret = read_func(handle, buf, propHdr.cb, &read);
if (ret && read == propHdr.cb)
{
if (propHdr.propID == CERT_CERT_PROP_ID)
CERT_STORE_ADD_NEW, &context);
}
else
- ret = CRYPT_ReadContextProp(contextInterface,
- context, &propHdr, buf, read);
+ {
+ if (!contextInterface)
+ {
+ WARN("prop id %d before a context id\n",
+ propHdr.propID);
+ ret = FALSE;
+ }
+ else
+ ret = CRYPT_ReadContextProp(
+ contextInterface, context, &propHdr, buf,
+ read);
+ }
}
}
else
return ret;
}
+static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead,
+ DWORD *bytesRead)
+{
+ return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL);
+}
+
+BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
+{
+ return CRYPT_ReadSerializedStore(file, read_file_wrapper, store);
+}
+
+struct BlobReader
+{
+ const CRYPT_DATA_BLOB *blob;
+ DWORD current;
+};
+
+static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead,
+ DWORD *bytesRead)
+{
+ struct BlobReader *reader = handle;
+ BOOL ret;
+
+ if (reader->current < reader->blob->cbData)
+ {
+ *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current);
+ memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead);
+ ret = TRUE;
+ }
+ else
+ ret = FALSE;
+ return ret;
+}
+
+BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
+ HCERTSTORE store)
+{
+ struct BlobReader reader = { blob, 0 };
+
+ return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store);
+}
+
static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
{
static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
{
WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
+ BOOL ret;
- ContextList_Delete(ms->certs, pCertContext);
- return TRUE;
+ if (ContextList_Remove(ms->certs, pCertContext))
+ ret = CertFreeCertificateContext(pCertContext);
+ else
+ ret = TRUE;
+ return ret;
}
static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
{
WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
+ BOOL ret;
- ContextList_Delete(ms->crls, pCrlContext);
- return TRUE;
+ if (ContextList_Remove(ms->crls, pCrlContext))
+ ret = CertFreeCRLContext(pCrlContext);
+ else
+ ret = TRUE;
+ return ret;
}
static BOOL CRYPT_MemAddCtl(PWINECRYPT_CERTSTORE store, void *ctl,
static BOOL CRYPT_MemDeleteCtl(PWINECRYPT_CERTSTORE store, void *pCtlContext)
{
WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
+ BOOL ret;
- ContextList_Delete(ms->ctls, pCtlContext);
- return TRUE;
+ if (ContextList_Remove(ms->ctls, pCtlContext))
+ ret = CertFreeCTLContext(pCtlContext);
+ else
+ ret = TRUE;
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_MemControl(HCERTSTORE hCertStore, DWORD dwFlags,
+ DWORD dwCtrlType, void const *pvCtrlPara)
+{
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
}
static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
store->hdr.ctls.addContext = CRYPT_MemAddCtl;
store->hdr.ctls.enumContext = CRYPT_MemEnumCtl;
store->hdr.ctls.deleteContext = CRYPT_MemDeleteCtl;
- store->hdr.control = NULL;
+ store->hdr.control = CRYPT_MemControl;
store->certs = ContextList_Create(pCertInterface,
sizeof(CERT_CONTEXT));
store->crls = ContextList_Create(pCRLInterface,
if (!pCertContext)
ret = TRUE;
else if (!pCertContext->hCertStore)
- {
- ret = TRUE;
- CertFreeCertificateContext(pCertContext);
- }
+ ret = CertFreeCertificateContext(pCertContext);
else
{
PWINECRYPT_CERTSTORE hcs = pCertContext->hCertStore;
else
ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
if (ret)
- CertFreeCertificateContext(pCertContext);
+ ret = CertFreeCertificateContext(pCertContext);
}
return ret;
}
if (!pCrlContext)
ret = TRUE;
else if (!pCrlContext->hCertStore)
- {
- ret = TRUE;
- CertFreeCRLContext(pCrlContext);
- }
+ ret = CertFreeCRLContext(pCrlContext);
else
{
PWINECRYPT_CERTSTORE hcs = pCrlContext->hCertStore;
ret = FALSE;
else
ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
- CertFreeCRLContext(pCrlContext);
+ if (ret)
+ ret = CertFreeCRLContext(pCrlContext);
}
return ret;
}
if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
return FALSE;
+ if (hcs->ref <= 0)
+ ERR("%p's ref count is %d\n", hcs, hcs->ref);
if (InterlockedDecrement(&hcs->ref) == 0)
{
TRACE("%p's ref count is 0, freeing\n", hcs);
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
+
+#define NONAMELESSUNION
+
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
if (entry)
{
if (!pszNameString)
- ret = strlenW(entry->pwszRfc822Name) + 1;
+ ret = strlenW(entry->u.pwszRfc822Name) + 1;
else if (cchNameString)
{
- ret = min(strlenW(entry->pwszRfc822Name), cchNameString - 1);
- memcpy(pszNameString, entry->pwszRfc822Name,
+ ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1);
+ memcpy(pszNameString, entry->u.pwszRfc822Name,
ret * sizeof(WCHAR));
pszNameString[ret++] = 0;
}
if (entry)
ret = CertNameToStrW(pCertContext->dwCertEncodingType,
- &entry->DirectoryName, *(DWORD *)pvTypePara, pszNameString,
+ &entry->u.DirectoryName, *(DWORD *)pvTypePara, pszNameString,
cchNameString);
if (info)
LocalFree(info);
if (entry)
ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0,
- &entry->DirectoryName, 0, pszNameString, cchNameString);
+ &entry->u.DirectoryName, 0, pszNameString, cchNameString);
if (altInfo)
LocalFree(altInfo);
}
if (entry)
{
if (!pszNameString)
- ret = strlenW(entry->pwszRfc822Name) + 1;
+ ret = strlenW(entry->u.pwszRfc822Name) + 1;
else if (cchNameString)
{
- ret = min(strlenW(entry->pwszRfc822Name),
+ ret = min(strlenW(entry->u.pwszRfc822Name),
cchNameString - 1);
- memcpy(pszNameString, entry->pwszRfc822Name,
+ memcpy(pszNameString, entry->u.pwszRfc822Name,
ret * sizeof(WCHAR));
pszNameString[ret++] = 0;
}
if (entry)
{
if (!pszNameString)
- ret = strlenW(entry->pwszDNSName) + 1;
+ ret = strlenW(entry->u.pwszDNSName) + 1;
else if (cchNameString)
{
- ret = min(strlenW(entry->pwszDNSName), cchNameString - 1);
- memcpy(pszNameString, entry->pwszDNSName, ret * sizeof(WCHAR));
+ ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1);
+ memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR));
pszNameString[ret++] = 0;
}
}
if (entry)
{
if (!pszNameString)
- ret = strlenW(entry->pwszURL) + 1;
+ ret = strlenW(entry->u.pwszURL) + 1;
else if (cchNameString)
{
- ret = min(strlenW(entry->pwszURL), cchNameString - 1);
- memcpy(pszNameString, entry->pwszURL, ret * sizeof(WCHAR));
+ ret = min(strlenW(entry->u.pwszURL), cchNameString - 1);
+ memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR));
pszNameString[ret++] = 0;
}
}
#define CRYPT_STRING_BASE64X509CRLHEADER 0x00000009
#define CRYPT_STRING_HEXADDR 0x0000000a
#define CRYPT_STRING_HEXASCIIADDR 0x0000000b
+#define CRYPT_STRING_NOCRLF 0x40000000
#define CRYPT_STRING_NOCR 0x80000000
/* OIDs */
#define szOID_POLICY_CONSTRAINTS "2.5.29.36"
#define szOID_ENHANCED_KEY_USAGE "2.5.29.37"
#define szOID_FRESHEST_CRL "2.5.29.46"
+#define szOID_INHIBIT_ANY_POLICY "2.5.29.54"
#define szOID_DOMAIN_COMPONENT "0.9.2342.19200300.100.1.25"
#define szOID_PKCS_12_FRIENDLY_NAME_ATTR "1.2.840.113549.1.9.20"
#define szOID_PKCS_12_LOCAL_KEY_ID "1.2.840.113549.1.9.21"
DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext);
+BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
+ const BYTE *pbCertEncoded, DWORD cbCertEncoded);
+BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
+ const BYTE *pbCertEncoded, DWORD cbCertEncoded);
+#define CertAddEncodedCertificateToSystemStore \
+ WINELIB_NAME_AW(CertAddEncodedCertificateToSystemStore)
+
BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext);
BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement);
+BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
+ PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage);
+
BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage);
BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,