Add Subject Alternate Name to self signed certificate using wincrypt - c++

How to add Subject Alternative Name in the certificate. Using wincrypt I have created and added the certificate to "MY" and "root" path where CN can be machine fully qualified domain name or hostname or IP. As Subject alternate name I want to add the following:DNS name=fully qualified domain name, DNS name=hostname and
DNS name=IP
How to do this?
I do not want to use openssl.
LPCTSTR cnName= fqdn;
DWORD cbEncoded = 0;
if (!CertStrToName(X509_ASN_ENCODING, cnName, CERT_X500_NAME_STR, NULL,
pbdata, &cbData, NULL))
{
_tprintf(_T("CertStrToName failed 0x%x\n"), GetLastError());
return 0;
}
if (!(pbdata = (BYTE *)malloc(cbData)))
{
_tprintf(_T("malloc Error 0x%x\n"), GetLastError());
return 0;
}
if (!CertStrToName(X509_ASN_ENCODING, cnName, CERT_X500_NAME_STR, NULL, pbdata, &cbData, NULL))
{
_tprintf(_T("CertStrToName failed 0x%x\n"), GetLastError());
return 0;
}
CERT_NAME_BLOB IssuerBlob;
IssuerBlob.cbData = cbEncoded;
IssuerBlob.pbData = pbEncoded;
CertCreateSelfSignCertificate(NULL, &IssuerBlob, 0, &KeyProvInfo, &Alg, 0, &EndTime, 0);
OpenandAddCertificateToStore(pCertContext, L"MY");
OpenandAddCertificateToStore(pCertContext, L"Root");
This creates and adds certificate to the store without SAN in the certificate
I tried passing extension list like below:
CertCreateSelfSignCertificate(NULL, &IssuerBlob, 0, &KeyProvInfo, &Alg, 0, &EndTime, &myExtns_list);
CERT_EXTENSION myExtn;
myExtn.fCritical = TRUE;
myExtn.pszObjId = szOID_SUBJECT_ALT_NAME;
myExtn.Value = myBlobdata;
CERT_EXTENSIONS myExtns_list;
myExtns_list.cExtension = 1;
myExtns_list.rgExtension = &myExtn;
char cb[20] = { "DNS Names=abc.com" };
BYTE *pbData = (BYTE*)cb;
CERT_NAME_BLOB myBlobdata;
myBlobdata.cbData = 20;
myBlobdata.pbData = pbData;
with this I could get the SAN as byte format in the left pane and the right pane shows my string "DNS Names=abc.com".
But my requirement is to show only the DNS Names in the SAN.

I'm assuming that your building of the extension data actually happened prior to your call to CertCreateSelfSignedCertificate (and, likewise, that your building of myBlobdata happened before using it).
The main problem is that you used one SAN entry (sort of) as the entirety of the SAN extension; which meant you lost some encoding wrappers. A secondary problem is that you used szOID_SUBJECT_ALT_NAME, which is the incorrect OID for Subject Alternative Name... you actually want szOID_SUBJECT_ALT_NAME2.
I want to add the following:DNS name=fully qualified domain name, DNS name=hostname and DNS name=IP
Adding an IP address as a DNS name is non-standard and is supposed to result in a match failure. You'd actually want to add the IP address as an IP Address SAN entry.
CERT_ALT_NAME_ENTRY entries[3];
entries[0] = { CERT_ALT_NAME_DNS_NAME };
entries[0].pwszDNSName = L"example.org";
// IPv4 Address 10.12.1.130
BYTE ip4Bytes[] = { 10, 12, 1, 130 };
entries[1] = { CERT_ALT_NAME_IP_ADDRESS };
entries[1].IPAddress = { sizeof(ip4Bytes), ip4Bytes };
// ::1, big-endian
BYTE ip6Bytes[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
entries[2] = { CERT_ALT_NAME_IP_ADDRESS };
entries[2].IPAddress = { sizeof(ip6Bytes), ip6Bytes };
CERT_NAME_BLOB name = { cbEncoded, buf };
BYTE extBuf[1024] = { 0 };
cbEncoded = sizeof(extBuf);
CERT_ALT_NAME_INFO info = { sizeof(entries) / sizeof(CERT_ALT_NAME_ENTRY), entries };
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
X509_ALTERNATE_NAME,
&info,
0,
nullptr,
extBuf,
&cbEncoded))
{
// Whatever your error handling story is.
//
// Note I didn't do a 0 buffer or CRYPT_ENCODE_ALLOC; I just knew
// that my buffer would be big enough.
}
CERT_EXTENSION extension = { 0 };
extension.fCritical = 0;
extension.pszObjId = szOID_SUBJECT_ALT_NAME2;
extension.Value = { cbEncoded, extBuf };
CERT_EXTENSIONS extensions = { 1, &extension };
...
PCCERT_CONTEXT cert = CertCreateSelfSignCertificate(
0,
&name,
0,
&keyProvInfo,
&sigAlg,
0,
&certExpirationDate,
&extensions);
In CertUI that gives me the Subject Alternative Name value I expect:
DNS Name=example.org
IP Address=10.12.1.130
IP Address=0000:0000:0000:0000:0000:0000:0000:0001

Related

CertGetCertificateChain with a supporting memory store and Certificate Trust List

I need to mark a custom self-signed root certificate as trusted during certificate chain validation and, overall, I want to rely on the system API as much as possible.
I create a temporary memory store.
HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, 0);
Then I place the custom root certificate into the store.
CertAddCertificateContextToStore(certStore, rootCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0);
The CertGetCertificateChain MSDN documentation says
hAdditionalStore A handle to any additional store to search for supporting certificates and certificate trust lists (CTLs).
As far as I understand if I create a CTL with the root certificate and place it to the store, CertGetCertificateChain will trust it. So, I create the root certificate CTL entry in an allocated buffer and then copy it to std::vector ctlEntries
CertCreateCTLEntryFromCertificateContextProperties(rootCertContext, 0, nullptr, CTL_ENTRY_FROM_PROP_CHAIN_FLAG, nullptr, ctlEntry, &size);
Then I create the CTL itself.
const std::wstring ctlID(L"TrustedRoots");
// I do not know what OIDs to use here. I tried different options.
std::vector<LPSTR> usageList;
usageList.push_back(szOID_SORTED_CTL);
usageList.push_back(szOID_PKIX_KP_CLIENT_AUTH);
usageList.push_back(szOID_PKIX_KP_SERVER_AUTH);
CTL_INFO ctlInfo;
ZeroMemory(&ctlInfo, sizeof(ctlInfo));
ctlInfo.dwVersion = CTL_V1;
ctlInfo.SubjectUsage.cUsageIdentifier = static_cast<DWORD>(usageList.size());
ctlInfo.SubjectUsage.rgpszUsageIdentifier = usageList.data();
ctlInfo.ListIdentifier.cbData = static_cast<DWORD>((ctlID.size() + 1) * sizeof(wchar_t));
ctlInfo.ListIdentifier.pbData = static_cast<BYTE*>(static_cast<void*>(const_cast<wchar_t*>(ctlID.data())));
ctlInfo.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1;
ctlInfo.cCTLEntry = static_cast<DWORD>(ctlEntries.size());
ctlInfo.rgCTLEntry = const_cast<PCTL_ENTRY>(ctlEntries.data());
// From MSDN:
// The message can be encoded without signers if the cbSize member of the structure is set to the
// size of the structure and all of the other members are set to zero.
CMSG_SIGNED_ENCODE_INFO encode;
ZeroMemory(&encode, sizeof(encode));
encode.cbSize = sizeof(encode);
DWORD size = 0, flags = CMSG_ENCODE_SORTED_CTL_FLAG | CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;
if (CryptMsgEncodeAndSignCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &ctlInfo, &encode, flags, nullptr, &size) == TRUE)
{
std::string data;
data.resize(size);
BYTE* p = static_cast<BYTE*>(static_cast<void*>(&data.front()));
if (CryptMsgEncodeAndSignCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &ctlInfo, &encode, flags, p, &size) == TRUE)
{
PCCTL_CONTEXT ctlContext = CertCreateCTLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, p, size);
if (ctlContext)
{
if (CertAddCTLContextToStore(certStore, ctlContext, CERT_STORE_ADD_REPLACE_EXISTING, nullptr) == TRUE)
{
// success
}
}
}
}
All API calls above finish successfully but when I call CertGetCertificateChain, it still returns CERT_TRUST_IS_UNTRUSTED_ROOT in TrustStatus.dwErrorStatus.
Potential Workaround
If I get the CERT_TRUST_IS_UNTRUSTED_ROOT error, I just extract the CTL from the certificate store and check if the root from the result chain (returned by CertGetCertificateChain) is in the CTL. It works but is still not fully acceptable for me. I would like to rely on CertGetCertificateChain.
What is wrong with the solution?
What specific Certificate Trust List OIDs must I use?
Is any requirement (like specific extensions) for the root certificate to be trusted in this case?
p.s. The test certificates are created using this instruction https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309
UPD: 2020-01-31
CertModifyCertificatesToTrust did not help. It finishes successfully but the chain is still reported as having an untrusted root. Probably, the issue is in different area.
PCCERT_CONTEXT copiedCert = nullptr;
BOOL result = CertAddCertificateContextToStore(certStore,
cert, CERT_STORE_ADD_REPLACE_EXISTING, &copiedCert);
CertFreeCertificateContext(cert);
if (result)
{
// Save the certificate to create a CTL entry later
trustedRoots.push_back(copiedCert);
}
...
// Creating the CTL entries
...
std::vector<LPSTR> usageList;
usageList.push_back(szOID_CTL); // I really do not know what IDs I must use here
...
CTL_INFO ctlInfo;
ZeroMemory(&ctlInfo, sizeof(ctlInfo));
ctlInfo.dwVersion = CTL_V1;
ctlInfo.SubjectUsage.cUsageIdentifier = static_cast<DWORD>(usageList.size());
ctlInfo.SubjectUsage.rgpszUsageIdentifier = usageList.data();
...
// Should I use any of the flags?
DWORD size = 0, flags = 0; /*CMSG_ENCODE_SORTED_CTL_FLAG | CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;*/
if (CryptMsgEncodeAndSignCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &ctlInfo, &encode, flags, nullptr, &size) == TRUE)
...
if (CertAddCTLContextToStore(certStore, ctlContext, CERT_STORE_ADD_REPLACE_EXISTING, nullptr) == TRUE)
{
// Check that the CTL is in the store and the root certificate is in the CTL
CTL_FIND_USAGE_PARA usagePara;
ZeroMemory(&usagePara, sizeof(usagePara));
usagePara.cbSize = sizeof(usagePara);
usagePara.SubjectUsage.cUsageIdentifier = 0;
usagePara.ListIdentifier.cbData = static_cast<DWORD>((ctlID.size() + 1) * sizeof(wchar_t));
usagePara.ListIdentifier.pbData = static_cast<BYTE*>(static_cast<void*>(const_cast<wchar_t*>(ctlID.data())));
PCCTL_CONTEXT foundCTLContext = CertFindCTLInStore(certStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CTL_FIND_USAGE,
static_cast<void*>(&usagePara), nullptr);
if (foundCTLContext != nullptr)
{
PCTL_ENTRY ctlEntry = CertFindSubjectInCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CTL_CERT_SUBJECT_TYPE, const_cast<void*>(*trustedRoots.begin()), foundCTLContext, 0);
if (ctlEntry != nullptr)
{
// It means the root certificate has been correctly added to the CTL and the CTL is in the store.
std::cout << "Found the certificate in the CTL" << std::endl;
}
}
// Make the certificate trusted via CertModifyCertificatesToTrust
HMODULE module = LoadLibrary(L"CryptDlg.dll");
if (module)
{
CertModifyCertificatesToTrustPfn pfn =
(CertModifyCertificatesToTrustPfn)GetProcAddress(hModule, "CertModifyCertificatesToTrust");
if (pfn != nullptr)
{
CTL_MODIFY_REQUEST req;
// Only one certificate is in the trustedRoots store curretly
req.pccert = static_cast<PCCERT_CONTEXT>(*trustedRoots.begin());
req.dwOperation = CTL_MODIFY_REQUEST_ADD_TRUSTED;
req.dwError = 0;
HRESULT hr = pfn(1, &req, szOID_CTL, NULL, certStore, nullptr);
if (hr == S_OK)
{
// Success
std::cout << "Modified" << std::endl;
}
}
}
}
You can try to use the following api: CertModifyCertificatesToTrust
And note that
This function has no associated import library. You must use the
LoadLibrary and GetProcAddress functions to dynamically link to
CryptDlg.dll.
Set the CTL_MODIFY_REQUEST.dwOperation to the flagCTL_MODIFY_REQUEST_ADD_TRUSTED to add the certificate to the CTL. The certificate is explicitly trusted.

GSSAPI: Error 0x80090311 returned by InitializeSecurityContext

I need to set up an active directory authentication system using Kerberos. My AcquireCredentialsHandleA class looks as follows. https://learn.microsoft.com/en-us/windows/win32/secauthn/acquirecredentialshandle--kerberos
SEC_WINNT_AUTH_IDENTITY AuthData, *pAuthData = NULL;
#ifdef UNICODE
AuthData.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
AuthData.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif
unsigned char username[200] = "user";
unsigned char domain[200] = "domain.com";
unsigned char password[100] = "secret";
AuthData.User = &username[0]; //username
AuthData.Domain = &domain[0]; //domain
AuthData.Password = &password[0]; //password
AuthData.UserLength = AuthData.User ? sizeof(AuthData.User) : 0;
AuthData.DomainLength = AuthData.Domain ? sizeof(AuthData.Domain) : 0;
AuthData.PasswordLength = AuthData.Password ? sizeof(AuthData.Password) : 0;
Status = g_pSSPI->AcquireCredentialsHandleA(
NULL, // Name of principal //pN
ppPackageInfo[2].Name,//"kerberos" Name of package
SECPKG_CRED_OUTBOUND, // Flags indicating use
NULL, // Pointer to logon ID
pAuthData, //NULL, // Package specific data
NULL, // Pointer to GetKey() func
NULL, // Value to pass to GetKey()
phCreds, // (out) Cred Handle
&tsExpiry
);
This returns Success. However, when I call my InitializeSecurityContextAfunction it gives me 0x80090311 error which means SEC_E_NO_AUTHENTICATING_AUTHORITY. I have tried all sorts of possible domain name etc. When I do ksetup in the powershell it can generate ticket with same credentials. But the code always fails. Can anyone spot any problem here?
dwSSPIFlags = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_CONNECTION; // Not sure at all about them flags
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType = SECBUFFER_TOKEN; //2
//OutBuffers[0].cbBuffer = 0;
OutBuffers[0].cbBuffer = 7084;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION; //0
Status = g_pSSPI->InitializeSecurityContextA
(
phCreds,
fHaveCtxtHandle ? phContext : NULL,//phContext, can be NULL for the first call
server,
dwSSPIFlags,
0,
SECURITY_NETWORK_DREP,//SECURITY_NATIVE_DREP,
fHaveCtxtHandle ? &InBuffer : NULL,
0,
fHaveCtxtHandle ? NULL : phContext ,
&OutBuffer,
&dwSSPIOutFlags,
&tsExpiry
);
Can anyone help me with this? Thanks a lot. :)
--------------------------------------------------------------- edit ---------------------------------------------------------------
std::string fqdn = "HTTP/staging.company.com";
char * server = new char[fqdn.size() + 1];
std::copy(fqdn.begin(), fqdn.end(), server);
server[fqdn.size()] = '\0';
So this is how I set up the Service name. I have this service name registered in my active directory as well. Though the address does not offer any particular service yet. Do you think that could be the problem?
Another details: The Active directory is not in the same office, we tunnel to it via router.

SecKeyCreateFromData fails on 10.9 with -2147415792

I have a code that constructs an RSA public key on MacOS with the help of the security framework. This works fine on 10.11/10.12/10.13, but today I found that this fails on 10.9. Below is the constructor of the class that wraps the key:
CRSAPublicKey(const unsigned char* pExponent, const std::size_t nExponentSize, const unsigned char* pModulus, const std::size_t nModulusSize)
{
static const SecAsn1Template kRsaPublicKeyTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ASN1_RSA_PUBLIC_KEY) },
{ SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Modulus), 0, 0 },
{ SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Exponent), 0, 0 },
{ 0, 0, 0, 0 },
};
ASN1_RSA_PUBLIC_KEY Asn1Key;
Asn1Key.m_Modulus.Data = const_cast<unsigned char*>(pModulus);
Asn1Key.m_Modulus.Length = nModulusSize;
Asn1Key.m_Exponent.Data = const_cast<unsigned char*>(pExponent);
Asn1Key.m_Exponent.Length = nExponentSize;
MacOS::CAsn1CoderReference pAsn1Coder;
OSStatus nStatus = SecAsn1CoderCreate(&pAsn1Coder);
// Check nStatus
SecAsn1Item DerKey;
nStatus = SecAsn1EncodeItem(pAsn1Coder, &Asn1Key, kRsaPublicKeyTemplate, &DerKey);
// Check nStatus
const void* pKeys[] = { kSecAttrKeyType, kSecAttrKeyClass };
const void* pValues[] = { kSecAttrKeyTypeRSA, kSecAttrKeyClassPublic };
MacOS::CReference<CFDictionaryRef> pParameters(CFDictionaryCreate(kCFAllocatorDefault, pKeys, pValues, 2, nullptr, nullptr));
// Check pParameters
MacOS::CReference<CFDataRef> pKeyData(CFDataCreate(kCFAllocatorDefault, DerKey.Data, static_cast<CFIndex>(DerKey.Length)));
// Check pKeyData
MacOS::CReference<CFErrorRef> pError;
m_PublicKey = SecKeyCreateFromData(pParameters, pKeyData, &pError);
// Check m_PublicKey - this fails with "The operation couldn’t be completed. (OSStatus error -2147415792.)"
}
I removed some check macros etc, but this should illustrate the call sequence. On 10.9 I get a null pointer from SecKeyCreateFromData with an error code -2147415792. I tried adding the kSecAttrKeySizeInBits but that did not help. Meanwhile SecKeyGeneratePair with the same pParameters works fine, so I assume the issue is with the actual data. Is the ASN.1 coding supported only from 10.10 or something like that?
UPDATE
I got messed up in my tests, this actually does not work on 10.11 as well, which seems to corelate with addition SecKeyCreateWithData.
UPDATE 2
Looking at cssmerr.h this error code seems to be CSSMERR_CSP_INVALID_KEY.
Since I did not find the answer anywhere I had to solve this myself so I hope this helps others.
I did not find a direct explanation for the behavior changes of SecKeyCreateFromData, but since the documentation states:
Constructs a SecKeyRef object for a symmetric key.
10.12 added a SecKeyCreateWithData which does not mention anything about symmetric keys, maybe they added some additional functionality into SecKeyCreateFromData as well and that could be why it was working for me on 10.12 and up.
Nevertheless, to obtain 10.9 compatibility I used SecItemImport with the same ASN.1 encoded sequence:
static SecKeyRef ImportPkcs1PublicKey(const unsigned char* pExponent, const std::size_t nExponentSize, const unsigned char* pModulus, const std::size_t nModulusSize)
{
static const SecAsn1Template kRsaPublicKeyTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ASN1_RSA_PUBLIC_KEY) },
{ SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Modulus), 0, 0 },
{ SEC_ASN1_INTEGER, offsetof(ASN1_RSA_PUBLIC_KEY, m_Exponent), 0, 0 },
{ 0, 0, 0, 0 },
};
ASN1_RSA_PUBLIC_KEY Asn1Key;
Asn1Key.m_Modulus.Data = const_cast<unsigned char*>(pModulus);
Asn1Key.m_Modulus.Length = nModulusSize;
Asn1Key.m_Exponent.Data = const_cast<unsigned char*>(pExponent);
Asn1Key.m_Exponent.Length = nExponentSize;
MacOS::CAsn1CoderReference pAsn1Coder;
OSStatus nStatus = SecAsn1CoderCreate(&pAsn1Coder);
// Check nStatus and pAsn1Coder
SecAsn1Item DerKey;
nStatus = SecAsn1EncodeItem(pAsn1Coder, &Asn1Key, kRsaPublicKeyTemplate, &DerKey);
// Check nStatus
MacOS::CReference<CFDataRef> pKeyData(CFDataCreate(kCFAllocatorDefault, DerKey.Data, static_cast<CFIndex>(DerKey.Length)));
// Check pKeyData
SecExternalFormat nFormat = kSecFormatBSAFE;
SecExternalItemType nType = kSecItemTypePublicKey;
MacOS::CReference<CFArrayRef> pItems;
nStatus = SecItemImport(pKeyData, NULL, &nFormat, &nType, 0, NULL, NULL, &pItems);
// Check nStatus
SecKeyRef pKey = reinterpret_cast<SecKeyRef>(const_cast<void*>(CFArrayGetValueAtIndex(pItems, 0)));
// Check pKey
CFRetain(pKey);
return pKey;
}
The trick here was to guess nFormat and nType, but luckily I found a table with the mapping in Apple open source sources and [CocoaCryptoMac] in Github. I already had the PKCS1 version for my key as seen in the snippet in the question the remaining job was just to set the format accordingly. This answer has a lot of valuable info on PKCS1/PKCS8. Also, initially I was not sure if pKeyData is the string or binary form of the key, since there are lots of examples that use the string form with the SecKeyCreateFromData function. I just tried out all the options until the binary version worked.

Need help to retrieve a Windows Certificate by Template?

I need to retrieve a Windows Certificate by Template Name (The Template is in the Extension Fields) using Windows API, C++.
My steps:
Open store: CertOpenStore(..) (Done; I can enumerate the certificates using CertEnumCertificatesInStore(..), but I see only their "Version 1 fields" and not the "Extensions". The Template is in the Extensions, so I cannot find it.)
I tried to find it using the CertFindCertificateInStore(), but did not succeed. Can anyone help me with the correct find type and parameters or use another function?
CertFreeCertificateContext(..), CertCloseStore(..) (Done).
I would like to post my code, hope it helps someone.
void GetCertificateByTemplate(char *certificateTemplate)
{
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertContext = NULL;
BYTE *pbDecoded;
DWORD cbDecoded;
_CERT_TEMPLATE_EXT *pbDecodedTemplate = NULL;
// 1). Open Local Machine certificate store
if (hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
L"My"))
{
fprintf(stderr, "The store has been opened. \n");
}
// 2). Enumerate certificates
while (pCertContext = CertEnumCertificatesInStore(
hCertStore,
pCertContext))
{
// 3). Check certificate extended data
for (int i = 0; i < pCertContext->pCertInfo->cExtension; i++)
{
// 4). Decode certificate extended data
if (CryptDecodeObject(
X509_ASN_ENCODING,
pCertContext->pCertInfo->rgExtension[i].pszObjId,
pCertContext->pCertInfo->rgExtension[i].Value.pbData,
pCertContext->pCertInfo->rgExtension[i].Value.cbData,
0,
NULL,
&cbDecoded))
{
; // error !!!
}
if (!(pbDecoded = (BYTE*)malloc(cbDecoded)))
{
; // error !!!
}
if (CryptDecodeObject(
X509_ASN_ENCODING,
pCertContext->pCertInfo->rgExtension[i].pszObjId,
pCertContext->pCertInfo->rgExtension[i].Value.pbData,
pCertContext->pCertInfo->rgExtension[i].Value.cbData,
0,
pbDecoded,
&cbDecoded))
{
pbDecodedTemplate = (_CERT_TEMPLATE_EXT*)pbDecoded;
char* objectId = pbDecodedTemplate->pszObjId;
// todo: check pDecodeTemplate->pszObjId
// 5). Compare the template string with the search one
if (strcmp(pbDecodedTemplate->pszObjId, certificateTemplate) == 0)
{
// todo: return certificate
printf("\nCertificate template found: %s \n", pbDecodedTemplate->pszObjId);
break;
}
}
}
}
// 6). Free certificate, close store
if (pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
CertCloseStore(hCertStore, 0);
}

Windows WMI - Getting multiple MAC addresses

I am using the following function and query to retrieve the network adapter's MAC address :
QueryValue( pService, L"SELECT MACAddress FROM Win32_NetworkAdapter", L"MACAddress", NetMacAddress, bufferLength );
But i don't know how to specify which card i want to get the address of. Is there a way to get the MAC address of every card on the computer (assuming they are activated and all that) using WMI ? Or using something else ?
Thank you :)
Without WMI you can simply use something like this...
unsigned long ulLen = 0;
IP_ADAPTER_ADDRESSES* p_adapAddress = NULL;
DWORD dwRetValue = GetAdaptersAddresses(AF_INET, 0, NULL, p_adapAddress,&ulLen);
if(dwRetValue == ERROR_BUFFER_OVERFLOW)
{
p_adapAddress = (PIP_ADAPTER_ADDRESSES)malloc(ulLen);
if(p_adapAddress)
{
dwRetValue = GetAdaptersAddresses(AF_INET, 0, NULL, p_adapAddress,&ulLen);
if(dwRetValue == NO_ERROR)
{
IP_ADAPTER_ADDRESSES* p_adapAddressAux = p_adapAddress;
do
{
// Get the value of the p_adapAddressAux.PhysicalAddress
}
while(p_adapAddressAux != NULL);
}
free(p_adapAddress);
}
}