如何使用根证书签署我的证书

时间:2010-03-04 09:24:20

标签: c++ windows cryptoapi

我在服务器和客户端之间使用基于证书的身份验证。我已经生成了根证书。我的客户端在安装时将生成一个新证书并使用根证书对其进行签名。我需要使用Windows API。不能使用像makecert这样的任何windows工具。

直到现在我已经能够在商店中安装Root证书了。代码

X509Certificate2 ^ certificate = gcnew X509Certificate2("C:\\rootcert.pfx","test123");
X509Store ^ store = gcnew X509Store( "teststore",StoreLocation::CurrentUser );
store->Open( OpenFlags::ReadWrite );
store->Add( certificate );
store->Close();

然后打开已安装的根证书以获取上下文

GetRootCertKeyInfo(){
  HCERTSTORE hCertStore;
  PCCERT_CONTEXT pSignerCertContext=NULL;
  DWORD dwSize = NULL; 
  CRYPT_KEY_PROV_INFO* pKeyInfo = NULL; 
  DWORD dwKeySpec;
  if ( !( hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL,  CERT_SYSTEM_STORE_CURRENT_USER,L"teststore")))
  {
    _tprintf(_T("Error 0x%x\n"), GetLastError());
  }
  pSignerCertContext = CertFindCertificateInStore(hCertStore,MY_ENCODING_TYPE,0,CERT_FIND_ANY,NULL,NULL);

if(NULL == pSignerCertContext)
{
    _tprintf(_T("Error 0x%x\n"), GetLastError());
}

if(!(CertGetCertificateContextProperty( pSignerCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwSize))) 
{ 
    _tprintf(_T("Error 0x%x\n"), GetLastError());
} 

if(pKeyInfo) 
   free(pKeyInfo); 
if(!(pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize))) 
{ 
    _tprintf(_T("Error 0x%x\n"), GetLastError());
} 


if(!(CertGetCertificateContextProperty( pSignerCertContext, CERT_KEY_PROV_INFO_PROP_ID, pKeyInfo, &dwSize))) 
{    
    _tprintf(_T("Error 0x%x\n"), GetLastError());
}
return pKeyInfo;
}

然后最终创建了证书并使用pKeyInfo

签名
    // Acquire key container
if (!CryptAcquireContext(&hCryptProv, _T("trykeycon"), NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 
{
  _tprintf(_T("Error 0x%x\n"), GetLastError());

  // Try to create a new key container
  _tprintf(_T("CryptAcquireContext... "));
  if (!CryptAcquireContext(&hCryptProv, _T("trykeycon"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
  {
    _tprintf(_T("Error 0x%x\n"), GetLastError());
    return 0;
  }
  else 
  {
    _tprintf(_T("Success\n"));
  }
}
else
{
  _tprintf(_T("Success\n"));
}

// Generate new key pair
_tprintf(_T("CryptGenKey... "));
if (!CryptGenKey(hCryptProv, AT_SIGNATURE, 0x08000000 /*RSA-2048-BIT_KEY*/, &hKey))
{
  _tprintf(_T("Error 0x%x\n"), GetLastError());
  return 0;
}
else
{
  _tprintf(_T("Success\n"));
}
//some code
    CERT_NAME_BLOB SubjectIssuerBlob;
memset(&SubjectIssuerBlob, 0, sizeof(SubjectIssuerBlob));
SubjectIssuerBlob.cbData = cbEncoded;
SubjectIssuerBlob.pbData = pbEncoded;

// Prepare algorithm structure for self-signed certificate
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
memset(&SignatureAlgorithm, 0, sizeof(SignatureAlgorithm));
SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;

// Prepare Expiration date for self-signed certificate
SYSTEMTIME EndTime;
GetSystemTime(&EndTime);
EndTime.wYear += 5;

// Create self-signed certificate
_tprintf(_T("CertCreateSelfSignCertificate... "));

CRYPT_KEY_PROV_INFO* aKeyInfo;
aKeyInfo = GetRootCertKeyInfo();
pCertContext = CertCreateSelfSignCertificate(NULL, &SubjectIssuerBlob, 0, aKeyInfo, &SignatureAlgorithm, 0, &EndTime, 0);

使用上面的代码,我可以创建证书,但它看起来不会被根证书签名。我无法确定我所做的是对还是不对.. 非常感谢任何帮助。

由于 阿西

2 个答案:

答案 0 :(得分:1)

我认为您不需要自签名证书。您想创建一个由“根”证书签名的新“客户”证书,对吗?我认为您需要使用CryptSignAndEncodeCertificate来执行此操作。

答案 1 :(得分:1)

首先,几年前我写了一些产品,其中还包含您要求的完整代码:创建新证书并根据其他根证书对其进行签名。此代码仅使用 Microsoft CryptoAPI 。但在我给你详细解答或发布一些我想知道的代码之前,你的问题是否真实:你的问题已经有一个半月了。

一般来说,为了做你想做的事,不应该使用CertCreateSelfSignCertificate()函数,而是创建一个关于其他CryptoAPI的证书。 CertCreateSelfSignCertificate()函数只能用于创建和签署自签名证书。它无法使用您创建的其他证书签署证书。此外,CertCreateSelfSignCertificate()函数(或至少在几年前)对创建的私钥的长度进行了严格的限制。因此,必须做出CertCreateSelfSignCertificate()函数手动执行的相同操作。 API链中的最后一个API是CryptSignAndEncodeCertificate(),就像你在另一个问题上写的那样回答了你的问题。

此外,我有一个大的嫌疑人,为您的目的创建证书链是不正确的方式。如果只需要进行身份验证,则无需在客户端创建证书。在我看来,使用有罪信息就足够了。一个使用证书而不是密钥对的情况是,您需要关键撤销或密钥限制等功能,仅用于某些目的(例如,仅用于代码签名而不用于数据加密)。

如果您确实需要实施基于认证的身份验证,那么至少您必须创建客户端计算机的证书,将其发送到服务器计算机并在服务器计算机上唱出客户端证书,因为只有服务器计算机可以保存私钥根证书。

您还可以根据证书注册API 实施您的要求吗?它不是你要求的,但它可以解决你的主要问题。

回答其他问题(评论): 要么我不理解您计划实现的构造为“双向认证”或概念是错误的。

  1. 我不明白您计划如何以及何时将所有客户端的客户端证书传输到服务器。
  2. 您希望与客户端根CA签署客户端证书,因此您必须在客户端上保留客户端根CA证书的私钥(!!! ???)。
  3. 如果服务器没有任何关于客户端的验证信息(如其根CA证书),那么您实际上无法使用客户端证书进行客户端授权。任何拥有证书的客户都将被“授权”。
  4. 使用没有客户端证书的标准SSL,您可以确保始终与同一客户端进行通信。因此,如果您没有解决客户端根CA传输到服务器的问题,您将无法像标准(没有客户端证书)SSL那样实现更高的安全性。
  5. 您写的内容似乎是您尝试不在服务器和客户端之间使用标准通信协议。而不是你试图引入一个新的自己的协议。 非常危险!如果您不是加密专家,您将会实现一个看起来只是安全的协议,而不是那样。 “小”问题,如持有私钥和公钥从客户端到服务器或后端的安全传输是非常重要的加密主题。有不同的加密协议可以解决。所以不要试图在这方面实施新的东西!
  6. 再想一想你为什么要使用客户端证书。你真的用这种方式实现客户端身份验证吗?例如,在标准SSL中,可以确保一个人与同一客户端进行通信,并且仅使用随机的随机数和为会话生成的对称密钥。是否要为每个客户端或每个会话生成证书?
  7. 我可以写更多我的问题。如果你实施他自己的基于证书的通信协议,那么在我理解你的概念之前,我有很大的问题要提出我的建议。