.NET + OpenSSL +智能卡

发布于 2024-10-27 13:50:23 字数 10810 浏览 5 评论 0原文

我使用 .NET 和 OpenSSL 生成 CA 和客户端证书。

以下代码段生成客户端证书并使用 CA 证书对其进行签名:

//Generating public/private key pair
var userRsa = new RSA();
userRsa.GenerateKeys(4096, 3, null, null);

var userCryptoKey = new CryptoKey(userRsa);


//Creating certificate signing request
var userSubjectName = new X509Name();
userSubjectName.Common = "Some Value";
userSubjectName.OrganizationUnit = "Some Value";
userSubjectName.Organization = "Some Value";
userSubjectName.StateOrProvince = "Some Value";
userSubjectName.StateOrProvince = "Some Value";
userSubjectName.Country = "US";

var userRequest = new X509Request(3, userSubjectName, userCryptoKey);
userRequest.Sign(userCryptoKey, MessageDigest.SHA1);


//Signing Certificate by authority (this part of code will be located in the separate CA Authority service)
X509Certificate userX509Certificate = signingX509CertificateAuthority.ProcessRequest(userRequest, DateTime.Now, DateTime.Now.AddYears(1), MessageDigest.SHA1);
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "basicConstraints", true, "CA:false"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "keyUsage", true, "nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, encipherOnly, decipherOnly, keyAgreement"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "extendedKeyUsage", true, "clientAuth"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "nsComment", true, "OpenSSL Generated Certificate"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "subjectKeyIdentifier", true, "hash"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "authorityKeyIdentifier", true, "keyid,issuer:always"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "issuerAltName", true, "issuer:copy"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "crlDistributionPoints", true, "URI:http://ok/certEnroll/ok-ca.crl"));
userX509Certificate.Sign(signingCryptoKey, MessageDigest.SHA1);


//CA chain
var userX509Chain = new X509Chain();
userX509Chain.Add(rootX509Certificate);
userX509Chain.Add(signingX509Certificate);


//Creating Personal Information Exchange (PFX) Certificate
var userPkcs12 = new PKCS12("1", "Olexiy Kubliy", userCryptoKey, userX509Certificate, new Stack<X509Certificate>(), PKCS12.PBE.SHA1_3DES, PKCS12.PBE.SHA1_3DES, 1);

这段代码工作正常,但有一个问题。我想在智能卡上生成密钥和 PFX,因此证书生成步骤应该是:

1.) 在智能卡上生成公钥/私钥对;

2.) 通过 OpenSLL 创建证书签名请求并使用智能卡上的私钥对其进行签名;

3.) 向我们的 CA 机构服务发送证书签名请求并使用 CA 证书进行签名;

4.) 检索证书(由 CA 机构签名),使用智能卡上存储的私钥对其进行签名,并在智能卡上生成 pfx;

为了使用智能卡,我使用了 Microsoft CryptoAPI 和 NCryptoki。 NET 库,但我最多能做的是在智能卡上生成公钥/私钥对,并在智能卡上导入带有 CA 链的 pfx 证书。我无法签署证书请求和从自己的 CA 机构检索的证书。

使用 Microsoft CryptoAPI:

const string provider = "etoken Base Cryptographic Provider";
const Int32 AT_KEYEXCHANGE = 1;
const Int32 PRIVATEKEYBLOB = 0x7;
const int KP_CERTIFICATE = 26;

const uint type = PROV_RSA_FULL;
IntPtr cardCryptoProvider = IntPtr.Zero;
if (!Win32.CryptAcquireContext(ref cardCryptoProvider, null, provider, type, Win32.CRYPT_NEWKEYSET))
    showWin32Error(Marshal.GetLastWin32Error());

const string fileName = @"D:\test.pfx";
var fileinfo = new FileInfo(fileName);
var br = new BinaryReader(fileinfo.OpenRead());
byte[] Bytes = new byte[fileinfo.Length];
br.Read(Bytes, 0, (int)fileinfo.Length);
br.Close();

IntPtr buffer = Marshal.AllocHGlobal(Bytes.Length);
Marshal.Copy(Bytes, 0, buffer, Bytes.Length);

var cryptDataBlob = new Win32.CRYPT_DATA_BLOB();
cryptDataBlob.pbData = buffer;
cryptDataBlob.cbData = Bytes.Length;

IntPtr store = Win32.PFXImportCertStore(ref cryptDataBlob, "1", Win32.CRYPT_EXPORTABLE | Win32.CRYPT_USER_KEYSET);

IntPtr currentCertContext = IntPtr.Zero;
X509Certificate2 c = null;

do
{
    currentCertContext = Win32.CertEnumCertificatesInStore(store, currentCertContext);
    if (currentCertContext == IntPtr.Zero)
        break;

    uint sizeOfData = 0;

    if (!Win32.CertGetCertificateContextProperty(currentCertContext, 2, IntPtr.Zero, ref sizeOfData))
    {
        showWin32Error(Marshal.GetLastWin32Error());
        continue;
    }

    IntPtr pData = Marshal.AllocHGlobal((int)sizeOfData);

    if (!Win32.CertGetCertificateContextProperty(currentCertContext, 2, pData, ref sizeOfData))
        showWin32Error(Marshal.GetLastWin32Error());

    var pKeyProvInfo = (Win32.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(pData, typeof(Win32.CRYPT_KEY_PROV_INFO));

    int cryptAcquireCertificatePrivateKeyFlags = AT_KEYEXCHANGE;
    IntPtr cryptoProvider = IntPtr.Zero;
    bool callerFree = false;

    if (!Win32.CryptAcquireCertificatePrivateKey(currentCertContext, 0, IntPtr.Zero,
        ref cryptoProvider, ref cryptAcquireCertificatePrivateKeyFlags, ref callerFree))
        showWin32Error(Marshal.GetLastWin32Error());

    IntPtr cryptKeyHandle = IntPtr.Zero;
    if (!Win32.CryptGetUserKey(cryptoProvider, AT_KEYEXCHANGE, ref cryptKeyHandle))
        showWin32Error(Marshal.GetLastWin32Error());


    uint pkSize = 0;
    if (!Win32.CryptExportKey(cryptKeyHandle, IntPtr.Zero, PRIVATEKEYBLOB, 0, null, ref pkSize))
        showWin32Error(Marshal.GetLastWin32Error());

    byte[] pPk = new byte[pkSize];

    if (!Win32.CryptExportKey(cryptKeyHandle, IntPtr.Zero, PRIVATEKEYBLOB, 0, pPk, ref pkSize))
        showWin32Error(Marshal.GetLastWin32Error());

    IntPtr importedKey = IntPtr.Zero;
    if (!Win32.CryptImportKey(cardCryptoProvider, pPk, (uint)pPk.Length, IntPtr.Zero, 0, ref importedKey))
        showWin32Error(Marshal.GetLastWin32Error());

    var cert = new X509Certificate(currentCertContext);

    if (!Win32.CryptSetKeyParam(importedKey, KP_CERTIFICATE, cert.GetRawCertData(), 0))
        showWin32Error(Marshal.GetLastWin32Error());

} while (currentCertContext != IntPtr.Zero);
if (cardCryptoProvider != IntPtr.Zero)
    Win32.CryptReleaseContext(cardCryptoProvider, 0);

使用 NCryptoki。 NET 库:

Cryptoki cryptoki = new Cryptoki(@"C:\Windows\System32\eTPKCS11.dll");
cryptoki.Initialize();

Slot slot = null;

foreach (Slot slot1 in slots)
{
    if (slot1.IsTokenPresent)
    {
        slot = slot1;
        break;
    }
}

Token token = slot.Token;
Session session = token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);

if (session.Login(Session.CKU_USER, "12345678") != 0)
{
    Console.WriteLine("Wrong PIN");
    return;
}

var certificate = new X509Certificate2(@"C:\certificate.pfx", "1", X509KeyStorageFlags.Exportable);            
var keyPair = certificate.PrivateKey as RSA;

var collection = new X509Certificate2Collection();
collection.Import(@"C:\certificate.pfx", "1", X509KeyStorageFlags.PersistKeySet);            

RSAParameters keyParams = keyPair.ExportParameters(true);

var template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_EXTRACTABLE, true));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_MODULUS, keyParams.Modulus));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PUBLIC_EXPONENT, keyParams.Exponent));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE_EXPONENT, keyParams.D));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIME_1, keyParams.P));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIME_2, keyParams.Q));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_EXPONENT_1, keyParams.DP));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_EXPONENT_2, keyParams.DQ));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_COEFFICIENT, keyParams.InverseQ));            
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "dddd"));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));            
session.Objects.Create(template);

foreach (X509Certificate2 x509Certificate2 in collection)
{
    var template1 = new CryptokiCollection();
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, false));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_CATEGORY, x509Certificate2.HasPrivateKey ? 0 : 2));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_VALUE, x509Certificate2.RawData));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_SUBJECT, x509Certificate2.SubjectName.RawData));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));

    session.Objects.Create(template1);
}

任何人都可以帮助我签署证书请求(通过 Open SLL 生成)并使用存储在智能卡上的私钥签署从自己的 CA 机构检索的证书吗?

使用 NCryptoki Sign 方法对一些文本进行签名:

Cryptoki cryptoki = new Cryptoki(@"C:\Windows\System32\eTPKCS11.dll");
cryptoki.Initialize();
Slot slot = _cryptoki.ActiveSlots.FirstOrDefault();
Session session = slot.Token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);
session.Login(Session.CKU_USER, "12345678")

CryptokiCollection templatePub = new CryptokiCollection();
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PUBLIC_KEY));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, true));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "My Key"));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, "1"));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_MODULUS_BITS, 1024));

CryptokiCollection templatePri = new CryptokiCollection();
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, true));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "My Key"));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, "1"));

Key[] keys = session.GenerateKeyPair(Mechanism.RSA_PKCS_KEY_PAIR_GEN, templatePub, templatePri);
var privateKey = (RSAPrivateKey)keys[1];

const string text = "Some Value";
byte[] textBytes = Encoding.ASCII.GetBytes(text);
int result = session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
byte[] signature = session.Sign(textBytes);

I'm using .NET and OpenSSL to generate CA and client certificates.

The following piece of code generates a client certificate and signs it with the CA certificate:

//Generating public/private key pair
var userRsa = new RSA();
userRsa.GenerateKeys(4096, 3, null, null);

var userCryptoKey = new CryptoKey(userRsa);


//Creating certificate signing request
var userSubjectName = new X509Name();
userSubjectName.Common = "Some Value";
userSubjectName.OrganizationUnit = "Some Value";
userSubjectName.Organization = "Some Value";
userSubjectName.StateOrProvince = "Some Value";
userSubjectName.StateOrProvince = "Some Value";
userSubjectName.Country = "US";

var userRequest = new X509Request(3, userSubjectName, userCryptoKey);
userRequest.Sign(userCryptoKey, MessageDigest.SHA1);


//Signing Certificate by authority (this part of code will be located in the separate CA Authority service)
X509Certificate userX509Certificate = signingX509CertificateAuthority.ProcessRequest(userRequest, DateTime.Now, DateTime.Now.AddYears(1), MessageDigest.SHA1);
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "basicConstraints", true, "CA:false"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "keyUsage", true, "nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, encipherOnly, decipherOnly, keyAgreement"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "extendedKeyUsage", true, "clientAuth"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "nsComment", true, "OpenSSL Generated Certificate"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "subjectKeyIdentifier", true, "hash"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "authorityKeyIdentifier", true, "keyid,issuer:always"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "issuerAltName", true, "issuer:copy"));
userX509Certificate.AddExtension(new X509Extension(signingX509Certificate, userX509Certificate, "crlDistributionPoints", true, "URI:http://ok/certEnroll/ok-ca.crl"));
userX509Certificate.Sign(signingCryptoKey, MessageDigest.SHA1);


//CA chain
var userX509Chain = new X509Chain();
userX509Chain.Add(rootX509Certificate);
userX509Chain.Add(signingX509Certificate);


//Creating Personal Information Exchange (PFX) Certificate
var userPkcs12 = new PKCS12("1", "Olexiy Kubliy", userCryptoKey, userX509Certificate, new Stack<X509Certificate>(), PKCS12.PBE.SHA1_3DES, PKCS12.PBE.SHA1_3DES, 1);

This code works fine, but there is one issue. I want to generate a key and PFX on smartcard, so the certificate generation steps should be the next:

1.) Generate public/private key pair on smart card;

2.) Create certificate signign request over OpenSLL and sign it with the private key on smartcard;

3.) Send certificate signing request to our CA Authority service and sign it with the CA certificate;

4.) Retrieve certificate (signed by CA Authority), sign it with the private key stored on smartcard and generate pfx on smartcard;

To work with smartcards I used the Microsoft CryptoAPI and NCryptoki. NET library, but the most I could do is to generate the public/private key pair on the smartcard and import pfx certificate with CA chain on the smartcard. I can not sign a certificate request and certificate retrieved from own CA authority.

Using Microsoft CryptoAPI:

const string provider = "etoken Base Cryptographic Provider";
const Int32 AT_KEYEXCHANGE = 1;
const Int32 PRIVATEKEYBLOB = 0x7;
const int KP_CERTIFICATE = 26;

const uint type = PROV_RSA_FULL;
IntPtr cardCryptoProvider = IntPtr.Zero;
if (!Win32.CryptAcquireContext(ref cardCryptoProvider, null, provider, type, Win32.CRYPT_NEWKEYSET))
    showWin32Error(Marshal.GetLastWin32Error());

const string fileName = @"D:\test.pfx";
var fileinfo = new FileInfo(fileName);
var br = new BinaryReader(fileinfo.OpenRead());
byte[] Bytes = new byte[fileinfo.Length];
br.Read(Bytes, 0, (int)fileinfo.Length);
br.Close();

IntPtr buffer = Marshal.AllocHGlobal(Bytes.Length);
Marshal.Copy(Bytes, 0, buffer, Bytes.Length);

var cryptDataBlob = new Win32.CRYPT_DATA_BLOB();
cryptDataBlob.pbData = buffer;
cryptDataBlob.cbData = Bytes.Length;

IntPtr store = Win32.PFXImportCertStore(ref cryptDataBlob, "1", Win32.CRYPT_EXPORTABLE | Win32.CRYPT_USER_KEYSET);

IntPtr currentCertContext = IntPtr.Zero;
X509Certificate2 c = null;

do
{
    currentCertContext = Win32.CertEnumCertificatesInStore(store, currentCertContext);
    if (currentCertContext == IntPtr.Zero)
        break;

    uint sizeOfData = 0;

    if (!Win32.CertGetCertificateContextProperty(currentCertContext, 2, IntPtr.Zero, ref sizeOfData))
    {
        showWin32Error(Marshal.GetLastWin32Error());
        continue;
    }

    IntPtr pData = Marshal.AllocHGlobal((int)sizeOfData);

    if (!Win32.CertGetCertificateContextProperty(currentCertContext, 2, pData, ref sizeOfData))
        showWin32Error(Marshal.GetLastWin32Error());

    var pKeyProvInfo = (Win32.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(pData, typeof(Win32.CRYPT_KEY_PROV_INFO));

    int cryptAcquireCertificatePrivateKeyFlags = AT_KEYEXCHANGE;
    IntPtr cryptoProvider = IntPtr.Zero;
    bool callerFree = false;

    if (!Win32.CryptAcquireCertificatePrivateKey(currentCertContext, 0, IntPtr.Zero,
        ref cryptoProvider, ref cryptAcquireCertificatePrivateKeyFlags, ref callerFree))
        showWin32Error(Marshal.GetLastWin32Error());

    IntPtr cryptKeyHandle = IntPtr.Zero;
    if (!Win32.CryptGetUserKey(cryptoProvider, AT_KEYEXCHANGE, ref cryptKeyHandle))
        showWin32Error(Marshal.GetLastWin32Error());


    uint pkSize = 0;
    if (!Win32.CryptExportKey(cryptKeyHandle, IntPtr.Zero, PRIVATEKEYBLOB, 0, null, ref pkSize))
        showWin32Error(Marshal.GetLastWin32Error());

    byte[] pPk = new byte[pkSize];

    if (!Win32.CryptExportKey(cryptKeyHandle, IntPtr.Zero, PRIVATEKEYBLOB, 0, pPk, ref pkSize))
        showWin32Error(Marshal.GetLastWin32Error());

    IntPtr importedKey = IntPtr.Zero;
    if (!Win32.CryptImportKey(cardCryptoProvider, pPk, (uint)pPk.Length, IntPtr.Zero, 0, ref importedKey))
        showWin32Error(Marshal.GetLastWin32Error());

    var cert = new X509Certificate(currentCertContext);

    if (!Win32.CryptSetKeyParam(importedKey, KP_CERTIFICATE, cert.GetRawCertData(), 0))
        showWin32Error(Marshal.GetLastWin32Error());

} while (currentCertContext != IntPtr.Zero);
if (cardCryptoProvider != IntPtr.Zero)
    Win32.CryptReleaseContext(cardCryptoProvider, 0);

using NCryptoki. NET library:

Cryptoki cryptoki = new Cryptoki(@"C:\Windows\System32\eTPKCS11.dll");
cryptoki.Initialize();

Slot slot = null;

foreach (Slot slot1 in slots)
{
    if (slot1.IsTokenPresent)
    {
        slot = slot1;
        break;
    }
}

Token token = slot.Token;
Session session = token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);

if (session.Login(Session.CKU_USER, "12345678") != 0)
{
    Console.WriteLine("Wrong PIN");
    return;
}

var certificate = new X509Certificate2(@"C:\certificate.pfx", "1", X509KeyStorageFlags.Exportable);            
var keyPair = certificate.PrivateKey as RSA;

var collection = new X509Certificate2Collection();
collection.Import(@"C:\certificate.pfx", "1", X509KeyStorageFlags.PersistKeySet);            

RSAParameters keyParams = keyPair.ExportParameters(true);

var template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_EXTRACTABLE, true));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_MODULUS, keyParams.Modulus));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PUBLIC_EXPONENT, keyParams.Exponent));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE_EXPONENT, keyParams.D));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIME_1, keyParams.P));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIME_2, keyParams.Q));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_EXPONENT_1, keyParams.DP));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_EXPONENT_2, keyParams.DQ));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_COEFFICIENT, keyParams.InverseQ));            
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "dddd"));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));            
session.Objects.Create(template);

foreach (X509Certificate2 x509Certificate2 in collection)
{
    var template1 = new CryptokiCollection();
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, false));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_CATEGORY, x509Certificate2.HasPrivateKey ? 0 : 2));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_VALUE, x509Certificate2.RawData));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_SUBJECT, x509Certificate2.SubjectName.RawData));
    template1.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));

    session.Objects.Create(template1);
}

Can anybody help me with signing a certificate request(generated over Open SLL) and signing certificate retrieved from own CA Authority with the private key stored on smartcard?

Using NCryptoki Sign method for signing some text:

Cryptoki cryptoki = new Cryptoki(@"C:\Windows\System32\eTPKCS11.dll");
cryptoki.Initialize();
Slot slot = _cryptoki.ActiveSlots.FirstOrDefault();
Session session = slot.Token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);
session.Login(Session.CKU_USER, "12345678")

CryptokiCollection templatePub = new CryptokiCollection();
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PUBLIC_KEY));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, true));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "My Key"));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, "1"));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_MODULUS_BITS, 1024));

CryptokiCollection templatePri = new CryptokiCollection();
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, true));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "My Key"));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, "1"));

Key[] keys = session.GenerateKeyPair(Mechanism.RSA_PKCS_KEY_PAIR_GEN, templatePub, templatePri);
var privateKey = (RSAPrivateKey)keys[1];

const string text = "Some Value";
byte[] textBytes = Encoding.ASCII.GetBytes(text);
int result = session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
byte[] signature = session.Sign(textBytes);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笑咖 2024-11-03 13:50:23

您误解了您任务的某些方面。

首先,您不需要使用您的私钥重新签署从 CA 收到的证书(步骤 4)。它已经由 CA 的私钥签名。

其次,PFX只是一种可以存储证书的格式。 PFX用于在文件中保存密码加密的证书和私钥;在智能卡上存储证书时不使用它。

第三,硬件令牌通常不允许导出私钥,也就是说,如果令牌上已生成密钥对,您将无法创建证书+密钥 PFX 文件。

现在回答你的问题。

据我所知,OpenSSL 不支持访问存储在 HSM 上的密钥,即您将无法获取私钥来签署请求。然而,如果令牌供应商提供适当的 CSP(实际上是 CryptoAPI 和低级令牌驱动程序之间的一层),则可以使用 CryptoAPI 访问此类密钥,就像通常的基于系统的密钥一样。但是,由于此类密钥不可导出,因此您只能将它们与 CryptoAPI 函数一起使用,并通过 CryptoAPI 密钥句柄引用它们。同时,CryptoAPI的证书注册控制不支持从现有私钥生成证书请求(始终生成全新的密钥对)。

也就是说,您有以下三个选项:

  1. 基于 CryptoAPI。自己形成证书请求 BLOB (PKCS#10) 并使用 CryptSignHash() 方法对其进行签名;然后将创建的签名附加到 BLOB 中。可以在形成请求之前通过 CryptGenKey() 方法或通过其他方式(例如某些 PKCS#11 组件或工具)生成密钥对。

  2. 基于 OpenSSL。生成一个全新的密钥对(您将被迫将其存储在文件中)和证书请求。将密钥对导入到令牌中。销毁文件中存储的私钥。

  3. 第三个。使用一些 PKCS#11 库生成密钥对并签署请求。与选项 1 一样,您需要自己提出请求。

You are misunderstanding certain aspects of your task.

First, you do not need to re-sign the certificate received from a CA with your private key (step 4). It will be already signed by the CA's private key.

Second, PFX is just a format in which certificate can be stored. PFX is used to keep password-encrypted certificates and private keys in files; it is not used when storing certificates on smart cards.

Third, hardware tokens usually do not allow exporting private keys, that is, you won't be able to create a certificate+key PFX file if the key pair has been generated on the token.

Now to your question.

As far as I'm aware, OpenSSL doesn't support accessing keys stored on HSM's, i.e. you just won't be able to get the private key in order to sign the request. Yet, such keys can be accessed with CryptoAPI just like usual system-based keys if the vendor of the token ships an appropriate CSP (which is actually a layer between CryptoAPI and low-level token driver). However, as such keys are non-exportable, you will only be able to use them with CryptoAPI functions, referencing them by CryptoAPI key handles. At the same time, CryptoAPI's certificate enrollment control does not support generation of certificate requests from existing private keys (brand new keypairs are always generated).

That is, you have the following three options:

  1. CryptoAPI-based. Form certificate request BLOB (PKCS#10) yourself and sign it with the use of CryptSignHash() method; then append the created signature to the BLOB. The keypair can be generated prior to forming the request either by CryptGenKey() method or via other means (e.g. some PKCS#11 component or tool).

  2. OpenSSL-based. Generate a brand new keypair (you will be forced to store it in files) and certificate request. Import the keypair to the token. Destroy the private key stored in file.

  3. The third. Use some PKCS#11 library to generate a keypair and sign the request. As with option 1, you will need to form the request yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文