簡體   English   中英

使用私鑰和登錄域簽署證書

[英]Sign certificate with private key and logon domain

我正在使用自定義 KSP 和我的憑據提供程序的證書實施與登錄域相關的程序。 我已經成功地從我的憑證提供者交互到自定義 KSP。 我正在實施自定義 KSP。 我在自定義 KSP 中執行處理的步驟如下:

  1. 將已從 ADCS 頒發的模板證書 Kerberos 安裝到本地計算機存儲。
  2. 通過以下命令從 ADCS 發布的文件 (.pfx) 中導出私鑰:
#openssl pkcs12 -in sample.pfx -nocerts -nodes -out sample.key.
#openssl rsa -in sample.key -out sample_private.key.
  1. 流程自定義 KSP 如下所示:
SampleKSPOpenProvider -> SampleKSPOpenKey-> SampleKSPGetKeyProperty -> SampleKSPSignHash.
  1. SampleKSPSignHash中,我讀取了私鑰並導入了密鑰,然后實現了函數BCryptCreateHashBCryptHashDataBCryptFinishHash ,最后是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM