问题
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.
来源:https://stackoverflow.com/questions/62982683/custom-cng-ksp-and-logon-domain