You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建OPC UA会话时遭遇‘Certificate Not Trusted’错误求助

OPC UA客户端连接时出现“Certificate Not Trusted”错误的排查解决

我是OPC UA协议新手,正在对接客户的OPC UA服务器。用C#开发客户端,通过OpenSSL生成客户端证书并交给客户放入信任证书文件夹,但每次尝试连接时,会话创建后都会触发Certificate Not Trusted错误,更换多个证书仍未解决问题。

客户端代码

using System;
using System.Security.Cryptography.X509Certificates;
using Opc.Ua;
using Opc.Ua.Client;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    private async Task<object> ReadVariableAsync(Session session, NodeId nodeId, CancellationToken cancellationToken = default)
    {
        ReadValueId readValueId = new ReadValueId { NodeId = nodeId, AttributeId = Attributes.Value };

        ReadResponse readResponse = await session.ReadAsync(
            null,
            0,
            TimestampsToReturn.Both,
            new[] { readValueId },
            cancellationToken
        );

        if (readResponse != null && readResponse.Results != null && readResponse.Results.Count > 0 && StatusCode.IsGood(readResponse.Results[0].StatusCode))
        {
            Console.WriteLine($"Value of MyVariable: {readResponse.Results[0].Value}");
            return readResponse.Results[0].Value;
        }
        else
        {
            Console.WriteLine("Failed to read the variable value.");
            return false;
        }
    }

    private async Task<bool> WriteVariableAsync(Session session, NodeId nodeId, object value, CancellationToken cancellationToken = default)
    {
        try
        {
            WriteValue writeValue = new WriteValue
            {
                NodeId = nodeId,
                AttributeId = Attributes.Value,
                Value = new DataValue(new Variant(value)),
            };

            WriteValueCollection writeValues = new WriteValueCollection
            {
                writeValue
            };

            WriteResponse writeResponse = await session.WriteAsync(
                null,
                writeValues,
                cancellationToken
            );

            if (writeResponse != null && writeResponse.Results != null && writeResponse.Results.Count > 0
                && StatusCode.IsGood(writeResponse.Results[0]))
            {
                Console.WriteLine("Write operation successful.");
                return true;
            }
            else
            {
                Console.WriteLine("Failed to write to the variable.");
                return false;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error during write operation: {ex.Message}");
            return false;
        }
    }

    static async Task Main()
    {
        string endpointUrl = "opc.tcp://xx.xx.xx";
        string username = "xxxx";
        string password = "xxxx";
        UserIdentity userIdentity = new UserIdentity(username, password);

        X509Certificate2 certificate = new X509Certificate2(@"C:\xxxx\xxxx.der");

        ApplicationConfiguration config = new ApplicationConfiguration
        {
            ClientConfiguration = new ClientConfiguration
            {
                DefaultSessionTimeout = 60000,
            },
            SecurityConfiguration = new SecurityConfiguration
            {
                ApplicationCertificate = new CertificateIdentifier 
                {   
                    Certificate = certificate,
                },
                AutoAcceptUntrustedCertificates = true,
                RejectSHA1SignedCertificates = true,
            },
        };

        using (var session = await Session.Create(config, new ConfiguredEndpoint(null, new EndpointDescription(endpointUrl)), true, "", 60000, userIdentity, null))
        {
            Program program = new Program();
            NodeId nodeId = NodeId.Parse("ns=4;s=xx.xxx.xx .Application.Rx_from_Client.Order");
            var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken = cancellationTokenSource.Token;
            object value = await program.ReadVariableAsync(session, nodeId, cancellationToken);
        }
    }
}

OpenSSL证书生成命令

openssl genpkey -algorithm RSA -out client_key.pem
openssl req -new -key client_key.pem -out client_csr.pem
openssl x509 -req -in client_csr.pem -signkey client_key.pem -out client_cert.pem
openssl x509 -req -in client_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out client_cert.pem
openssl x509 -in client_cert.pem -outform der -out client_cert.der

排查解决要点

  1. 证书加载完整性问题
    你当前加载的.der格式证书仅包含公钥,OPC UA客户端需要同时持有公钥和私钥才能完成双向认证。建议用OpenSSL将PEM格式证书和密钥合并为包含私钥的.pfx文件:

    openssl pkcs12 -export -in client_cert.pem -inkey client_key.pem -out client_cert.pfx
    

    然后在代码中加载该文件(需提供导出时设置的密码):

    X509Certificate2 certificate = new X509Certificate2(@"C:\xxxx\client_cert.pfx", "你的导出密码");
    
  2. 证书生成流程问题
    你的命令中第二次openssl x509 -req(CA签名)会覆盖第一次自签名的证书,确认客户信任的是CA签名后的最终证书。同时检查客户是否已将CA证书导入到服务器的信任根证书库中。

  3. OPC UA配置补充
    现有配置缺少应用标识和证书验证回调,补充以下内容:

    config.ApplicationName = "你的客户端应用名称";
    config.ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:你的客户端应用名称";
    // 测试环境临时跳过服务器证书验证,生产环境需严格校验
    config.CertificateValidator.CertificateValidation += (sender, e) =>
    {
        e.Accept = true;
    };
    

    注意:AutoAcceptUntrustedCertificates仅控制客户端是否接受服务器的未信任证书,不影响服务器对客户端证书的验证,无法解决当前问题。

  4. 服务器端信任配置验证
    确认客户已将你的客户端证书放入服务器的信任客户端证书目录(部分服务器会区分根证书和客户端证书文件夹),同时检查服务器是否启用了客户端证书强制验证,以及证书的有效期、主体名称是否符合服务器要求。

内容的提问来源于stack exchange,提问作者Jacopo SDG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:30:53