.NET Standard 2.0下如何从PEM加载私钥生成X509Certificate2适配Unity
.NET Standard 2.0(Unity 2020.3环境)加载PEM格式证书+私钥解决方案
方案一:预先转换为PFX格式(最简单,无第三方依赖)
该方案不需要额外引入第三方库,.NET Standard 2.0原生支持加载PFX格式证书,兼容性最好,优先推荐。
首先使用openssl命令将现有的证书、私钥PEM文件转换为PFX格式:
openssl pkcs12 -export -out server.pfx -inkey server-key.pem -in server-cert.pem
执行过程中会要求输入已加密私钥的密码,同时可以自定义PFX文件的保护密码。
转换完成后直接用原生代码加载即可:
using System.Security.Cryptography.X509Certificates; // KeyStorageFlags配置适配跨平台场景,避免Windows专属API依赖 var cert = new X509Certificate2( "server.pfx", "你设置的PFX保护密码", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable ); // 生成的cert实例可直接传入SslStream进行身份验证
该方案完美适配Windows、Linux、macOS全平台运行环境,完全兼容Unity 2020.3的.NET Standard 2.0运行时。
方案二:动态解析PEM文件(需引入BouncyCastle库)
如果业务场景需要动态加载PEM文件,无法预先转换为PFX格式,可以使用兼容.NET Standard 2.0的Portable.BouncyCastle密码学库实现解析,该库完全跨平台,不依赖系统专属API。
代码示例
using System; using System.IO; using System.Security.Cryptography.X509Certificates; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Pkcs12; using Org.BouncyCastle.X509; public static X509Certificate2 LoadCertFromPem(string certPemPath, string privateKeyPemPath, string keyPassword = null) { // 加载PEM格式证书 X509Certificate cert; using (var reader = new StreamReader(certPemPath)) { var pemReader = new PemReader(reader); cert = (X509Certificate)pemReader.ReadObject(); } // 加载PEM格式私钥,支持加密私钥解析 AsymmetricKeyParameter privateKey; using (var reader = new StreamReader(privateKeyPemPath)) { PemReader pemReader = string.IsNullOrEmpty(keyPassword) ? new PemReader(reader) : new PemReader(reader, new PasswordFinder(keyPassword)); var keyObject = pemReader.ReadObject(); privateKey = keyObject is AsymmetricCipherKeyPair keyPair ? keyPair.Private : (AsymmetricKeyParameter)keyObject; } // 构造临时PFX结构绕开.NET Standard 2.0的私钥绑定限制 var store = new Pkcs12Store(); var certEntry = new X509CertificateEntry(cert); store.SetCertificateEntry("temp_cert", certEntry); store.SetKeyEntry("temp_key", new AsymmetricKeyEntry(privateKey), new[] { certEntry }); using (var pfxStream = new MemoryStream()) { // 临时密码仅用于内部转换,无对外暴露风险 var tempPwd = Guid.NewGuid().ToString(); store.Save(pfxStream, tempPwd.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom()); pfxStream.Position = 0; return new X509Certificate2( pfxStream.ToArray(), tempPwd, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable ); } } // 加密私钥的密码回调实现 internal class PasswordFinder : IPasswordFinder { private readonly string _password; public PasswordFinder(string password) => _password = password; public char[] GetPassword() => _password.ToCharArray(); }
内容的提问来源于stack exchange,提问作者Luis Masuelli
相关产品推荐
相关产品推荐

