【发布时间】:2021-07-04 15:06:51
【问题描述】:
我正在尝试仅使用 .Net 代码来创建证书请求并将请求提交给我们的本地 Active Directory PKI 证书颁发机构,然后取回证书。我有一个已经工作了几年的解决方案,但它使用 CERTCLILib 和 CERTENROLLLib,我想摆脱这些依赖关系并将此代码移植到 .Net 5。
然后将这些证书导入 Yubikey 设备。我们在 Yubikey 上生成密钥对,然后将公钥与 CSR 一起使用。
Generate and Sign Certificate Request using pure .net Framework 此处的这个问题对获得 DER 编码的 CSR 非常有帮助,但我仍有一些问题无法弄清楚。
- 如何指定 CA 和要在
CertificateRequest对象中使用的模板? - 我有一个公共密钥,它是一个
RSAParameters对象。如何将其放入RSA对象中以与CertificateRequst构造函数一起使用? - 获得 DER 编码的 CSR 后,如何将其提交给 CA?我在
System.Security.Cryptography.X509Certificates命名空间中找不到任何可以实现这一点的类或方法。
这是我想要移植到 .NET 5 的当前正在运行的代码。请注意,DeviceDetails 包含有关 Yubikey 设备以及 CA 和模板的属性。此代码是配置 Yubikey 设备的更大应用程序的一部分。
public static class CertificateUtilities
{
//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}");
}
}
}
【问题讨论】:
标签: c# .net-core certificate pki