我以编程方式使用证书并与证书颁发机构进行通信。我一直在使用Windows 2008R2上的C#中的CertClient和CertEnroll COM对象。
我可以生成请求并从CA获取证书。我从这个例子开始: http://blogs.msdn.com/b/alejacma/archive/2008/09/05/how-to-create-a-certificate-request-with-certenroll-and-net-c.aspx
我有两个我无法弄清楚的问题。首先,如何访问用于生成证书的私钥?作为IX509PrivateKey接口一部分的方法似乎不适用于我的测试环境。我给CA的请求与私钥不同,对吗?
第二个问题是我在申请证书时似乎无法提供注册代理证书。此API的旧版本具有使用的方法SetSignerCertificate。我找不到新API中的等价物。
答案 0 :(得分:4)
使用注册代理证书的示例可在Create Enroll on Behalf of Another User Request下的MSDN上找到。证书将安装到您指定的证书存储区中,您可以像使用任何其他已安装的证书一样使用私钥。
完整示例:
// Add references to CERTENROLL (CertEnroll 1.0 Type Library)
// and CERTCLILib (CertCli 1.0 Type Library)
using CERTCLILib;
using CERTENROLLLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using X509KeyUsageFlags = CERTENROLLLib.X509KeyUsageFlags;
namespace TestSubmitEnrollment
{
class Program
{
static void Main(string[] args)
{
string requesterName = @"DOMAIN\otherUser";
string caName = @"CA1.DOMAIN.LOCAL\DOMAIN-CA1-CA";
string template = "User";
// signerCertificate's private key must be accessible to this process
var signerCertificate = FindCertificateByThumbprint("3f817d138f32a9a8df2aa6e43b8aed76eb93a932");
// create a new private key for the certificate
CX509PrivateKey privateKey = new CX509PrivateKey();
// http://blogs.technet.com/b/pki/archive/2009/08/05/how-to-create-a-web-server-ssl-certificate-manually.aspx
privateKey.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
privateKey.MachineContext = false;
privateKey.Length = 2048;
privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_NONE;
privateKey.Create();
// PKCS 10 Request
// we use v1 to avoid compat issues on w2k8
IX509CertificateRequestPkcs10 req = (IX509CertificateRequestPkcs10)new CX509CertificateRequestPkcs10();
req.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, privateKey, template);
// PKCS 7 Wrapper
var signer = new CSignerCertificate();
signer.Initialize(false, X509PrivateKeyVerify.VerifyAllowUI, EncodingType.XCN_CRYPT_STRING_BASE64_ANY,
Convert.ToBase64String(signerCertificate.GetRawCertData()));
var wrapper = new CX509CertificateRequestPkcs7();
wrapper.InitializeFromInnerRequest(req);
wrapper.RequesterName = requesterName;
wrapper.SignerCertificate = signer;
// get CSR
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(wrapper);
var csr = enroll.CreateRequest();
//File.WriteAllText("csr.p7b", csr);
// submit
const int CR_IN_BASE64 = 1, CR_OUT_BASE64 = 1;
const int CR_IN_PKCS7 = 0x300;
ICertRequest2 liveCsr = new CCertRequest();
var disposition = (RequestDisposition)liveCsr.Submit(CR_IN_BASE64 | CR_IN_PKCS7, csr, null, caName);
if (disposition == RequestDisposition.CR_DISP_ISSUED)
{
string resp = liveCsr.GetCertificate(CR_OUT_BASE64);
//File.WriteAllText("resp.cer", resp);
// install the response
var install = new CX509Enrollment();
install.Initialize(X509CertificateEnrollmentContext.ContextUser);
install.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedRoot,
resp, EncodingType.XCN_CRYPT_STRING_BASE64_ANY, null);
}
else
{
Console.WriteLine("disp: " + disposition.ToString());
}
Console.WriteLine("done");
Console.ReadLine();
}
private enum RequestDisposition
{
CR_DISP_INCOMPLETE = 0,
CR_DISP_ERROR = 0x1,
CR_DISP_DENIED = 0x2,
CR_DISP_ISSUED = 0x3,
CR_DISP_ISSUED_OUT_OF_BAND = 0x4,
CR_DISP_UNDER_SUBMISSION = 0x5,
CR_DISP_REVOKED = 0x6,
CCP_DISP_INVALID_SERIALNBR = 0x7,
CCP_DISP_CONFIG = 0x8,
CCP_DISP_DB_FAILED = 0x9
}
private static X509Certificate2 FindCertificateByThumbprint(string sslCertThumbprint)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindByThumbprint, sslCertThumbprint, true);
if (certs.Count > 0)
{
return certs[0];
}
else
{
throw new KeyNotFoundException();
}
}
finally
{
store.Close();
}
}
// we re-declare this to account for backcompat to 2k8
[ComImport, Guid("884E2042-217D-11DA-B2A4-000E7BBB2B09")]
class CX509CertificateRequestPkcs10
{
}
}
}
答案 1 :(得分:0)
我给CA的请求与私钥不同,对吗?
您只能将公钥传递给CA。
在申请证书时,我似乎无法提供注册代理证书。
您需要将PKCS10包装在CMS / CMC中。看看http://tools.ietf.org/html/rfc5272