【问题标题】:How do I sign my certificate using the root certificate如何使用根证书签署我的证书
【发布时间】:2010-03-04 09:24:20
【问题描述】:

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

到目前为止,我已经能够在商店中安装根证书。下面的代码

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);

使用上面的代码,我可以创建证书,但它看起来没有被根证书签名。我无法弄清楚我所做的是对还是错.. 任何帮助都将不胜感激..

谢谢 阿西夫

【问题讨论】:

  • 谷歌把我送到这里。看起来这会将您的根证书的私钥安装在客户端上。但这不可能是正确的,我一定是弄错了,因为 1)那会很疯狂, 2)有人会在过去 6 年中指出这一点。对吗?

标签: c++ windows cryptoapi


【解决方案1】:

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

【讨论】:

  • 是的..我需要用根证书签名..查看 certcreateselfsigncertificate() 描述,它看起来也可以用来用我的根证书签名..但是我仍然很困惑..如何使用不同于证书链的根证书进行签名..我的意思是,如果我使用根证书签署我的证书,那么我的证书将具有这样的路径.. 根证书___ | | ----- 我的证书.. 非常感谢 Asif
  • 如果我有根证书,你能否给我一些关于如何使用 CryptSignAndEncodeCertificate 的信息。如何创建证书,然后使用我的根证书对其进行签名并在商店中安装。我在 web 上找不到太多帮助。非常感谢 Asif
  • 我不确定 CertCreateSelfSignCertificate 是如何工作的,但一般来说,当您创建自签名证书时,它是一个自己签名的证书。可以由您的根证书签名的唯一自签名证书是您的根证书。我也不知道 CryptSignAndEncodeCertificate 是如何工作的,但这听起来像是你想要做的事情的合理候选者。这是一些将其导出到文件的代码:hi.baidu.com/mingyuejingque/blog/item/…
【解决方案2】:

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

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

此外,我有一个很大的怀疑,即出于您的目的创建证书链不是正确的方法。如果您只需要为身份验证执行此操作,则无需在客户端创建证书。在我看来,处理 singed 消息就足够了。一种使用证书而不是密钥对的情况是,您需要密钥撤销或密钥限制等功能仅用于某些目的(例如仅用于代码签名而不用于数据加密)。

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

您也可以实现您对 Certificate Enrollment API 的要求吗?它不会完全符合您的要求,但它可以解决您的主要问题。

回答其他问题(cmets): 要么我不理解您计划实现为“双向身份验证”的构造,要么这个概念是错误的。

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

我可以写更多我的问题。如果你实现了他自己的基于证书的通信协议,在我理解你的概念之前,我有很大的问题要给出我的建议。

【讨论】:

  • 感谢.. 对此提供了一些见解。我们想要实现什么:我们必须在服务器和客户端之间设置基于证书的身份验证。在 SSL 设置后,服务器应发送其证书(由私有 CA 或根证书签名),并希望客户端发送其证书。现在,服务器和客户端都应将私有 CA 安装为可信证书。我需要做的是在安装服务器和客户端时,我必须创建一个新证书并使用私有可信 CA 对其进行签名。
  • 我们打算使用非对称密钥对加密进行 2 路身份验证。正如您所建议的,我们希望即时创建客户端证书,将其发送到服务器,对其进行签名,然后将其用于 SSL 握手。但是,如果我们查看 2 路身份验证,我确定应该如何采用此模型。如果您能给我有关使用 MS Crypto Api 的提示,那就太好了,尽管我不喜欢 Windows,但我仍然必须在 Windows 上完成这项工作
猜你喜欢
  • 2018-10-08
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
相关资源
最近更新 更多