如何解决仅使用 .Net 生成证书请求并提交给 CA
我正在尝试仅使用 .Net 代码创建证书请求并将请求提交给我们的内部 Active Directory PKI 证书颁发机构,然后取回证书。我有一个已经工作了几年的解决方案,但它使用 CERTCLILib 和 CERTENROLLLib,我想摆脱这些依赖项并将此代码移植到 .Net 5。
然后将这些证书导入 Yubikey 设备。我们在 Yubikey 上生成密钥对,然后将公钥与 CSR 一起使用。
这里的这个问题 Generate and Sign Certificate Request using pure .net Framework 对获得 DER 编码的 CSR 非常有帮助,但我仍然有一些我无法弄清楚的问题。
- 如何指定要在
CertificateRequest
对象中使用的 CA 和模板? - 我有一个公钥,它是一个
RSAParameters
对象。如何将其放入RSA
对象以与CertificateRequst
构造函数一起使用? - 获得 DER 编码的 CSR 后,我该如何将其提交给 CA?我在
System.Security.Cryptography.X509Certificates
命名空间中找不到任何实现此目的的类或方法。
这是我当前正在运行的代码,我想将其移植到 .NET 5。请注意,DeviceDetails
包含有关 Yubikey 设备以及 CA 和模板的属性。此代码是配置 Yubikey 设备的大型应用的一部分。
{
//private const int CC_UIPICKCONfig = 0x1;
private const int CR_IN_BASE64 = 0x1;
private const int CR_IN_FORMatanY = 0;
private const int CR_disP_ISSUED = 0x3;
private const int CR_disP_UNDER_SUBMISSION = 0x5;
private const int CR_OUT_BASE64 = 0x1;
public static string GenerateRequest(DeviceDetails deviceDetails)
{
// Create all the objects that will be required
var objPkcs10 = new CX509CertificateRequestPkcs10();
var objDN = new CX500distinguishedname();
var objObjectIds = new CObjectIds();
var objObjectId = new CObjectId();
var objExtensionKeyUsage = new CX509ExtensionKeyUsage();
var objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsage();
var objPublicKey = new CX509PublicKey();
try
{
var publicKey = Utilities.ExportPublicKeyToPEMFormat(deviceDetails.PublicKey);
publicKey = string.Join("",publicKey.Split(new[] { "\r\n" },StringSplitOptions.RemoveEmptyEntries).Where(s => !s.StartsWith("--")));
objPublicKey.InitializefromEncodedPublicKeyInfo(publicKey,EncodingType.XCN_CRYPT_STRING_BASE64);
var sha512 = new CObjectId();
sha512.InitializefromValue("2.16.840.1.101.3.4.2.3");
// Initialize the PKCS#10 certificate request object based on the public key.
objPkcs10.InitializefrompublicKey(X509CertificateEnrollmentContext.ContextUser,objPublicKey,"");
objPkcs10.HashAlgorithm = sha512;
//Key Usage Extension
objExtensionKeyUsage.InitializeEncode(
X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE |
X509KeyUsageFlags.XCN_CERT_NON_REPUDIATION_KEY_USAGE |
X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE |
X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
);
objPkcs10.X509Extensions.Add((CX509Extension)objExtensionKeyUsage);
// Enhanced Key Usage Extension
objObjectId.InitializefromValue("1.3.6.1.5.5.7.3.2"); // OID for Client Authentication usage
objObjectIds.Add(objObjectId);
objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage);
// Encode the name in using the distinguished Name object
objDN.Encode(
deviceDetails.CertificateDetails.Subject,X500NameFlags.XCN_CERT_NAME_STR_NONE
);
// Adding the subject name by using the distinguished Name object initialized above
objPkcs10.Subject = objDN;
// Adding the Subject Alternate Names
var strRfc822Name = deviceDetails.UserDetails.OUN + "@corp.com";
var strUpn = deviceDetails.UserDetails.OUN + "@corp.com";
var objRfc822Name = new CAlternativeName();
var objUserPrincipalName = new CAlternativeName();
var objAlternativeNames = new CAlternativeNames();
var objExtensionAlternativeNames = new CX509ExtensionAlternativeNames();
// Set Alternative RFC822 Name
objRfc822Name.InitializefromString(AlternativeNameType.XCN_CERT_ALT_NAME_RFC822_NAME,strRfc822Name);
// Set Alternative UPN
objUserPrincipalName.InitializefromString(AlternativeNameType.XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME,strUpn);
// Set Alternative Names
objAlternativeNames.Add(objRfc822Name);
objAlternativeNames.Add(objUserPrincipalName);
objExtensionAlternativeNames.InitializeEncode(objAlternativeNames);
objPkcs10.X509Extensions.Add((CX509Extension)objExtensionAlternativeNames);
// Create a CMC outer request and initialize
var cmcReq = new CX509CertificateRequestCmc();
cmcReq.InitializefromInnerRequestTemplateName(objPkcs10,deviceDetails.CertificateDetails.TemplateName);
// encode the request
cmcReq.Encode();
var strRequest = cmcReq.RawData[EncodingType.XCN_CRYPT_STRING_BASE64];
return strRequest;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
// Submit request to CA and get response
public static X509Certificate2 SendRequest(DeviceDetails deviceDetails,string request,out string error)
{
error = "";
// Create all the objects that will be required
//var objCertConfig = new CCertConfig();
var objcertrequest = new Ccertrequest();
try
{
// Submit the request
var idisposition = objcertrequest.Submit(
CR_IN_BASE64 | CR_IN_FORMatanY,request,null,deviceDetails.CertificateDetails.IssuingCa
);
// Check the submission status
if (CR_disP_ISSUED != idisposition) // Not enrolled
{
var strdisposition = objcertrequest.GetdispositionMessage();
if (CR_disP_UNDER_SUBMISSION == idisposition) // Pending
{
error = "The submission is pending: " + strdisposition;
return null;
}
else // Failed
{
error = $"The submission Failed: {strdisposition}. Last status: {objcertrequest.GetLastStatus()}";
return null;
}
}
// Get the certificate
var strCert = objcertrequest.GetCertificate(CR_OUT_BASE64);
var rawCert = Convert.FromBase64String(strCert);
return new X509Certificate2(rawCert);
}
catch (Exception ex)
{
throw new Exception($"Error sending the request. {ex.Message}");
}
}
解决方法
多部分问题很难,因为它们需要多部分答案。以下是我可以回答的部分:
如何指定要在 CertificateRequest 对象中使用的 CA 和模板?
您不能,但没关系,因为您也没有在 CertEnroll 代码中。 CertificateRequest 对象等效于您的 objPkcs10
,CA 和模板用于处理 CreateSigningRequest
输出。
我有一个公钥,它是一个 RSAParameters 对象。如何将其放入 RSA 对象以与 CertificateRequst 构造函数一起使用?
using (RSA key = RSA.Create())
{
key.ImportParameters(rsaParameters);
...
}
一旦我获得了 DER 编码的 CSR,我该如何将其提交给 CA?我在 System.Security.Cryptography.X509Certificates 命名空间中找不到任何实现该功能的类或方法。
框中没有直接用于此的任何内容。基于 CX509CertificateRequest
类名,它似乎使用了 Certificate Management over CMS (CMC),但仍然需要解决身份验证和请求提交部分。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。