crypt32: Implement CertCompare functions, with tests.
This commit is contained in:
parent
36a8e5fba3
commit
d0505de674
|
@ -29,6 +29,94 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||||
|
|
||||||
|
BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
|
||||||
|
PCERT_INFO pCertId1, PCERT_INFO pCertId2)
|
||||||
|
{
|
||||||
|
TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
|
||||||
|
|
||||||
|
return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
|
||||||
|
&pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
|
||||||
|
&pCertId2->SerialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
|
||||||
|
PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
|
||||||
|
|
||||||
|
if (pCertName1->cbData == pCertName2->cbData)
|
||||||
|
{
|
||||||
|
if (pCertName1->cbData)
|
||||||
|
ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
|
||||||
|
pCertName1->cbData);
|
||||||
|
else
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of significant bytes in pInt, where a byte is
|
||||||
|
* insignificant if it's a leading 0 for positive numbers or a leading 0xff
|
||||||
|
* for negative numbers. pInt is assumed to be little-endian.
|
||||||
|
*/
|
||||||
|
static DWORD CRYPT_significantBytes(PCRYPT_INTEGER_BLOB pInt)
|
||||||
|
{
|
||||||
|
DWORD ret = pInt->cbData;
|
||||||
|
|
||||||
|
while (ret > 1)
|
||||||
|
{
|
||||||
|
if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
|
||||||
|
ret--;
|
||||||
|
else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
|
||||||
|
ret--;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
|
||||||
|
PCRYPT_INTEGER_BLOB pInt2)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
DWORD cb1, cb2;
|
||||||
|
|
||||||
|
TRACE("(%p, %p)\n", pInt1, pInt2);
|
||||||
|
|
||||||
|
cb1 = CRYPT_significantBytes(pInt1);
|
||||||
|
cb2 = CRYPT_significantBytes(pInt2);
|
||||||
|
if (cb1 == cb2)
|
||||||
|
ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1);
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
|
||||||
|
PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
|
||||||
|
|
||||||
|
if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
|
||||||
|
pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
|
||||||
|
{
|
||||||
|
if (pPublicKey2->PublicKey.cbData)
|
||||||
|
ret = !memcmp(pPublicKey1->PublicKey.pbData,
|
||||||
|
pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
|
||||||
|
else
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
|
PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
|
||||||
CRYPT_ATTRIBUTE rgAttr[])
|
CRYPT_ATTRIBUTE rgAttr[])
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
@ stdcall CertAddStoreToCollection(ptr ptr long long)
|
@ stdcall CertAddStoreToCollection(ptr ptr long long)
|
||||||
@ stdcall CertAlgIdToOID(long)
|
@ stdcall CertAlgIdToOID(long)
|
||||||
@ stdcall CertCloseStore(ptr long)
|
@ stdcall CertCloseStore(ptr long)
|
||||||
@ stub CertCompareCertificate
|
@ stdcall CertCompareCertificate(long ptr ptr)
|
||||||
@ stub CertCompareCertificateName
|
@ stdcall CertCompareCertificateName(long ptr ptr)
|
||||||
@ stub CertCompareIntegerBlob
|
@ stdcall CertCompareIntegerBlob(ptr ptr)
|
||||||
@ stub CertComparePublicKeyInfo
|
@ stdcall CertComparePublicKeyInfo(long ptr ptr)
|
||||||
@ stdcall CertControlStore(long long long ptr)
|
@ stdcall CertControlStore(long long long ptr)
|
||||||
@ stdcall CertCreateCRLContext(long ptr long)
|
@ stdcall CertCreateCRLContext(long ptr long)
|
||||||
@ stdcall CertCreateCTLContext(long ptr long)
|
@ stdcall CertCreateCTLContext(long ptr long)
|
||||||
|
|
|
@ -682,6 +682,160 @@ static void testKeyUsage(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testCompareCertName(void)
|
||||||
|
{
|
||||||
|
static const BYTE bogus[] = { 1, 2, 3, 4 };
|
||||||
|
static const BYTE bogusPrime[] = { 0, 1, 2, 3, 4 };
|
||||||
|
static const BYTE emptyPrime[] = { 0x30, 0x00, 0x01 };
|
||||||
|
BOOL ret;
|
||||||
|
CERT_NAME_BLOB blob1, blob2;
|
||||||
|
|
||||||
|
/* crashes
|
||||||
|
ret = CertCompareCertificateName(0, NULL, NULL);
|
||||||
|
*/
|
||||||
|
/* An empty name checks against itself.. */
|
||||||
|
blob1.pbData = (LPBYTE)emptyCert;
|
||||||
|
blob1.cbData = sizeof(emptyCert);
|
||||||
|
ret = CertCompareCertificateName(0, &blob1, &blob1);
|
||||||
|
ok(ret, "CertCompareCertificateName failed: %08lx\n", GetLastError());
|
||||||
|
/* It doesn't have to be a valid encoded name.. */
|
||||||
|
blob1.pbData = (LPBYTE)bogus;
|
||||||
|
blob1.cbData = sizeof(bogus);
|
||||||
|
ret = CertCompareCertificateName(0, &blob1, &blob1);
|
||||||
|
ok(ret, "CertCompareCertificateName failed: %08lx\n", GetLastError());
|
||||||
|
/* Leading zeroes matter.. */
|
||||||
|
blob2.pbData = (LPBYTE)bogusPrime;
|
||||||
|
blob2.cbData = sizeof(bogusPrime);
|
||||||
|
ret = CertCompareCertificateName(0, &blob1, &blob2);
|
||||||
|
ok(!ret, "Expected failure\n");
|
||||||
|
/* As do trailing extra bytes. */
|
||||||
|
blob2.pbData = (LPBYTE)emptyPrime;
|
||||||
|
blob2.cbData = sizeof(emptyPrime);
|
||||||
|
ret = CertCompareCertificateName(0, &blob1, &blob2);
|
||||||
|
ok(!ret, "Expected failure\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const BYTE int1[] = { 0x88, 0xff, 0xff, 0xff };
|
||||||
|
static const BYTE int2[] = { 0x88, 0xff };
|
||||||
|
static const BYTE int3[] = { 0x23, 0xff };
|
||||||
|
static const BYTE int4[] = { 0x7f, 0x00 };
|
||||||
|
static const BYTE int5[] = { 0x7f };
|
||||||
|
static const BYTE int6[] = { 0x80, 0x00, 0x00, 0x00 };
|
||||||
|
static const BYTE int7[] = { 0x80, 0x00 };
|
||||||
|
|
||||||
|
struct IntBlobTest
|
||||||
|
{
|
||||||
|
CRYPT_INTEGER_BLOB blob1;
|
||||||
|
CRYPT_INTEGER_BLOB blob2;
|
||||||
|
BOOL areEqual;
|
||||||
|
} intBlobs[] = {
|
||||||
|
{ { sizeof(int1), (LPBYTE)int1 }, { sizeof(int2), (LPBYTE)int2 }, TRUE },
|
||||||
|
{ { sizeof(int3), (LPBYTE)int3 }, { sizeof(int3), (LPBYTE)int3 }, TRUE },
|
||||||
|
{ { sizeof(int4), (LPBYTE)int4 }, { sizeof(int5), (LPBYTE)int5 }, TRUE },
|
||||||
|
{ { sizeof(int6), (LPBYTE)int6 }, { sizeof(int7), (LPBYTE)int7 }, TRUE },
|
||||||
|
{ { sizeof(int1), (LPBYTE)int1 }, { sizeof(int7), (LPBYTE)int7 }, FALSE },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void testCompareIntegerBlob(void)
|
||||||
|
{
|
||||||
|
DWORD i;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(intBlobs) / sizeof(intBlobs[0]); i++)
|
||||||
|
{
|
||||||
|
ret = CertCompareIntegerBlob(&intBlobs[i].blob1, &intBlobs[i].blob2);
|
||||||
|
ok(ret == intBlobs[i].areEqual,
|
||||||
|
"%ld: expected blobs %s compare\n", i, intBlobs[i].areEqual ?
|
||||||
|
"to" : "not to");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testComparePublicKeyInfo(void)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
CERT_PUBLIC_KEY_INFO info1 = { { 0 } }, info2 = { { 0 } };
|
||||||
|
static const BYTE bits1[] = { 1, 0 };
|
||||||
|
static const BYTE bits2[] = { 0 };
|
||||||
|
static const BYTE bits3[] = { 1 };
|
||||||
|
|
||||||
|
/* crashes
|
||||||
|
ret = CertComparePublicKeyInfo(0, NULL, NULL);
|
||||||
|
*/
|
||||||
|
/* Empty public keys compare */
|
||||||
|
ret = CertComparePublicKeyInfo(0, &info1, &info2);
|
||||||
|
ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
|
||||||
|
/* Different OIDs appear to compare */
|
||||||
|
info1.Algorithm.pszObjId = szOID_RSA_RSA;
|
||||||
|
info2.Algorithm.pszObjId = szOID_RSA_SHA1RSA;
|
||||||
|
ret = CertComparePublicKeyInfo(0, &info1, &info2);
|
||||||
|
ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
|
||||||
|
info2.Algorithm.pszObjId = szOID_X957_DSA;
|
||||||
|
ret = CertComparePublicKeyInfo(0, &info1, &info2);
|
||||||
|
ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
|
||||||
|
info1.PublicKey.cbData = sizeof(bits1);
|
||||||
|
info1.PublicKey.pbData = (LPBYTE)bits1;
|
||||||
|
info1.PublicKey.cUnusedBits = 0;
|
||||||
|
info2.PublicKey.cbData = sizeof(bits1);
|
||||||
|
info2.PublicKey.pbData = (LPBYTE)bits1;
|
||||||
|
info2.PublicKey.cUnusedBits = 0;
|
||||||
|
ret = CertComparePublicKeyInfo(0, &info1, &info2);
|
||||||
|
ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
|
||||||
|
/* Even though they compare in their used bits, these do not compare */
|
||||||
|
info1.PublicKey.cbData = sizeof(bits2);
|
||||||
|
info1.PublicKey.pbData = (LPBYTE)bits2;
|
||||||
|
info1.PublicKey.cUnusedBits = 0;
|
||||||
|
info2.PublicKey.cbData = sizeof(bits3);
|
||||||
|
info2.PublicKey.pbData = (LPBYTE)bits3;
|
||||||
|
info2.PublicKey.cUnusedBits = 1;
|
||||||
|
ret = CertComparePublicKeyInfo(0, &info1, &info2);
|
||||||
|
/* Simple (non-comparing) case */
|
||||||
|
ok(!ret, "Expected keys not to compare\n");
|
||||||
|
info2.PublicKey.cbData = sizeof(bits1);
|
||||||
|
info2.PublicKey.pbData = (LPBYTE)bits1;
|
||||||
|
info2.PublicKey.cUnusedBits = 0;
|
||||||
|
ret = CertComparePublicKeyInfo(0, &info1, &info2);
|
||||||
|
ok(!ret, "Expected keys not to compare\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const BYTE subjectName2[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
|
||||||
|
0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61,
|
||||||
|
0x6e, 0x67, 0x00 };
|
||||||
|
|
||||||
|
static const BYTE serialNum[] = { 1 };
|
||||||
|
|
||||||
|
void testCompareCert(void)
|
||||||
|
{
|
||||||
|
CERT_INFO info1 = { 0 }, info2 = { 0 };
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
/* Crashes
|
||||||
|
ret = CertCompareCertificate(X509_ASN_ENCODING, NULL, NULL);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Certs with the same issuer and serial number are equal, even if they
|
||||||
|
* differ in other respects (like subject).
|
||||||
|
*/
|
||||||
|
info1.SerialNumber.pbData = (LPBYTE)serialNum;
|
||||||
|
info1.SerialNumber.cbData = sizeof(serialNum);
|
||||||
|
info1.Issuer.pbData = (LPBYTE)subjectName;
|
||||||
|
info1.Issuer.cbData = sizeof(subjectName);
|
||||||
|
info1.Subject.pbData = (LPBYTE)subjectName2;
|
||||||
|
info1.Subject.cbData = sizeof(subjectName2);
|
||||||
|
info2.SerialNumber.pbData = (LPBYTE)serialNum;
|
||||||
|
info2.SerialNumber.cbData = sizeof(serialNum);
|
||||||
|
info2.Issuer.pbData = (LPBYTE)subjectName;
|
||||||
|
info2.Issuer.cbData = sizeof(subjectName);
|
||||||
|
info2.Subject.pbData = (LPBYTE)subjectName;
|
||||||
|
info2.Subject.cbData = sizeof(subjectName);
|
||||||
|
ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2);
|
||||||
|
ok(ret, "Expected certs to be equal\n");
|
||||||
|
|
||||||
|
info2.Issuer.pbData = (LPBYTE)subjectName2;
|
||||||
|
info2.Issuer.cbData = sizeof(subjectName2);
|
||||||
|
ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2);
|
||||||
|
ok(!ret, "Expected certs not to be equal\n");
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(cert)
|
START_TEST(cert)
|
||||||
{
|
{
|
||||||
init_function_pointers();
|
init_function_pointers();
|
||||||
|
@ -689,4 +843,8 @@ START_TEST(cert)
|
||||||
testCertSigs();
|
testCertSigs();
|
||||||
testCreateSelfSignCert();
|
testCreateSelfSignCert();
|
||||||
testKeyUsage();
|
testKeyUsage();
|
||||||
|
testCompareCertName();
|
||||||
|
testCompareIntegerBlob();
|
||||||
|
testComparePublicKeyInfo();
|
||||||
|
testCompareCert();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2693,6 +2693,15 @@ BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
|
||||||
const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
|
const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
|
||||||
DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext);
|
DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext);
|
||||||
|
|
||||||
|
BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
|
||||||
|
PCERT_INFO pCertId1, PCERT_INFO pCertId2);
|
||||||
|
BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
|
||||||
|
PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2);
|
||||||
|
BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
|
||||||
|
PCRYPT_INTEGER_BLOB pInt2);
|
||||||
|
BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
|
||||||
|
PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2);
|
||||||
|
|
||||||
const void *CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
|
const void *CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
|
||||||
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||||
PCERT_CREATE_CONTEXT_PARA pCreatePara);
|
PCERT_CREATE_CONTEXT_PARA pCreatePara);
|
||||||
|
|
Loading…
Reference in New Issue