Custom CNG KSP and Logon domain - cryptography

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.

Related

Sign certificate with private key and logon domain

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.

TLS Session Resumption with OpenSSL server and SChannel client

I must use the RFC5077 TLS session resumption. My Client use Windows SChannel and server usually uses OpenSSL. In my test, following result.
OpenSSL 1.1.0 (or later) and SChannel: Always session reused, SChannel send previous Session Ticket.
OpenSSL 1.0.2 (any revision) and Schannel: Always new session, SChannel does not send Session Ticket.
OpenSSL and OpenSSL: Always session reused.
So I want to know that
Why Schannel don't use TLS session resumption only for OpenSSL 1.0.2?
The difference between 1.0.2 and 1.1.0.
How to use TLS session resumption at OpenSSL 1.0.2 and SChannel?
Server code: Simple TLS Server
Client code: Windows C++
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define SECURITY_WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>
#include <sspi.h>
#include <schannel.h>
#include <stdio.h>
#include <vector>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Secur32.lib")
struct WSA {
WSA() {
WSADATA wsaData;
if (auto result = WSAStartup(WINSOCK_VERSION, &wsaData))
throw result;
}
~WSA() {
WSACleanup();
}
};
struct Credential : CredHandle {
Credential() {
SCHANNEL_CRED cred = { .dwVersion = SCHANNEL_CRED_VERSION, .dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION };
if (auto ss = AcquireCredentialsHandleW(nullptr, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, nullptr, &cred, nullptr, nullptr, this, nullptr); ss != SEC_E_OK)
throw ss;
}
~Credential() {
FreeCredentialsHandle(this);
}
};
struct Socket {
SOCKET s;
Socket(const char* target, int port) {
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(target);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
throw WSAGetLastError();
if (connect(s, reinterpret_cast<const SOCKADDR*>(&addr), sizeof addr))
throw WSAGetLastError();
u_long val = 1;
ioctlsocket(s, FIONBIO, &val);
}
~Socket() {
closesocket(s);
}
auto Read() {
for (std::vector<unsigned char> result;;) {
char buffer[2048];
if (auto read = recv(s, buffer, sizeof buffer, 0); read == 0)
return result;
else if (read == SOCKET_ERROR) {
if (auto lastError = WSAGetLastError(); lastError != WSAEWOULDBLOCK)
throw lastError;
if (!empty(result))
return result;
Sleep(0);
} else
result.insert(end(result), buffer, buffer + read);
}
}
void Write(void* data, int length) {
for (auto p = reinterpret_cast<const char*>(data); 0 < length;) {
auto sent = send(s, p, length, 0);
if (sent == 0)
throw 0;
else if (sent == SOCKET_ERROR)
throw WSAGetLastError();
p += sent;
length -= sent;
}
}
};
int main() {
WSA wsa;
Credential credential;
for (int i = 0; i < 5; i++) {
Socket socket{ "127.0.0.1", 4433 };
std::vector<unsigned char> read;
auto first = true;
CtxtHandle context;
for (SECURITY_STATUS ss = SEC_I_CONTINUE_NEEDED; ss == SEC_I_CONTINUE_NEEDED;) {
SecBuffer inbuf[] = {
{ .BufferType = SECBUFFER_EMPTY },
{ .BufferType = SECBUFFER_EMPTY },
};
if (!first) {
auto data = socket.Read();
read.insert(end(read), begin(data), end(data));
inbuf[0] = { static_cast<unsigned long>(read.size()), SECBUFFER_TOKEN, read.data() };
}
SecBufferDesc indesc = { SECBUFFER_VERSION, 2, inbuf };
SecBuffer outbuf = { .BufferType = SECBUFFER_TOKEN };
SecBufferDesc outdesc = { SECBUFFER_VERSION, 1, &outbuf };
unsigned long attr = 0;
ss = InitializeSecurityContextW(&credential, first ? nullptr : &context, L"localhost", ISC_REQ_ALLOCATE_MEMORY, 0, SECURITY_NETWORK_DREP, &indesc, 0, &context, &outdesc, &attr, nullptr);
if (FAILED(ss))
throw ss;
first = false;
read.erase(begin(read), end(read) - (inbuf[1].BufferType == SECBUFFER_EXTRA ? inbuf[1].cbBuffer : 0));
if (outbuf.cbBuffer != 0) {
socket.Write(outbuf.pvBuffer, outbuf.cbBuffer);
FreeContextBuffer(outbuf.pvBuffer);
}
}
for (;;) {
SecBuffer buffer[] = {
{ static_cast<unsigned long>(read.size()), SECBUFFER_DATA, read.data() },
{ .BufferType = SECBUFFER_EMPTY },
{ .BufferType = SECBUFFER_EMPTY },
{ .BufferType = SECBUFFER_EMPTY },
};
SecBufferDesc desc{ SECBUFFER_VERSION, 4, buffer };
if (auto ss = DecryptMessage(&context, &desc, 0, nullptr); ss == SEC_I_CONTEXT_EXPIRED)
break;
else if (ss == SEC_E_OK) {
if (buffer[1].BufferType == SECBUFFER_DATA && 0 < buffer[1].cbBuffer && buffer[1].pvBuffer)
printf("%.*s", buffer[1].cbBuffer, reinterpret_cast<const char*>(buffer[1].pvBuffer));
read.erase(begin(read), end(read) - (buffer[3].BufferType == SECBUFFER_EXTRA ? buffer[3].cbBuffer : 0));
} else if (ss != SEC_E_INCOMPLETE_MESSAGE)
throw ss;
if (auto data = socket.Read(); empty(data))
break;
else
read.insert(end(read), begin(data), end(data));
}
if (auto ss = DeleteSecurityContext(&context); ss != SEC_E_OK)
throw ss;
}
}
I'm a maintainer of ftp client. Some ftps server requires that DATA connection must reuse the TLS session of CONTROL connection for security.
At Windows Update 2019/10, RFC7627 Extended Master Secret was enabled. SChannel requires RFC7627 EMS support when RFC5077 TLS Session Resumption.
OpenSSL suport RFC7627 extended master secret from 1.1.0. So SChannel cannot reuse TLS session with OpenSSL 1.0.2.

BCryptDeriveKeyPBKDF2 replacement for Windows Embedded Compact 2013

I have to compile existing C code using CNG (Cryptography API: Next Generation) functions for Windows Embedded Compact 2013. This code is using BCryptDeriveKeyPBKDF2, which is not available under Windows Embedded Compact 2013.
That means I need a replacement for the function below to implement the PBKDF2 key derivation algorithm as defined in RFC 2898 section 5.2, but without using BCryptDeriveKeyPBKDF2.
I found some C code which is using CryptoAPI functions here, but i don't want to use a 2nd, deprecated API if possible.
BOOL pbkdf2(
PUCHAR pbPassword, ULONG cbPassword,
PUCHAR pbSalt, ULONG cbSalt,
ULONGLONG cIterations,
PUCHAR pbDerivedKey, ULONG cbDerivedKey)
{
NTSTATUS status;
BCRYPT_ALG_HANDLE hAlgorithm;
status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
if (BCRYPT_SUCCESS(status))
{
status = BCryptDeriveKeyPBKDF2(hAlgorithm, pbPassword, cbPassword, pbSalt, cbSalt, cIterations, pbDerivedKey, cbDerivedKey, 0);
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
return BCRYPT_SUCCESS(status);
}
You could use CNG primitive such as BCryptCreateHash to implement algorithm. The most important is to use flag BCRYPT_ALG_HANDLE_HMAC_FLAG in BCryptOpenAlgorithmProvider:
void pbkdf2()
{
BCRYPT_ALG_HANDLE hAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
std::vector<BYTE> pass = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
std::vector<BYTE> salt = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
std::vector<BYTE> derived_key(32);
std::vector<BYTE> dig(32);
byte t[] = { 0x00, 0x00, 0x00, 0x01 };
DWORD itcount = 10000;
SECURITY_STATUS status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM,
nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG);
if (status != ERROR_SUCCESS) {
goto Exit;
}
status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, pass.data(), pass.size(), 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
status = BCryptHashData(hHash, salt.data(), salt.size(), 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
status = BCryptHashData(hHash, t, 4, 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
status = BCryptFinishHash(hHash, dig.data(), dig.size(), 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
derived_key = dig;
BCryptDestroyHash(hHash);
for (DWORD i = 1; i < itcount; ++i)
{
status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, pass.data(), pass.size(), 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
status = BCryptHashData(hHash, dig.data(), dig.size(), 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
status = BCryptFinishHash(hHash, dig.data(), dig.size(), 0);
if (status != ERROR_SUCCESS) {
goto Exit;
}
BCryptDestroyHash(hHash);
for (DWORD j = 0; j < dig.size(); ++j) {
derived_key[j] ^= dig[j];
}
}
Exit:
if (hHash) {
BCryptDestroyHash(hHash);
}
if (hAlg) {
BCryptCloseAlgorithmProvider(hAlg, 0);
}
return;
}
EDIT: to clarify meaning of t[].
According to RFC (5.2):
For each block of the derived key apply the function F defined
below to the password P, the salt S, the iteration count c, and
the block index to compute the block:
T_1 = F (P, S, c, 1) ,
T_2 = F (P, S, c, 2) ,
...
T_l = F (P, S, c, l) ,
where the function F is defined as the exclusive-or sum of the
first c iterates of the underlying pseudorandom function PRF
applied to the password P and the concatenation of the salt S
and the block index i: F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
where
U_1 = PRF (P, S || INT (i)) ,
U_2 = PRF (P, U_1) ,
...
U_c = PRF (P, U_{c-1}) .
Here, INT (i) is a four-octet encoding of the integer i, most
significant octet first.
So, in my code t[] - is a four-octet encoding of the integer 1 (for the first iteration), most significant octet first.
I took this code, converted the deprecated wincrypt calls to the new CNG API, refactored it and removed the stuff which i don't need.
Although i don't understand what the code is doing, it seems that it is producing the same result than the function in my question which is using BCryptDeriveKeyPBKDF2.
#define NOCRYPT
#include <windows.h>
#include <bcrypt.h>
#include <math.h>
#include <assert.h>
#define DIGEST_SIZE 20
#define BLOCK_SIZE 64
typedef struct
{
BCRYPT_ALG_HANDLE hAlgorithm;
BCRYPT_HASH_HANDLE hInnerHash;
BCRYPT_HASH_HANDLE hOuterHash;
} PRF_CTX;
static void hmacFree(PRF_CTX* pContext)
{
if (pContext->hOuterHash) BCryptDestroyHash(pContext->hOuterHash);
if (pContext->hInnerHash) BCryptDestroyHash(pContext->hInnerHash);
if (pContext->hAlgorithm) BCryptCloseAlgorithmProvider(pContext->hAlgorithm, 0);
}
static BOOL hmacPrecomputeDigest(BCRYPT_HASH_HANDLE hHash, PUCHAR pbPassword, DWORD cbPassword, BYTE mask)
{
BYTE buffer[BLOCK_SIZE];
DWORD i;
assert(cbPassword <= BLOCK_SIZE);
memset (buffer, mask, sizeof(buffer));
for (i = 0; i < cbPassword; ++i)
{
buffer[i] = (char) (pbPassword[i] ^ mask);
}
return BCRYPT_SUCCESS(BCryptHashData(hHash, buffer, sizeof(buffer), 0));
}
static BOOL hmacInit(PRF_CTX* pContext, PUCHAR pbPassword, DWORD cbPassword)
{
BCRYPT_HASH_HANDLE hHash = NULL;
BOOL bStatus = FALSE;
BYTE key[DIGEST_SIZE];
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&pContext->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, 0)) ||
!BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hInnerHash, NULL, 0, NULL, 0, 0)) ||
!BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hOuterHash, NULL, 0, NULL, 0, 0)))
{
goto hmacInit_end;
}
if (cbPassword > BLOCK_SIZE)
{
ULONG cbResult;
if (!BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &hHash, NULL, 0, NULL, 0, 0)) ||
!BCRYPT_SUCCESS(BCryptHashData(hHash, pbPassword, cbPassword, 0)) ||
!BCRYPT_SUCCESS(BCryptGetProperty(hHash, BCRYPT_HASH_LENGTH, (PUCHAR)&cbPassword, sizeof(cbPassword), &cbResult, 0)) ||
!BCRYPT_SUCCESS(BCryptFinishHash(hHash, key, cbPassword, 0)))
{
goto hmacInit_end;
}
pbPassword = key;
}
bStatus =
hmacPrecomputeDigest(pContext->hInnerHash, pbPassword, cbPassword, 0x36) &&
hmacPrecomputeDigest(pContext->hOuterHash, pbPassword, cbPassword, 0x5C);
hmacInit_end:
if (hHash) BCryptDestroyHash(hHash);
if (bStatus == FALSE) hmacFree(pContext);
return bStatus;
}
static BOOL hmacCalculateInternal(BCRYPT_HASH_HANDLE hHashTemplate, PUCHAR pbData, DWORD cbData, PUCHAR pbOutput, DWORD cbOutput)
{
BOOL success = FALSE;
BCRYPT_HASH_HANDLE hHash = NULL;
if (BCRYPT_SUCCESS(BCryptDuplicateHash(hHashTemplate, &hHash, NULL, 0, 0)))
{
success =
BCRYPT_SUCCESS(BCryptHashData(hHash, pbData, cbData, 0)) &&
BCRYPT_SUCCESS(BCryptFinishHash(hHash, pbOutput, cbOutput, 0));
BCryptDestroyHash(hHash);
}
return success;
}
static BOOL hmacCalculate(PRF_CTX* pContext, PUCHAR pbData, DWORD cbData, PUCHAR pbDigest)
{
return
hmacCalculateInternal(pContext->hInnerHash, pbData, cbData, pbDigest, DIGEST_SIZE) &&
hmacCalculateInternal(pContext->hOuterHash, pbDigest, DIGEST_SIZE, pbDigest, DIGEST_SIZE);
}
static void xor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen)
{
while (dwLen--)
*ptr1++ ^= *ptr2++;
}
BOOL pbkdf2(
PUCHAR pbPassword, ULONG cbPassword,
PUCHAR pbSalt, ULONG cbSalt,
DWORD cIterations,
PUCHAR pbDerivedKey, ULONG cbDerivedKey)
{
BOOL bStatus = FALSE;
DWORD l, r, dwULen, i, j;
BYTE Ti[DIGEST_SIZE];
BYTE V[DIGEST_SIZE];
LPBYTE U = malloc(max((cbSalt + 4), DIGEST_SIZE));
PRF_CTX prfCtx = { 0 };
assert(pbPassword != NULL && cbPassword != 0 && pbSalt != NULL && cbSalt != 0);
assert(cIterations > 0 && pbDerivedKey > 0 && cbDerivedKey > 0);
if (!hmacInit(&prfCtx, pbPassword, cbPassword))
{
goto PBKDF2_end;
}
l = (DWORD) ceil((double) cbDerivedKey / (double) DIGEST_SIZE);
r = cbDerivedKey - (l - 1) * DIGEST_SIZE;
for (i = 1; i <= l; i++)
{
ZeroMemory(Ti, DIGEST_SIZE);
for (j = 0; j < cIterations; j++)
{
if (j == 0)
{
// construct first input for PRF
memcpy(U, pbSalt, cbSalt);
U[cbSalt] = (BYTE) ((i & 0xFF000000) >> 24);
U[cbSalt + 1] = (BYTE) ((i & 0x00FF0000) >> 16);
U[cbSalt + 2] = (BYTE) ((i & 0x0000FF00) >> 8);
U[cbSalt + 3] = (BYTE) ((i & 0x000000FF));
dwULen = cbSalt + 4;
}
else
{
memcpy(U, V, DIGEST_SIZE);
dwULen = DIGEST_SIZE;
}
if (!hmacCalculate(&prfCtx, U, dwULen, V))
{
goto PBKDF2_end;
}
xor(Ti, V, DIGEST_SIZE);
}
if (i != l)
{
memcpy(&pbDerivedKey[(i-1) * DIGEST_SIZE], Ti, DIGEST_SIZE);
}
else
{
// Take only the first r bytes
memcpy(&pbDerivedKey[(i-1) * DIGEST_SIZE], Ti, r);
}
}
bStatus = TRUE;
PBKDF2_end:
hmacFree(&prfCtx);
free(U);
return bStatus;
}

Why does my structure assignment fail in C language?

Why does my structure assignment fail in C language?
I have a class A: define a structure
typedef struct{
int sockfd;
on_av_frame_cb av_frame_cb;
on_av_frame_cb rtp_cb;
on_error_cb error_cb;
uint8_t *p_buf;
uint8_t *v_buf;
uint8_t *a_buf;
int rtp_flag;
}udp_client_t;
Then I call in class B:
static udp_client_t client;
int jldv_create_client(int src_port,int port ,const char *dst_ip){
udp_client_t *udpClient = &client;
assert(udpClient != NULL);
const char *c_ip = dst_ip;
memset(udpClient, 0, sizeof(udp_client_t));
int ret = create_client(src_port, port, c_ip, &udpClient);
if (ret != 0) {
goto err_output;
}
udpClient->av_frame_cb = (on_av_frame_cb )onVideoFrame;
udpClient->error_cb = on_error;
if (rtp_create(&udpClient) < 0) { ///above problem
goto err_output;
}
printf("rtp_client:%d \n",udpClient->rtp_flag);
return 0;
err_output:
destroy_client(udpClient);
return -1;
}
In the above problem, I used the C class method:
int rtp_create(udp_client_t **data)
{
logi("%s", __func__);
udp_client_t *udpClient = *data;
if(udpClient)
{
udpClient->rtp_flag = 1;
memset(&rtp_cxt, 0, sizeof(rtp_context_t));
int ret = init_server();
if (ret < 0)
{
return -1;
}
rtp_cxt.nalu = alloc_nalu(MAX_FRAME_SIZE);//
if (!rtp_cxt.nalu)
{
loge("alloc nalu failed");
return -2;
}
}
else
{
loge("%s: data is null", __func__);
return -3;
}
printf("udpClient after==>%d \n",udpClient->rtp_flag);
return 0;
}
However, the result of printing is:
udpClient after==>1
rtp_client:0
supplement:
int create_client(int src_port, int dst_port, const char *dst_ip, udp_client_t **client)
{
udp_client_t *udpClient = *client;
assert(udpClient != NULL);
memset(udpClient, 0, sizeof(udp_client_t));
printf("create_client:%p\n",udpClient);
udpClient->port = src_port;
if (pthread_create(&udpClient->recv_tid, NULL, udp_receiver_runnable, (void *) udpClient) != 0)
{
loge("Failed to start new thread");
goto err_output;
}
return 0;
err_output:
memset(udpClient, 0, sizeof(udp_client_t));
return -10;
}
Why is that? Did i use something wrong?

my __init is called but not getting call for probe

I am enabling the pinctrl driver in the raspberry linux and I tried something and enabled it.
But what happened is, the __init is calling but the probe is not calling by the linux.
My code is
this is the probe
static int bcm2835_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct bcm2835_pinctrl *pc;
struct resource iomem;
int err, i;
BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2835_NUM_GPIOS);
BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2835_NUM_GPIOS);
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
platform_set_drvdata(pdev, pc);
pc->dev = dev;
err = of_address_to_resource(np, 0, &iomem);
if (err) {
dev_err(dev, "could not get IO memory\n");
return err;
}
pc->base = devm_ioremap_resource(dev, &iomem);
if (IS_ERR(pc->base))
return PTR_ERR(pc->base);
pc->gpio_chip = bcm2835_gpio_chip;
pc->gpio_chip.dev = dev;
pc->irq_domain = irq_domain_add_linear(np, BCM2835_NUM_GPIOS,
&irq_domain_simple_ops, NULL);
if (!pc->irq_domain) {
dev_err(dev, "could not create IRQ domain\n");
return -ENOMEM;
}
for (i = 0; i < BCM2835_NUM_GPIOS; i++) {
int irq = irq_create_mapping(pc->irq_domain, i);
irq_set_lockdep_class(irq, &gpio_lock_class);
irq_set_chip_and_handler(irq, &bcm2835_gpio_irq_chip,
handle_simple_irq);
irq_set_chip_data(irq, pc);
set_irq_flags(irq, IRQF_VALID);
}
for (i = 0; i < BCM2835_NUM_BANKS; i++) {
unsigned long events;
unsigned offset;
int len;
char *name;
/* clear event detection flags */
bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0);
bcm2835_gpio_wr(pc, GPFEN0 + i * 4, 0);
bcm2835_gpio_wr(pc, GPHEN0 + i * 4, 0);
bcm2835_gpio_wr(pc, GPLEN0 + i * 4, 0);
bcm2835_gpio_wr(pc, GPAREN0 + i * 4, 0);
bcm2835_gpio_wr(pc, GPAFEN0 + i * 4, 0);
/* clear all the events */
events = bcm2835_gpio_rd(pc, GPEDS0 + i * 4);
for_each_set_bit(offset, &events, 32)
bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
pc->irq[i] = irq_of_parse_and_map(np, i);
pc->irq_data[i].pc = pc;
pc->irq_data[i].bank = i;
spin_lock_init(&pc->irq_lock[i]);
len = strlen(dev_name(pc->dev)) + 16;
name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
if (!name)
return -ENOMEM;
snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
err = devm_request_irq(dev, pc->irq[i],
bcm2835_gpio_irq_handler, IRQF_SHARED,
name, &pc->irq_data[i]);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", pc->irq[i]);
return err;
}
}
err = gpiochip_add(&pc->gpio_chip);
if (err) {
dev_err(dev, "could not add GPIO chip\n");
return err;
}
pc->pctl_dev = pinctrl_register(&bcm2835_pinctrl_desc, dev, pc);
if (!pc->pctl_dev) {
err = gpiochip_remove(&pc->gpio_chip);
return err;
}
pc->gpio_range = bcm2835_pinctrl_gpio_range;
pc->gpio_range.base = pc->gpio_chip.base;
pc->gpio_range.gc = &pc->gpio_chip;
pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
return 0;
}
static struct of_device_id bcm2835_pinctrl_match[] = {
{ .compatible = "brcm,bcm2835-gpio" },
{}
};
MODULE_DEVICE_TABLE(of, bcm2835_pinctrl_match);
static struct platform_driver bcm2835_pinctrl_driver = {
.probe = bcm2835_pinctrl_probe,
.remove = bcm2835_pinctrl_remove,
.driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
.of_match_table = bcm2835_pinctrl_match,
},
};
static int __init bcm2835_pinctrl_init(void)
{
return platform_driver_register(&bcm2835_pinctrl_driver);
}
static void __exit bcm2835_pinctrl_exit(void)
{
platform_driver_unregister(&bcm2835_pinctrl_driver);
}
module_init(bcm2835_pinctrl_init);
module_exit(bcm2835_pinctrl_exit);
MODULE_AUTHOR("Chris Boot, Simon Arlott, Stephen Warren");
MODULE_DESCRIPTION("BCM2835 Pin control driver");
MODULE_LICENSE("GPL");
Can anyone help me out this?
I am not getting where i did wrong and why the probe is not calling?
The solution for this problem is that i forgot to add the driver structure in the board file.
After adding that i am getting call to the probe