2016-04-19 68 views
2

我試圖使用最初導入到使用MMC的「證書」管理單元的Windows 10計算機上的CurrentUser密鑰庫的X509證書。已經在Windows 8.1計算機上測試過相同的過程,結果相同。.NET Framework x509Certificate2類,HasPrivateKey == true && PrivateKey == null?

使用PowerShell的標準PKI模塊,我使用的是得到一個X509Certificate2對象獲取-項目:

$my_cert = Get-Item Cert:\CurrentUser\My\ADAA82188A17THUMBPRINTXXXXXXXXXXX 

$my_cert | fl *輸出如下:

PSPath     : Microsoft.PowerShell.Security\Certificate::CurrentUser\My\XXXXXXXXXXXXXXXXXXX 
PSParentPath    : Microsoft.PowerShell.Security\Certificate::CurrentUser\My 
PSChildName    : XXXXXXXXXXXXXXXXXXX 
PSDrive     : Cert 
PSProvider    : Microsoft.PowerShell.Security\Certificate 
PSIsContainer   : False 
EnhancedKeyUsageList  : {Secure Email (1.3.6.1.5.5.7.3.4), IP security user (1.3.6.1.5.5.7.3.7), Encrypting File 
          System (1.3.6.1.4.1.311.10.3.4), Document Signing (1.3.6.1.4.1.311.10.3.12)...} 
DnsNameList    : {My Name} 
SendAsTrustedIssuer  : False 
EnrollmentPolicyEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty 
EnrollmentServerEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty 
PolicyId     : {D52C406F-C279-4BF2-B7C2-EE704290DB3E} 
Archived     : False 
Extensions    : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, 
          System.Security.Cryptography.Oid, System.Security.Cryptography.Oid...} 
FriendlyName    : 
IssuerName    : System.Security.Cryptography.X509Certificates.X500DistinguishedName 
NotAfter     : 4/15/2017 2:15:16 PM 
NotBefore    : 4/15/2016 2:15:16 PM 
HasPrivateKey   : True 
PrivateKey    : 
PublicKey    : System.Security.Cryptography.X509Certificates.PublicKey 
RawData     : {56, 130, 19, 252...} 
SerialNumber    : 4F0000002F700000000000000000000000 
SubjectName    : System.Security.Cryptography.X509Certificates.X500DistinguishedName 
SignatureAlgorithm  : System.Security.Cryptography.Oid 
Thumbprint    : XXXXXXXXXXXXXXXXXXX 
Version     : 3 
Handle     : 2241663016272 
Issuer     : CN=Issuing CA, DC=My, DC=Domain, DC=us 
Subject     : [email protected], CN=My Name 

所以HasPrivateKey ==真,但PrivateKey == null。我一直在想如何獲得訪問私鑰來執行加密和解密。我在網上看到的所有例子都似乎表明X509Certificate2類的PrivateKey屬性應該是可用的,但顯然我錯過了一些東西。

我讀過類似的問題,例如Empty PrivateKey in x509certificate2,但沒有一個能夠解決我的問題。我也讀過Paul Stovell的Eight tips for working with X.509 certificates in .NET,這很有啓發,但最終沒有幫助。這也幫助我確認私鑰則在正確的位置,而且據我所知,有正確的權限由x509Certificate2類引用:

C:\Users\My.Name\AppData\Roaming\Microsoft\SystemCertificates\My\Keys 

密鑰文件的名稱相匹配證書上的主題密鑰標識符。

編輯:

certutil -user -store my "Serial Number"輸出是:

Serial Number: 4f000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
Issuer: CN=Issuing CA, DC=My, DC=Domain, DC=us 
NotBefore: 4/15/2016 2:15 PM 
NotAfter: 4/15/2017 2:15 PM 
Subject: [email protected], CN=My Name 
Non-root Certificate 
Template: Userv1, User v1 
Cert Hash(sha1): ad ab 82 18 8a 17 4d 75 11 04 48 7c 43 43 d4 05 b9 74 c8 4c 
    Key Container = te-Userv1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 
    Unique container name: fcbba1aa0xxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 
    Provider = Microsoft Software Key Storage Provider 
Encryption test passed 
CertUtil: -store command completed successfully. 

什麼 「鑰匙」 的資料片我錯過了?爲什麼不能方便地從X509Certificate2對象中引用私鑰?我如何獲得訪問權限?

+0

嘗試'$ my_cert.get_PrivateKey()'。請問它會拋出任何異常? – PetSerAl

+0

@PetSerAl,我確實得到了一個異常 - 「無效的提供程序類型指定。」 –

回答

4

這可能表明下列之一:

1)私有密鑰存儲在密鑰存儲提供程序(而不是傳統的加密服務提供商),這是不好的.NET的支持而不是由PrivateKey財產支持X509Certificate2班。您可以通過運行以下命令來檢查:

certutil -user -store my "<CertSerialNumber>" 

2)私鑰丟失。

HasPrivateKey財產並不一定反映實際的圖片和不存在的密鑰可以TrueFalse現有的密鑰。運行上面的certutil命令以確定是否顯示了密鑰。

在這種情況下,如果私鑰被提出,但綁定被打破,你可以嘗試通過運行以下命令來恢復綁定:

certutil -user -repairstore my "<CertSerialNumber>" 
+0

我已經將CertUtil的輸出添加到我原來的帖子中。它看起來像你是正確的 - 私人密鑰存儲密鑰存儲供應商(KSP)。我正在尋找現在使用KSP和CNG鑰匙的很好的例子...瞭解任何? –

+0

你究竟需要什麼? – Crypt32

+0

我想我不需要任何東西。我只是尋找一個通過例子來理解的捷徑,但我設法一起破解它......感謝您的幫助! –

3

你的certutil信息顯示Provider = Microsoft Software Key Storage Provider這意味着私鑰存儲在Windows CNG下,而不是Windows CryptoAPI(CAPI)。

.NET 4。6添加了GetRSAPrivateKey(擴展)方法,以便於讓PrivateKey屬性返回非RSACryptoServiceProvider(或DSACryptoServiceProvider)的內容。如果您有權訪問該方法(我不確定PowerShell使用哪個版本的框架),那麼它可以解決您的問題。

有兩點需要注意,雖然:

  1. GetRSAPrivateKey每次返回一個唯一的一次性對象。你應該把它放在一個使用語句/手動調用Dispose完成它(而不是cert.PrivateKey,這是不唯一的,所以不應該被處置)。
  2. sign/verify //加密/解密方法已經下移到RSA基類(albiet具有略微不同,更具前瞻性的簽名)。
2

我解決了這個問題。

由於某些原因,.NET框架無法從文件中導入私鑰,但是,它可以從內置的Windows存儲中導入,這是因爲PrivateKey方法僅支持RSA和DSA密鑰是根據Microsoft Spec:閱讀「備註」部分下的說明。

總之,要獲得專用密鑰對象返回的關鍵信息,你需要做到以下幾點:

1)導入您的P12文件到Windows密鑰庫通過雙擊它。 2)當提示爲「當前用戶」 3)選擇「導入」確保你選擇「Make鍵可導出」,

如果此選項不可用,那麼你的證書沒有私有 關鍵

。 4)選擇「自動放到商店」

5)寫出下面的代碼檢索您的證書:

Dim CertDataInfo As System.Security.Cryptography.X509Certificates.X509Certificate2 
Dim Store As New System.Security.Cryptography.X509Certificates.X509Store("MY", Security.Cryptography.X509Certificates.StoreLocation.CurrentUser) 

Store.Open(Security.Cryptography.X509Certificates.OpenFlags.ReadOnly) 
Console.writeline (Store.Certificates.Count) 

For I = 0 To Store.Certificates.Count - 1 
If Store.Certificates.Item(I).FriendlyName = "Heider Sati's Cert(48F57XTHVE)" Then 
    CertDataInfo = Store.Certificates.Item(I) 
End If 

Console.writeline ("Cert: " & Store.Certificates.Item(I).FriendlyName) 

Next 
Store.Close() 

If CertDataInfo.PrivateKey Is Nothing Then 
MsgBox("NULL") 
Else 
MsgBox("YES") 
End If 

6)運行代碼,如果你得到一個YES,那麼私鑰不爲NULL (或什麼都沒有),這就是你要找的。

如果您直接從文件加載相同的證書,私鑰將始終爲NOTHING/NULL,但HasPrivateKey會說YES,這意味着(我知道有一個密鑰,但是,我不知道如何理解它。當你把它導入到Windows應用商店,操作系統將其轉換爲.NET兼容的格式。

我希望這有助於。