我在不使用注册并坚持使用 .NET 4.5.x 的情况下弄清楚了。我首先使用 CspParameters 创建了一个 RSACrytpoServiceProvider。然后我从 RSACryptoServiceProvider 构造一个私钥和公钥。我创建一个证书请求并从私钥启动。证书请求被编码并转换为原始数据,然后转换为字节。然后这些字节用于创建 X509Certificate2。
public static X509Certificate2 GenerateCertificate(string subjectName)
{
var dn = new CX500DistinguishedName();
dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_COMMA_FLAG);
//Create crytpo provider to generate an assymetric key
int KeyType = (int)X509ProviderType.XCN_PROV_RSA_SCHANNEL;
CspParameters cspParams = new CspParameters(KeyType);
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.KeyContainerName = Guid.NewGuid().ToString();
var rsa = new RSACryptoServiceProvider(2048, cspParams);
var CryptoProvider = rsa.CspKeyContainerInfo.ProviderName;
var keyContainerName = rsa.CspKeyContainerInfo.KeyContainerName;
CX509PrivateKey privateKey = new CX509PrivateKey();
privateKey.MachineContext = true;
privateKey.ProviderName = CryptoProvider;
privateKey.ContainerName = keyContainerName;
privateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
privateKey.Open();
keyContainerName = privateKey.ContainerName;
CX509PublicKey publicKey = privateKey.ExportPublicKey();
var oid = new CObjectId();
oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
var oidlist = new CObjectIds();
oidlist.Add(oid);
var eku = new CX509ExtensionEnhancedKeyUsage();
eku.InitializeEncode(oidlist);
var hashobj = new CObjectId();
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
AlgorithmFlags.AlgorithmFlagsNone, "SHA256");
CX509CertificateRequestCertificate certRequest = new CX509CertificateRequestCertificate();
certRequest.InitializeFromPrivateKey(
X509CertificateEnrollmentContext.ContextMachine,
privateKey,
"");
certRequest.Subject = dn;
certRequest.NotBefore = DateTime.Now;
certRequest.NotAfter = DateTime.Now.AddYears(1);
certRequest.HashAlgorithm = hashobj;
certRequest.X509Extensions.Add((CX509Extension)eku);
certRequest.Encode();
return new X509Certificate2(
Convert.FromBase64String(certRequest.RawData), "",
X509KeyStorageFlags.Exportable)
{
PrivateKey = rsa,
FriendlyName = subjectName
};
}
颁发证书。启动并附加 CSignerCertificate 遵循相同的过程。但在此之前,我将根证书保存到 My, Local Machine Certificate Store。然后,我使用刚刚添加到商店的根创建一个签名证书。然后我从商店中删除证书。
签署证书请求
var dnSigner = new CX500DistinguishedName();
dnSigner.Encode("CN=" + signer.FriendlyName, X500NameFlags.XCN_CERT_NAME_STR_COMMA_FLAG);
string base64Root = Convert.ToBase64String(signer.RawData);
CSignerCertificate certSigner = new CSignerCertificate();
bool useMachineStore = ((ICspAsymmetricAlgorithm)signer.PrivateKey).CspKeyContainerInfo.MachineKeyStore;
certSigner.Initialize(useMachineStore, X509PrivateKeyVerify.VerifyNone, EncodingType.XCN_CRYPT_STRING_BASE64, base64Root);
certRequest.SignerCertificate = certSigner;
certRequest.Issuer = dnSigner;
static void Main(string[] args)
{
X509Certificate2 rootCert = GenerateCertificate("TEST_ROOT");
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(rootCert);
X509Certificate2 signedChild = GenerateUserCertificate("Testy McTesterson", rootCert);
store.Remove(rootCert);
store.Close();
}
需要注意的一些重要事项:这仅适用于某些密钥用法和密钥规范标志 X509Chain 仍将构建和验证,但它会识别根是不受信任的(易于绕过)。