如何让OPC UA .NET客户端通过Find()加载OpenSSL生成的证书?
我基于.NET使用OPC UA Client SDK开发了OPC客户端,通过SDK自带的CertificateFactory.CreateCertificate()方法生成的证书可以正常通过Find()方法加载,但用OpenSSL生成的配置一致的证书(已删除SDK生成的证书)却无法被找到——即使证书的SubjectName与XML配置匹配,尝试通过指纹查找也失败。
相关代码
生成证书的代码:
// Get local interface ip addresses and DNS name List<string> localIps = GetLocalIpAddressAndDns(); UInt16 keySize = 2048; //must be multiples of 1024 DateTime startTime = DateTime.Now; string certPassword = "123"; UInt16 lifeTime = 24; UInt16 hashSize = 2048; //Make ApplicationCertificate from xml settings config.SecurityConfiguration.ApplicationCertificate = new(CertificateFactory.CreateCertificate( config.SecurityConfiguration.ApplicationCertificate.StoreType, config.SecurityConfiguration.ApplicationCertificate.StorePath, certPassword, config.ApplicationUri, config.ApplicationName, config.SecurityConfiguration.ApplicationCertificate.SubjectName, localIps, keySize, startTime, lifeTime, hashSize ));
加载证书的代码:
config.SecurityConfiguration.ApplicationCertificate.LoadPrivateKey("123").Wait(); config.SecurityConfiguration.ApplicationCertificate = new(config.SecurityConfiguration.ApplicationCertificate.Find(true).Result);
XML配置片段:
<ApplicationName>opcpublisher</ApplicationName> <ApplicationUri>urn:desktop-q2t5j2p:Microsoft.Azure.IIoT:microsoft</ApplicationUri> <ProductUri>urn:SIMATIC.S7-1200.OPC-UA.Application:StratusPLC</ProductUri> <ApplicationType>Client_1</ApplicationType> <SecurityConfiguration> <ApplicationCertificate> <StoreType>Directory</StoreType> <StorePath>%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault</StorePath> <SubjectName>CN=opcpublisher, O=mycompany</SubjectName> </ApplicationCertificate>
1. 匹配OPC UA证书存储的命名规则
OPC UA的Directory类型证书存储对文件命名有严格要求:
- 证书文件(.cer)必须以**证书的十六进制指纹(大写、无冒号分隔符)**命名
- 私钥文件(如.pfx)需与证书文件同名,放在同一目录
用OpenSSL获取证书指纹并重命名文件:
# 提取证书指纹(自动去除冒号并转为大写) openssl x509 -in your-cert.cer -noout -fingerprint | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | tr '[:lower:]' '[:upper:]'
将你的.cer文件重命名为上述命令输出的指纹值,再放入配置指定的MachineDefault目录。
2. 强制添加OPC UA必备的X.509扩展
SDK生成的证书会自动嵌入ApplicationUri作为X.509扩展,这是Find()方法识别证书的核心校验项之一,OpenSSL生成的证书默认没有这个字段,必须手动添加:
创建一个opcua-ext.cnf配置文件:
[req] distinguished_name = req_distinguished_name x509_extensions = v3_ext [req_distinguished_name] CN = opcpublisher O = mycompany [v3_ext] # 必须匹配XML中的ApplicationUri,同时添加本地IP和主机名作为SAN subjectAltName = URI:urn:desktop-q2t5j2p:Microsoft.Azure.IIoT:microsoft, IP:你的本地IP地址, DNS:你的主机名
用该配置重新生成证书:
openssl req -x509 -newkey rsa:2048 -keyout your-key.pem -out your-cert.cer -days 8760 -passout pass:123 -config opcua-ext.cnf
3. 转换私钥为SDK兼容的PFX格式
SDK的LoadPrivateKey()方法仅支持PFX格式的私钥文件(需包含证书与私钥),如果OpenSSL生成的是PEM格式私钥,需要转换:
openssl pkcs12 -export -out your-cert.pfx -inkey your-key.pem -in your-cert.cer -passout pass:123
将生成的PFX文件放入证书存储目录,确保密码与代码中的123一致。
4. 校验证书哈希算法与有效期
检查OpenSSL生成的证书是否与SDK生成的参数匹配:
- 哈希算法需为SHA-1(对应代码中
hashSize=2048) - 有效期需为24个月(8760天)
用以下命令校验:
# 查看签名算法 openssl x509 -in your-cert.cer -noout -text | grep "Signature Algorithm" # 查看有效期 openssl x509 -in your-cert.cer -noout -dates
如果算法不符,生成时需指定-sha1参数:
openssl req -x509 -newkey rsa:2048 -keyout your-key.pem -out your-cert.cer -days 8760 -passout pass:123 -config opcua-ext.cnf -sha1
5. 手动指定指纹查找做测试
如果上述步骤完成后仍无法自动查找,可尝试手动指定指纹调用Find(),确认是否为查找逻辑问题:
// 替换为你的证书指纹(大写无分隔符) var targetThumbprint = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; var foundCert = config.SecurityConfiguration.ApplicationCertificate.FindByThumbprint(targetThumbprint).Result; if (foundCert != null) { config.SecurityConfiguration.ApplicationCertificate = new(foundCert); }
OpenSSL生成的证书无法被SDK识别,大多是因为缺少OPC UA特定的X.509扩展、文件命名不符合规范,或者私钥格式不兼容。按照上述步骤逐一修正后,即可正常通过Find()方法加载证书。
内容的提问来源于stack exchange,提问作者Victor Pieper

