![](/img/trans.png)
[英]How to sign a message using private key of the certificate in javascript
[英]Sign certificate with private key and logon domain
我正在使用自定義 KSP 和我的憑據提供程序的證書實施與登錄域相關的程序。 我已經成功地從我的憑證提供者交互到自定義 KSP。 我正在實施自定義 KSP。 我在自定義 KSP 中執行處理的步驟如下:
#openssl pkcs12 -in sample.pfx -nocerts -nodes -out sample.key.
#openssl rsa -in sample.key -out sample_private.key.
SampleKSPOpenProvider -> SampleKSPOpenKey-> SampleKSPGetKeyProperty -> SampleKSPSignHash.
SampleKSPSignHash
中,我讀取了私鑰並導入了密鑰,然后實現了函數BCryptCreateHash
、 BCryptHashData
、 BCryptFinishHash
,最后是BCryptSignHash
。 數據 hash 將從SampleKSPGetKeyProperty
獲取,方法是從本地機器store(CertContext->pbCertEncoded)
讀取證書。但是我在使用hash數據時遇到問題,並且在BCryptSignHash
示例代碼期間出現錯誤。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);
}
}
....
}
接下來是SampleKSPSignHash的代碼,調用BCryptSignHash時失敗:
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;
}
我認為在執行這樣的過程並調用憑據提供程序后將登錄到域。 我理解正確嗎? - 提前致謝。
我已經很久沒有寫過類似的東西了,但如果我沒記錯的話,你需要調用 BCryptSignHash 兩次。 第一次得到預期的簽名大小,第二次實際做簽名。
pb輸出
用於接收此 function 生成的簽名的緩沖區的地址。 cbOutput 參數包含此緩沖區的大小。
如果這個參數是NULL,這個function會計算簽名所需的大小,並在pcbResult參數指向的位置返回大小。
即使我已經知道尺寸並將其交給 function,它仍然抱怨 STATUS_INVALID_PARAMETER 是 0xC000000D 的翻譯。 只有在我調用它兩次之后,事情才開始起作用。 請務必仔細閱讀 windows 加密 API 的文檔,因為其中有一些問題。 ;-)
編輯
仔細查看您的示例,我發現您在調用 BCryptSignHash 時將 0 作為最后一個參數。 根據文檔,這應該是 0x00000002 (PKCS1) 或 0x00000008 (PSS):
dwFlags
一組修改此 function 行為的標志。 允許的標志集取決於 hKey 參數指定的密鑰類型。
這可以是以下值之一。
BCRYPT_PAD_PKCS1 使用 PKCS1 填充方案。 pPaddingInfo 參數是一個指向 BCRYPT_PKCS1_PADDING_INFO 結構的指針。
BCRYPT_PAD_PSS 使用概率簽名方案 (PSS) 填充方案。 pPaddingInfo 參數是一個指向 BCRYPT_PSS_PADDING_INFO 結構的指針。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.