Related
I'm implementing the program related to logon domain with certificate by custom KSP and my credential provider. I have successfully interacted from my credential provider to custom KSP. I'm in the process of implementing custom KSP. The steps I perform handling in custom KSP are as follows:
Install the template certificate Kerberos that has been issued from ADCS to local machine store. This is step how I Issue certificates and set up logons. Is there something missing?
Export the private key from the file (.pfx) that has been issued from ADCS via the command.
#openssl pkcs12 -in sample.pfx -nocerts -nodes -out sample.key.
#openssl rsa -in sample.key -out sample_private.key.
The flow custom KSP looks like this:
SampleKSPOpenProvider() -> SampleKSPOpenKey()->
SampleKSPGetKeyProperty() -> SampleKSPSignHash()
At SampleKSPSignHash(), My signing data is a buffer that contains the encoded certificate ( pbCertEncoded) and I signed the certificate with the private key and also verified the signature with the public key successfully.
I think the final handling is always in the SampleKSPSignHash () function, and I know that function can be called multiple times so I tried force code to always return the pbSignature signature, but still could not logon the domain.The event log always returns the error code ID 4625. About CAPI2 and Crypto-NCrypt log, Although I have enabled but when deploy logon with custom KSP and my credential provider doesn't output. It seems that has not been called yet, then I tried to logon with the default password window, the log was exported. Currently I only have a Log in Custom KSP developing. Is code handling logic wrong?
Below is the code of SampleKSPSignHash():
SECURITY_STATUS WINAPI SampleKSPSignHash(
__in NCRYPT_PROV_HANDLE hProvider,
__in NCRYPT_KEY_HANDLE hKey,
__in_opt VOID* pPaddingInfo,
__in_bcount(cbHashValue) PBYTE pbHashValue,
__in DWORD cbHashValue,
__out_bcount_part_opt(cbSignaturee, *pcbResult) PBYTE pbSignature,
__in DWORD cbSignaturee,
__out DWORD* pcbResult,
__in DWORD dwFlags)
{
SECURITY_STATUS Status = NTE_INTERNAL_ERROR;
NTSTATUS ntStatus = STATUS_INTERNAL_ERROR;
SAMPLEKSP_KEY* pKey = NULL;
DWORD cbTmpSig = 0;
DWORD cbTmp = 0;
UNREFERENCED_PARAMETER(hProvider);
DebugPrint("Call function ");
//Start workround
//Add handling to hash data and sign certificate with private key.
char text[4096];
DWORD dwBufferLen = 0, cbKeyBlob = 0;
PBYTE pbBuffer = NULL, pbKeyBlob = NULL;
LPBYTE lpHashData;
DWORD dwHashDataSize;
NTSTATUS status;
BCRYPT_ALG_HANDLE hAlg;
DWORD dwSignatureSize;
PBYTE lpSignature;
BCRYPT_PKCS1_PADDING_INFO padding_PKCS1;
padding_PKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM;
//Start Regardless of which calls to take, force always signs with the current certificate
//Alway force input pbHashValue = aCertContext->pbCertEncoded
HCERTSTORE hMyCertStore = NULL;
PCCERT_CONTEXT aCertContext = NULL;
LPBYTE pbData = NULL;
DWORD cbData = 0;
DWORD dwKeySpec;
hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING,
0,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
L"MY");
if (hMyCertStore == NULL)
{
DebugPrint("Call function -> hMyCertStore is NULL");
}
aCertContext = CertFindCertificateInStore(hMyCertStore,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR_A,
L"test01", // use appropriate subject name
NULL);
if (aCertContext == NULL)
{
DebugPrint("Call function -> Error: aCertContext is NULL");
}
pbHashValue = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, aCertContext->cbCertEncoded);
CopyMemory(pbHashValue, aCertContext->pbCertEncoded, aCertContext->cbCertEncoded);
cbHashValue = aCertContext->cbCertEncoded;
// End force
//Debug printout
DebugPrint("Call function - cbHashValue= %ld", cbHashValue);
DebugPrint("Call function - cbSignaturee= %ld", cbSignaturee);
DebugPrint("Call function - dwFlags= %ld", dwFlags);
for (int i = 0; i < cbHashValue; i++)
{
sprintf((char*)text + (i * 2), "%02X", pbHashValue[i]);
}
DebugPrint("Call function -> pbHashValue: %s", text);
// ------- HARCODE PRIVATE KEY ------ //
//Import the previously exported private key using the pfx file.Use the command below to
//export the private key.
//Command :#openssl pkcs12 -in sample.pfx -nocerts -nodes -out sample.key
// #openssl rsa -in sample.key -out sample_private.key
const char* szPemPrivKeyPass =
"-----BEGIN RSA PRIVATE KEY-----"
"MIIEowIBAAKCAQEA1MtKkDL5RuY7lYwCZy38x1w9kisJLhyb7VkIlodJPLyqkQUZ"
"eDjEvSyKl75ucgB4gzyO4MyYbH/lrttXH2sR830gG40MKz6EnsxyzCsCgYEA4AUC"
"fz5l+q7lW9Fm+hhM9duDFO5EME6RDJp6MIEWH9C0khv2wWhNJCdWNPwwlPgCWIpL"
"7ueaVfhErJkJLzH8V8gIPpb5Hot4YUycTNvZffSeS+RE5AF9kWgzlxcd31fGHgZZ"
"f9W0xn7ieQS3fFnVWlK900drOQ+qkQ8jMKvxDdcCgYEAtUJnGoSFq6undecimpVI"
"qwzzfr+MKpt7Ym+cdDrJ3qts+kYCD35O80lNM6TqqSJqCB76EwV3VmyzKQ+1/bZ9"
"wrb2FPOTew+ytzDh20dOHpAaVt3krCRQ4gBWzjgsWq4NP5cQParfSbvYBlBTkcJX"
"........................................................."
"-----END RSA PRIVATE KEY-----";
DebugPrint("Process Start import private key");
if (!CryptStringToBinaryA(szPemPrivKeyPass, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen,
NULL, NULL))
{
DebugPrint("Failed to convert BASE64 private key. Error 0x%.8X\n", GetLastError());
}
pbBuffer = (PBYTE)LocalAlloc(0, dwBufferLen);
if (!CryptStringToBinaryA(szPemPrivKeyPass, 0, CRYPT_STRING_BASE64HEADER, pbBuffer,
&dwBufferLen, NULL, NULL))
{
DebugPrint("Failed to convert BASE64 private key. Error 0x%.8X\n", GetLastError());
}
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY,
pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob))
{
DebugPrint("Failed to parse private key. Error 0x%.8X\n", GetLastError());
}
pbKeyBlob = (PBYTE)LocalAlloc(0, cbKeyBlob);
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY,
pbBuffer,
dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob))
{
DebugPrint("Failed to parse private key. Error 0x%.8X\n", GetLastError());
}
// ---------START HASH DATA ------------//
DebugPrint("Start Hash the data");
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RSA_ALGORITHM, NULL, 0);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptOpenAlgorithmProvider");
return 0;
}
//Import key pair
status = BCryptImportKeyPair(hAlg, NULL, LEGACY_RSAPRIVATE_BLOB, &hKey, (PUCHAR)pbKeyBlob,
cbKeyBlob, 0);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptImportKeyPair : 0x%.8X\n", GetLastError());
return FALSE;
}
// Hash Data certificate
if (!GetHashData((LPBYTE)pbHashValue, cbHashValue, &lpHashData, &dwHashDataSize)) {
DebugPrint("Error: GetHashData");
return FALSE;
}
//Sign hash certificate
BCryptSignHash(hKey, &padding_PKCS1, (LPBYTE)lpHashData, dwHashDataSize, NULL, 0,
&dwSignatureSize, BCRYPT_PAD_PKCS1);
pbSignature = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, dwSignatureSize);
status = BCryptSignHash(hKey, &padding_PKCS1, (LPBYTE)lpHashData, dwHashDataSize,
pbSignature, dwSignatureSize, pcbResult, BCRYPT_PAD_PKCS1);
//Debug print
DebugPrint("Call function - dwHashDataSize= %ld", dwHashDataSize);
DebugPrint("Call function - pcbResult= %ld", *pcbResult);
DebugPrint("Call function - dwSignatureSize= %ld", dwSignatureSize);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptSignHash= %X", status);
HeapFree(GetProcessHeap(), 0, lpHashData);
HeapFree(GetProcessHeap(), 0, pbSignature);
return FALSE;
}
// Print the Signature data.
char textPn[4096];
for (int i = 0; i < dwSignatureSize; i++){
sprintf((char*)textPn + (i * 2), "%02X", pbSignature[i]);
}
DebugPrint("pbSignature: %s", textPn);
// Verify the signature with the public key
if (!VerifySign(pbSignature, dwSignatureSize)) {
DebugPrint("Error signature");
return FALSE;
}
DebugPrint("Verify the signature success", );
Status = ERROR_SUCCESS;
//End workround
cleanup:
return Status;
}
BOOL VerifySign(
__in_bcount(cbSignaturee) PBYTE pbSignature,
__in DWORD cbSignaturee)
{
HCERTSTORE hMyCertStore = NULL;
PCCERT_CONTEXT aCertContext = NULL;
LPBYTE pbData = NULL;
DWORD cbData = 0;
DWORD dwKeySpec;
PBYTE pbOutput = NULL;
PBYTE vHashData;
DWORD vHashDataSize;
NTSTATUS status;
BCRYPT_PKCS1_PADDING_INFO padding_PKCS1;
padding_PKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM;
DebugPrint("Start VerifySign");
hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING,
0,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
L"MY");
if (hMyCertStore == NULL)
{
DebugPrint("Call function -> hMyCertStore is NULL");
return FALSE;
}
aCertContext = CertFindCertificateInStore(hMyCertStore,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR_A,
L"test01", // use appropriate subject name
NULL
);
if (aCertContext == NULL)
{
DebugPrint("Call function -> Error: aCertContext is NULL");
return FALSE;
}
PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, aCertContext-
>pbCertEncoded, aCertContext->cbCertEncoded);
if (!pcCertContext)
{
DebugPrint("ERROR: pcCertContext");
return FALSE;
}
BCRYPT_KEY_HANDLE publicKeyHandle = NULL;
if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &pcCertContext->pCertInfo-
>SubjectPublicKeyInfo, 0, NULL, &publicKeyHandle))
{
DebugPrint("CryptImportPublicKeyInfoEx2 failed");
return FALSE;
}
pbOutput = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, aCertContext->cbCertEncoded);
CopyMemory(pbOutput, aCertContext->pbCertEncoded, aCertContext->cbCertEncoded);
if (!GetHashData((LPBYTE)pbOutput, aCertContext->cbCertEncoded, &vHashData, &vHashDataSize))
{
DebugPrint("GetHashData failed.");
return FALSE;
}
status = BCryptVerifySignature(publicKeyHandle, &padding_PKCS1, vHashData, vHashDataSize,
pbSignature, cbSignaturee, BCRYPT_PAD_PKCS1);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptSignHash= %X", status);
return FALSE;
}
DebugPrint("Verify Sign OK");
return TRUE;
}
BOOL GetHashData(PBYTE lpData, DWORD dwDataSize, PBYTE* lplpHashData, LPDWORD lpdwHashDataSize)
{
BCRYPT_ALG_HANDLE hAlg;
BCRYPT_HASH_HANDLE hHash;
DWORD dwResult;
DWORD dwHashObjectSize;
PBYTE lpHashObject;
NTSTATUS status;
DebugPrint("Call function ");
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM, NULL, 0);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptOpenAlgorithmProvider 0x%.8X\n", GetLastError());
return FALSE;
}
DebugPrint("Call function ");
BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&dwHashObjectSize, sizeof(DWORD),
&dwResult, 0);
lpHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, dwHashObjectSize);
status = BCryptCreateHash(hAlg, &hHash, lpHashObject, dwHashObjectSize, NULL, 0, 0);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptCreateHash 0x%.8X\n", GetLastError());
DebugPrint("Error: status= %X\n", status);
HeapFree(GetProcessHeap(), 0, lpHashObject);
BCryptCloseAlgorithmProvider(hAlg, 0);
return FALSE;
}
DebugPrint("Call function ");
BCryptHashData(hHash, lpData, dwDataSize, 0);
BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)lpdwHashDataSize, sizeof(DWORD),
&dwResult,0);
*lplpHashData = (PBYTE)HeapAlloc(GetProcessHeap(), 0, *lpdwHashDataSize);
BCryptFinishHash(hHash, *lplpHashData, *lpdwHashDataSize, 0);
HeapFree(GetProcessHeap(), 0, lpHashObject);
BCryptDestroyHash(hHash);
BCryptCloseAlgorithmProvider(hAlg, 0);
DebugPrint("Call function ");
return TRUE;
}
I also wonder if this Issue has anything to do with the my Credential Provider?
Below is my current Credential Provider code:
//Build the authentication data used by LsaLogonUser
void ConstructAuthInfo(LPBYTE* ppbAuthInfo, ULONG* pulAuthInfoLen)
{
DebugPrint("call function");
WCHAR szCardName[] = L"";
WCHAR szContainerName[] = L"";
WCHAR szReaderName[] = L"";
WCHAR szCspName[] = L"Microsoft Sample Key Storage Provider";
WCHAR szPin[] = L"1234";
ULONG ulPinByteLen = wcslen(szPin) * sizeof(WCHAR);
WCHAR szUserName[] = L"test01";
ULONG ulUserByteLen = wcslen(szUserName) * sizeof(WCHAR);
WCHAR szDomainName[] = L"xyz.co";
ULONG ulDomainByteLen = wcslen(szDomainName) * sizeof(WCHAR);
LPBYTE pbAuthInfo = NULL;
ULONG ulAuthInfoLen = 0;
KERB_CERTIFICATE_LOGON* pKerbCertLogon;
KERB_SMARTCARD_CSP_INFO* pKerbCspInfo;
LPBYTE pbDomainBuffer, pbUserBuffer, pbPinBuffer;
LPBYTE pbCspData;
LPBYTE pbCspDataContent;
ULONG ulCspDataLen = sizeof(KERB_SMARTCARD_CSP_INFO) -
sizeof(TCHAR) + (wcslen(szCardName) + 1) * sizeof(WCHAR) +
(wcslen(szCspName) + 1) * sizeof(WCHAR) +
(wcslen(szContainerName) + 1) * sizeof(WCHAR) +
(wcslen(szReaderName) + 1) * sizeof(WCHAR);
ulAuthInfoLen = sizeof(KERB_CERTIFICATE_LOGON) +
ulDomainByteLen + sizeof(WCHAR) + ulUserByteLen + sizeof(WCHAR) +
ulPinByteLen + sizeof(WCHAR) + ulCspDataLen;
pbAuthInfo = (LPBYTE)CoTaskMemAlloc(ulAuthInfoLen);
ZeroMemory(pbAuthInfo, ulAuthInfoLen);
pbDomainBuffer = pbAuthInfo + sizeof(KERB_CERTIFICATE_LOGON);
pbUserBuffer = pbDomainBuffer + ulDomainByteLen + sizeof(WCHAR);
pbPinBuffer = pbUserBuffer + ulUserByteLen + sizeof(WCHAR);
pbCspData = pbPinBuffer + ulPinByteLen + sizeof(WCHAR);
memcpy(pbDomainBuffer, szDomainName, ulDomainByteLen);
memcpy(pbUserBuffer, szUserName, ulUserByteLen);
memcpy(pbPinBuffer, szPin, ulPinByteLen);
pKerbCertLogon = (KERB_CERTIFICATE_LOGON*)pbAuthInfo;
pKerbCertLogon->MessageType = KerbCertificateLogon;
pKerbCertLogon->DomainName.Length = (USHORT)ulDomainByteLen;
pKerbCertLogon->DomainName.MaximumLength = (USHORT)(ulDomainByteLen
+ sizeof(WCHAR));
pKerbCertLogon->DomainName.Buffer = (PWSTR)(pbDomainBuffer - pbAuthInfo);
pKerbCertLogon->UserName.Length = (USHORT)ulUserByteLen;
pKerbCertLogon->UserName.MaximumLength = (USHORT)(ulUserByteLen + sizeof(WCHAR));
pKerbCertLogon->UserName.Buffer = (PWSTR)(pbUserBuffer - pbAuthInfo);
pKerbCertLogon->Pin.Length = (USHORT)ulPinByteLen;
pKerbCertLogon->Pin.MaximumLength = (USHORT)(ulPinByteLen + sizeof(WCHAR));
pKerbCertLogon->Pin.Buffer = (PWSTR)(pbPinBuffer - pbAuthInfo);
pKerbCertLogon->CspDataLength = ulCspDataLen;
pKerbCertLogon->CspData = (PUCHAR)(pbCspData - pbAuthInfo);
pKerbCspInfo = (KERB_SMARTCARD_CSP_INFO*)pbCspData;
pKerbCspInfo->dwCspInfoLen = ulCspDataLen;
pKerbCspInfo->MessageType = 1;
pKerbCspInfo->KeySpec = CERT_NCRYPT_KEY_SPEC;
//pKerbCspInfo->KeySpec = AT_KEYEXCHANGE;
pKerbCspInfo->nCardNameOffset = 0;
pKerbCspInfo->nReaderNameOffset = pKerbCspInfo->nCardNameOffset + wcslen(szCardName) + 1;
pKerbCspInfo->nContainerNameOffset = pKerbCspInfo->nReaderNameOffset + wcslen(szReaderName) + 1;
pKerbCspInfo->nCSPNameOffset = pKerbCspInfo->nContainerNameOffset + wcslen(szContainerName) + 1;
pbCspDataContent = pbCspData + sizeof(KERB_SMARTCARD_CSP_INFO) - sizeof(TCHAR);
memcpy(pbCspDataContent + (pKerbCspInfo->nCardNameOffset * sizeof(WCHAR)), szCardName, wcslen(szCardName) * sizeof(WCHAR));
memcpy(pbCspDataContent + (pKerbCspInfo->nReaderNameOffset * sizeof(WCHAR)), szReaderName, wcslen(szReaderName) * sizeof(WCHAR));
memcpy(pbCspDataContent + (pKerbCspInfo->nContainerNameOffset * sizeof(WCHAR)), szContainerName, wcslen(szContainerName) * sizeof(WCHAR));
memcpy(pbCspDataContent + (pKerbCspInfo->nCSPNameOffset * sizeof(WCHAR)), szCspName, wcslen(szCspName) * sizeof(WCHAR));
*ppbAuthInfo = pbAuthInfo;
*pulAuthInfoLen = ulAuthInfoLen;
DebugPrint("call function -> 12");
}
HRESULT CSampleCredential::GetSerialization(
_Out_ CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *pcpgsr,
_Out_ CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpcs,
_Outptr_result_maybenull_ PWSTR *ppwszOptionalStatusText,
_Out_ CREDENTIAL_PROVIDER_STATUS_ICON *pcpsiOptionalStatusIcon)
{
if (DEVELOPING) PrintLn("Credential::GetSerialization");
HRESULT hr = E_UNEXPECTED;
*pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
*ppwszOptionalStatusText = nullptr;
*pcpsiOptionalStatusIcon = CPSI_NONE;
ZeroMemory(pcpcs, sizeof(*pcpcs));
//Start add connect to KSP
if (DEVELOPING) DebugPrint("Start test login");
ULONG ulAuthPackage;
hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);
ConstructAuthInfo(&pcpcs->rgbSerialization, &pcpcs->cbSerialization);
if (SUCCEEDED(hr))
{
DebugPrint("Start test SUCCEEDED");
pcpcs->ulAuthenticationPackage = ulAuthPackage;
pcpcs->clsidCredentialProvider = CLSID_CSample;
*pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
DebugPrint("End test SUCCEEDED");
}
return hr;
}
HRESULT RetrieveNegotiateAuthPackage(ULONG* pulAuthPackage)
{
HRESULT hr = S_OK;
HANDLE hLsa = NULL;
NTSTATUS status = LsaConnectUntrusted(&hLsa);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
ULONG ulAuthPackage;
LSA_STRING lsaszKerberosName;
_LsaInitString(&lsaszKerberosName, MICROSOFT_KERBEROS_NAME_A);//NEGOSSP_NAME_A or MICROSOFT_KERBEROS_NAME_A
status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
*pulAuthPackage = ulAuthPackage;
hr = S_OK;
}
else
{
hr = HRESULT_FROM_NT(status);
}
LsaDeregisterLogonProcess(hLsa);
}
else
{
hr = HRESULT_FROM_NT(status);
}
return hr;
}
This is all my code SampleKSP.c. Thank in advance.
I'm implementing the program related to logon domain with certificate by custom KSP and my credential provider. I have successfully interacted from my credential provider to custom KSP. I'm in the process of implementing custom KSP. The steps I perform handling in custom KSP are as follows:
Install the template certificate Kerberos that has been issued from ADCS to local machine store.
Export the private key from the file (.pfx) that has been issued from ADCS via the command:
#openssl pkcs12 -in sample.pfx -nocerts -nodes -out sample.key.
#openssl rsa -in sample.key -out sample_private.key.
The flow custom KSP looks like this:
SampleKSPOpenProvider -> SampleKSPOpenKey-> SampleKSPGetKeyProperty -> SampleKSPSignHash.
In SampleKSPSignHash, I read the private key and imported the key, then implemented the functions BCryptCreateHash, BCryptHashData, BCryptFinishHash, and finally BCryptSignHash. The data hash will be taken from SampleKSPGetKeyProperty by reading the certificate from the local machine store(CertContext->pbCertEncoded).But I'm having trouble with the hash data and there was an error during BCryptSignHash.Below is the code of SampleKSPGetKeyProperty:
SECURITY_STATUS
WINAPI
SampleKSPGetKeyProperty(
__in NCRYPT_PROV_HANDLE hProvider,
__in NCRYPT_KEY_HANDLE hKey,
__in LPCWSTR pszProperty,
__out_bcount_part_opt(cbOutput, *pcbResult) PBYTE pbOutput,
__in DWORD cbOutput,
__out DWORD * pcbResult,
__in DWORD dwFlags)
{
....
....
else if (wcscmp(pszProperty, NCRYPT_CERTIFICATE_PROPERTY) == 0) {
if (pbOutput == NULL) // get the certificate size {
*pcbResult = aCertContext->cbCertEncoded;
}
else
{
if (aCertContext->cbCertEncoded < *pcbResult)
{
DebugPrint("ERROR", "Buffer too small!");
Status = NTE_BUFFER_TOO_SMALL;
goto cleanup;
}
DebugPrint("INFO Returning certificate payload...");
*pcbResult = aCertContext->cbCertEncoded;
CopyMemory(pbOutput, aCertContext->pbCertEncoded, aCertContext-
>cbCertEncoded);
//Debug print the output certEncoded
char text[4096];
for (int i = 0; i < aCertContext->cbCertEncoded; i++)
{
sprintf((char*)text + (i), "%02X", pbOutput[i]);
}
DebugPrint("Call function -> pbOutput: %s", text);
// There should handle call SampleKSPSignHash directly here ?
PBYTE pbSignature = NULL;
DWORD cbSignaturee = 0;
SampleKSPSignHash(hProvider,hKey,NULL, pbOutput, aCertContext-
>cbCertEncoded, pbSignature, pbSignature,0,0);
}
}
....
}
Next is the code of SampleKSPSignHash, When calling BCryptSignHash, it failed:
SECURITY_STATUS
WINAPI
SampleKSPSignHash(
__in NCRYPT_PROV_HANDLE hProvider,
__in NCRYPT_KEY_HANDLE hKey,
__in_opt VOID *pPaddingInfo,
__in_bcount(cbHashValue) PBYTE pbHashValue,
__in DWORD cbHashValue,
__out_bcount_part_opt(cbSignaturee, *pcbResult) PBYTE pbSignature,
__in DWORD cbSignaturee,
__out DWORD * pcbResult,
__in DWORD dwFlags)
{
DWORD dwBufferLen = 0, cbKeyBlob = 0;
PBYTE pbBuffer = NULL, pbKeyBlob = NULL;
LPBYTE lpHashData;
DWORD dwHashDataSize;
NTSTATUS status;
BCRYPT_ALG_HANDLE hAlg;
DWORD dwSignatureSize;
PBYTE lpSignature;
const char* szPemPrivKeyPass =
"-----BEGIN RSA PRIVATE KEY-----"
"MIIEpAIBAAKCAQEAn5JrYEBEC8Yy3cbCzZnu89MyLNsFnuRlWQzKx2toE9xZCuUf"
".....
"eSfelLMqp94Ia//VwTFTnj5jKJCcTkQ4L7M0I2tm3PAM7PUzCxKHgw=="
"-----END RSA PRIVATE KEY-----";
if (!CryptStringToBinaryA(szPemPrivKeyPass, 0, CRYPT_STRING_BASE64HEADER,
NULL, &dwBufferLen, NULL, NULL))
{
return FALSE;
}
pbBuffer = (PBYTE)LocalAlloc(0, dwBufferLen);
if (!CryptStringToBinaryA(szPemPrivKeyPass, 0, CRYPT_STRING_BASE64HEADER,
pbBuffer, &dwBufferLen, NULL, NULL))
{
return FALSE;
}
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, NULL,
&cbKeyBlob))
{
return FALSE;
}
pbKeyBlob = (PBYTE)LocalAlloc(0, cbKeyBlob);
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob,
&cbKeyBlob))
{
return FALSE;
}
// -------------START HASH DATA ------------//
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RSA_ALGORITHM, NULL,
0);
if (!NT_SUCCESS(status)) {
return FALSE;
}
status = BCryptImportKeyPair(hAlg, NULL, LEGACY_RSAPRIVATE_BLOB, &hKey,
(PUCHAR)pbKeyBlob, cbKeyBlob, 0);
if (!NT_SUCCESS(status)) {
return FALSE;
}
if (!GetHashData((PBYTE)pbHashValue, cbHashValue, &lpHashData,
&dwHashDataSize)) {
return FALSE;
}
BCryptSignHash(hKey, NULL, (PBYTE)lpHashData, dwHashDataSize, NULL, 0,
&dwSignatureSize, 0);
pbSignature = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, dwSignatureSize);
//----I have failed here---//
status = BCryptSignHash(hKey, NULL, (PBYTE)lpHashData, dwHashDataSize,
pbSignature, dwSignatureSize, &dwSignatureSize, 0);
if (!NT_SUCCESS(status)) {
HeapFree(GetProcessHeap(), 0, lpHashData);
HeapFree(GetProcessHeap(), 0, pbSignature);
return FALSE; //I have failed here
}
}
BOOL GetHashData(PBYTE lpData, DWORD dwDataSize, PBYTE* lplpHashData,
LPDWORD
lpdwHashDataSize){
BCRYPT_ALG_HANDLE hAlg;
BCRYPT_HASH_HANDLE hHash;
DWORD dwResult;
DWORD dwHashObjectSize;
PBYTE lpHashObject;
NTSTATUS status;
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM, NULL,
0);
if (!NT_SUCCESS(status)) {
DebugPrint("Error: BCryptOpenAlgorithmProvider 0x%.8X\n",
GetLastError());
return FALSE;
}
BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&dwHashObjectSize,
sizeof(DWORD), &dwResult, 0);
lpHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, dwHashObjectSize);
status = BCryptCreateHash(hAlg, &hHash, lpHashObject, dwHashObjectSize,
NULL, 0, 0);
if (!NT_SUCCESS(status)) {
HeapFree(GetProcessHeap(), 0, lpHashObject);
BCryptCloseAlgorithmProvider(hAlg, 0);
return FALSE;
}
BCryptHashData(hHash, lpData, dwDataSize, 0);
BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)lpdwHashDataSize,
sizeof(DWORD), &dwResult, 0);
*lplpHashData = (PBYTE)HeapAlloc(GetProcessHeap(), 0, *lpdwHashDataSize);
BCryptFinishHash(hHash, *lplpHashData, *lpdwHashDataSize, 0);
HeapFree(GetProcessHeap(), 0, lpHashObject);
BCryptDestroyHash(hHash);
BCryptCloseAlgorithmProvider(hAlg, 0);
return TRUE;
}
I think after performing such a process and calling the credential provider will login to the domain. Do I understand that correctly? - Thanks in advance.
It's been a long time since I wrote something like that, but if I remember correctly you need to call BCryptSignHash two times. The first time to get the expected size of the signature and the second time to actually do the signing.
pbOutput
The address of a buffer to receive the signature produced by this
function. The cbOutput parameter contains the size of this buffer.
If this parameter is NULL, this function will calculate the size
required for the signature and return the size in the location pointed
to by the pcbResult parameter.
Even when I already knew the size and handed it over to the function it still complained with STATUS_INVALID_PARAMETER which is the translation of 0xC000000D. Only after I called it twice things started to work. Be sure to read the documentation of the windows crypto API carefully as there are some catches in it. ;-)
EDIT
Looking closer at your example I see that you have 0 as the last parameter in your call to BCryptSignHash.
According to the documentation this should be 0x00000002 (PKCS1) or 0x00000008 (PSS):
dwFlags
A set of flags that modify the behavior of this function. The allowed
set of flags depends on the type of key specified by the hKey
parameter.
This can be one of the following values.
BCRYPT_PAD_PKCS1 Use the PKCS1 padding scheme. The pPaddingInfo
parameter is a pointer to a BCRYPT_PKCS1_PADDING_INFO structure.
BCRYPT_PAD_PSS Use the Probabilistic Signature Scheme (PSS) padding
scheme. The pPaddingInfo parameter is a pointer to a
BCRYPT_PSS_PADDING_INFO structure.
I am working on an application, which connects to a COM object and calls methods and gets properties from this object etc.
I can connect and call the members, that is not the issue. I cannot however figure out, how to call a method, which has an output parameter, for instance (pseudo code):
int GetAppVersion(bsRetMsg [out, optional]).
This functions return int as the version and can also return a string representation of the version via the output parameter.
What I've tried:
(1)
VARIANT result;
DISPPARAMS params = {NULL, NULL, 0, 0};
VARIANTARG args[1];
BSTR str = SysAllocString(L"longerfoostring");
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_BYREF;
args[0].bstrVal = str;
params.rgvarg = args;
params.cArgs = 1;
res = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL,
NULL);
if (SUCCEEDED(res)) { // here it failed: Not enough storage is available to complete this operation.
std::cout << result.intVal << std::endl;
...
(2)
VARIANT result;
DISPPARAMS params = {NULL, NULL, 0, 0};
VARIANTARG args[1];
BSTR str = SysAllocString(L""); // change: empty string
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_BYREF;
args[0].bstrVal = str;
params.rgvarg = args;
params.cArgs = 1;
res = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL,
NULL);
if (SUCCEEDED(res)) { // here it failed: Not enough storage is available to complete this operation.
std::cout << result.intVal << std::endl;
...
(3)
...
BSTR str = SysAllocString(L"longerfoostring");
VariantInit(&args[0]);
args[0].vt = VT_BSTR; // change: no BYREF
args[0].bstrVal = str;
params.rgvarg = args;
params.cArgs = 1;
... invoke is the same...
res = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL,
NULL);
if (SUCCEEDED(res)) {
std::cout << result.intVal << std::endl; // this number is correct - version in int
printf("'%S'", params.rgvarg[0].bstrVal); // prints 'longerfoostring' instead of version, ie. '2.0.5...'
(4)
BSTR *str;
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_PTR; // change: different VT
args[0].pbstrVal = str; //change: different type
params.rgvarg = args;
params.cArgs = 1;
... invoke failes with Bad variable type.
So the question is:
How to pass a string (or any type) as an input/output parameter to a COM method and correctly get the output from this parameter?
Since you want to get back the data, you have to provide the address of a BSTR
BSTR str;
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_BYREF; // it's a BSTR and it's by ref
args[0].pbstrVal = &str; // give address of variable
params.rgvarg = args;
params.cArgs = 1;
now call invoke and don't forget to free the returned BSTR.
I am getting status code 404 for the below code snippet.
Note: please add <HOSTNAME> when you are trying to figure out the issue.
HINTERNET m_hConnect;
HINTERNET m_hSession;
HINTERNET m_hRequest;
m_hSession = WinHttpOpen(userAgent,
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!m_hSession) {
printf("WinHttpOpen:Error %d has occurred.",GetLastError());
return 0;
}
// connect to the IPP server on the given port
m_hConnect = WinHttpConnect( m_hSession, <HOSTNAME>, 443, 0);
if (!m_hConnect) {
printf("WinHttpConnect: Error %d has occurred.",GetLastError());
return 0;
}
// Create an HTTP Request handle.
m_hRequest = WinHttpOpenRequest(m_hConnect, L"POST" ,L"/ipp",
L"HTTP/1.1", WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,WINHTTP_FLAG_SECURE);
if (!m_hRequest) {
printf("WinHttpOpenRequest:Error %d has occurred.",GetLastError());
return 0;
}
DWORD secureflags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID |SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
BOOL bResult= WinHttpSetOption(m_hRequest, WINHTTP_OPTION_SECURITY_FLAGS, (LPVOID)&secureflags, sizeof(secureflags));
if (!bResult) {
printf("WinHttpSetOption:Error %d has occurred.",GetLastError());
return 0;
}
bResult = WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS,0,WINHTTP_NO_REQUEST_DATA,0,0,0);
if (!bResult) {
printf("WinHttpSendRequest:Error %d has occurred.",GetLastError());
return 0;
}
if( !WinHttpReceiveResponse( m_hRequest, NULL ) )
{
if( GetLastError( ) == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED )
{
HCERTSTORE hMyStore = 0;
PCCERT_CONTEXT pCertContext = 0;
WCHAR szCertName[256]={0};
//MY is the store the certificate is in.
hMyStore = CertOpenSystemStore( 0, TEXT("MY") );
if( hMyStore )
{
pCertContext = CertFindCertificateInStore( hMyStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
(LPVOID) szCertName, //Subject string in the certificate.
NULL );
if( pCertContext )
{
WinHttpSetOption( m_hRequest,
WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
(LPVOID) pCertContext,
sizeof(CERT_CONTEXT) );
CertFreeCertificateContext( pCertContext );
}
CertCloseStore( hMyStore, 0 );
// NOTE: Application should now resend the request.
bResult = WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS,0,WINHTTP_NO_REQUEST_DATA,0,0,0);
if (!bResult) {
printf("WinHttpSendRequest:Error %d has occurred.",GetLastError());
return 0;
}
}
}
}
DWORD dwStatusCode = 0;
DWORD dwSize = sizeof(DWORD);
BOOL bResults = true;
bResults = WinHttpQueryHeaders( m_hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSize, NULL );
Result: I am getting status code of 404. I am not able to figure out why it is happening.
Using WinINet, I have followed the same procedure, I am getting status code of 200, which is success. But my requirement is to use only WinHttp.
This is not a mystery. It is happening because the resource you request was not found.
Either:
The URL you used was incorrect, or
The mapping of URLs to resources at the server isn't correct.
Code :
hHCDev = CreateFileA(completeDeviceName,
//"F:\\test.txt",
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hHCDev == INVALID_HANDLE_VALUE)
{
CloseHandle(hHCDev);
}
else
{
char bufRead[256] = {0};
DWORD countRead = 0;
BOOL result ;
result = ReadFile(hHCDev, bufRead, 5, &countRead, NULL) ;
if(!result)
{
printf("Reading file error %d\n", GetLastError());
}
char bufWrite[] = {'7', '8', '9', ' '};
DWORD countWritten = 0;
result = WriteFile(hHCDev, bufWrite, 3, &countWritten, NULL) ;
if(!result)
{
printf("Writing file error %d\n", GetLastError());
}
else
{
printf("sucess");
}
CloseHandle(hHCDev);
}
memset(completeDeviceName,0,256) ;
Description:
We tried to open the USB device connected using createfile(). Using Readfile and Writefile() calls we tried to communicate with the device. But these calls returned with error code 1. What might be the reason??
Your Help would be highly appreciated.
Best Regards
Suren
Try to run your application with administrator rights.