Unity加载X509证书遇FormatException:仅整数可转换问题求助
问题场景
尝试加载X509证书以调用以下方法:
sslStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired: false, checkCertificateRevocation: true);
加载证书的代码:
serverCertificate = new X509Certificate("c:/my/path/server_pfx.pfx");
执行时抛出FormatException: Only integer can be converted,完整错误栈:
FormatException: Only integer can be converted
Mono.Security.ASN1Convert.ToInt32 (Mono.Security.ASN1 asn1) (at <193c77b884c54aa38915aba0dcad62fa>:0)
Mono.Security.X509.PKCS12.Decrypt (Mono.Security.PKCS7+EncryptedData ed) (at <193c77b884c54aa38915aba0dcad62fa>:0)
Mono.Security.X509.PKCS12.Decode (System.Byte[] data) (at <193c77b884c54aa38915aba0dcad62fa>:0)
Mono.Security.X509.PKCS12..ctor (System.Byte[] data, System.String password) (at <193c77b884c54aa38915aba0dcad62fa>:0)
System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.ImportPkcs12 (System.Byte[] rawData, System.String password) (at :0)
System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono.ImportPkcs12 (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password) (at :0)
System.Security.Cryptography.X509Certificates.X509Certificate2ImplMono..ctor (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) (at :0)
Mono.X509PalImpl.ImportFallback (System.Byte[] data, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) (at :0)
Mono.X509PalImplMono.Import (System.Byte[] data, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) (at :0)
Mono.SystemCertificateProvider.Import (System.Byte[] data, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, Mono.CertificateImportFlags importFlags) (at :0)
Mono.SystemCertificateProvider.Mono.ISystemCertificateProvider.Import (System.Byte[] data, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, Mono.CertificateImportFlags importFlags) (at :0)
System.Security.Cryptography.X509Certificates.X509Helper.Import (System.Byte[] rawData, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) (at :0)
System.Security.Cryptography.X509Certificates.X509Certificate..ctor (System.String fileName, System.String password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags) (at :0)
System.Security.Cryptography.X509Certificates.X509Certificate..ctor (System.String fileName) (at :0)
Server.Start () (at Assets/Scripts/Server.cs:32)
证书通过以下OpenSSL命令生成:
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -sha256 -keyout key.pem -out cert.pem openssl pkcs12 -export -in cert.pem -inkey key.pem -out server_pfx.pfx -macalg sha1
补充:相同代码在.NET应用中正常运行,仅Unity环境下出现此问题,推测是Unity的Mono实现无法正常加载带私钥的证书。
问题原因及解决方法
1. 证书生成兼容性问题
你使用的openssl pkcs12命令指定了-macalg sha1,而Unity的Mono版本对PKCS12的SHA1消息认证算法兼容性不佳,建议改用SHA256作为MAC算法。
2. 修正后的证书生成命令
# 生成证书和密钥 openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -sha256 -keyout key.pem -out cert.pem # 生成PKCS12证书,使用SHA256作为MAC算法 openssl pkcs12 -export -in cert.pem -inkey key.pem -out server_pfx.pfx -macalg sha256
3. 证书加载代码优化
在Unity中,建议使用X509Certificate2而非X509Certificate来加载带私钥的证书,同时指定合适的X509KeyStorageFlags避免权限问题:
// 如果证书没有设置密码,password传入null或空字符串 var serverCertificate = new X509Certificate2("c:/my/path/server_pfx.pfx", "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
4. 替代加载方案
如果上述方法仍不生效,可以尝试通过读取文件字节流的方式加载:
byte[] certData = File.ReadAllBytes("c:/my/path/server_pfx.pfx"); var serverCertificate = new X509Certificate2(certData, "", X509KeyStorageFlags.MachineKeySet);
内容的提问来源于stack exchange,提问作者aarelovich

