OPCFoundation / UA-.NETStandard

OPC Unified Architecture .NET Standard
Other
1.97k stars 950 forks source link

OPCUA client should check the application URI of the server certifiate #2032

Open GregoireG-C opened 1 year ago

GregoireG-C commented 1 year ago

Type of issue

Current Behavior

The OPCUA client verify the following points concerning the server certificate:

But the client does not check the ApplicationUri of the server presented in its application certificate.

Expected Behavior

Th client should verify the applicationUri of the server certificate.

Steps To Reproduce

1.Compile sample client and standard UA server

  1. Connect using sign or sign&encrypt to the server ; the server using a certificate presenting an applicationUri null or different form the one present into its configuration file
  2. The client accept the connection.

Environment

- OS:Windows 10
- Environment: Visual Studio 2019
- Runtime:NET 4.6.2
- Server: Reference server
- Client: Reference client

Anything else?

No response

GregoireG-C commented 1 year ago

According to the standard part 4 - Service Release: §5.4.1 Discovery Service Set:

[...] A Client shall be careful when using the information returned from a DiscoveryEndpoint since it has no security. A Client does this by comparing the information returned from the DiscoveryEndpoint to the information returned in the CreateSession response. A Client shall verify that: a) The ApplicationUri specified in the Server Certificate is the same as the ApplicationUri provided in the EndpointDescription. [...]

=> This suggest that the client must verify that the applicationUri presented in the endpoint descriptions and in the server certificate in the GetEndpointResponse match.

GregoireG-C commented 1 year ago

I suggest the following modification: Opc.Ua.Client.Session public method open:

if (checkDomain)
{
    m_configuration.CertificateValidator.Validate(serverCertificateChain, m_endpoint);
    //Modification - Begin
    // verify if applicationUri from ApplicationDescription matches the applicationUri in the client certificate.
    string certificateApplicationUri = X509Utils.GetApplicationUriFromCertificate(serverCertificate);
    if (!String.IsNullOrEmpty(certificateApplicationUri) &&
        !String.IsNullOrEmpty(m_endpoint.Description.Server.ApplicationUri))
    {

        if (certificateApplicationUri != m_endpoint.Description.Server.ApplicationUri)
            throw new Exception(
                string.Format("Server certificate is refused. The applicationUri does not match:" +
                "-Certificate applicationUri='{0}', -EndpointDescription applicationUri='{1}'",
                certificateApplicationUri, m_endpoint.Description.Server.ApplicationUri));
        else
            throw new Exception(
                string.Format("Server certificate is refused. Server certificate is refused, the applicationUri " +
                "in the certificate or in the endpoint description is null."));
    }
    //Modification - End
}
else
{
    m_configuration.CertificateValidator.Validate(serverCertificateChain);
}
mregen commented 7 months ago

The application Uri should always be checked against the information in the endpoint.

mregen commented 7 months ago

Hi @GregoireG-C, is this topic no more an issue? We were planning to include your fix in the next release, please share if it is not necessary.

GregoireG-C commented 7 months ago

It's still an issue. I closed it because you have added this one to a milestone. So I have not any reason to follow it. I will let you close it then.

Best regards

ykarpeev commented 5 months ago

Hello, is there a recommended way to bypass this functionality other than modifying the code on my end as I am doing now?

My use is case is that I often develop against opc-ua servers that are on internal LANs - so I setup a computer on that LAN and then use netsh to port proxy over. It looks like this causes the certificateApplicationUri to not match the applicationUri.

I think it is because GetApplicationUriFromCertificate return's the URI of the PC that I am using as the proxy.

I also want to be able to connect to servers even if they have invalid certificates in the future.

romanett commented 5 months ago

Hi, my recommendation would be to use the "Security: None" endpoint as all the other endpoints need to follow the spec

ykarpeev commented 5 months ago

Thank you. That works great here. Below is what I added.

            EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(this.configuration, serverUrl, true);

            endpointDescription.SecurityPolicyUri = SecurityPolicies.None;
            endpointDescription.SecurityMode = MessageSecurityMode.None;
mregen commented 2 months ago

at this time the check has been removed to work around IOP issues. WIP #2731