Skip to content

Commit

Permalink
Support use of opc.https endpoint url for client and server. (#2140)
Browse files Browse the repository at this point in the history
Currently the https protocol doesn't support a spec compliant endpoint with a `opc.https` prefix., as client and server.
Fix:
- Add the client and server support for the `opc.https` prefix. 
- Continue support for `https` prefix for non compliant implementations.
- Any CancellationTokenSource should be disposed after being used.
- Follow coding guidelines
- Use macOS cert callback
  • Loading branch information
mregen committed Jun 12, 2023
1 parent e792e43 commit c7bd19d
Show file tree
Hide file tree
Showing 20 changed files with 283 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ public Protocol(EndpointDescription url)
{
Url = Utils.ParseUri(url.EndpointUrl);

if ((Url != null) && (Url.Scheme == Utils.UriSchemeHttps))
if ((Url != null) && Utils.IsUriHttpsScheme(Url.Scheme))
{
switch (url.TransportProfileUri)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
</TransportQuotas>
<ServerConfiguration>
<BaseAddresses>
<ua:String>https://localhost:62540/Quickstarts/ReferenceServer</ua:String>
<ua:String>opc.https://localhost:62540/Quickstarts/ReferenceServer</ua:String>
<ua:String>opc.tcp://localhost:62541/Quickstarts/ReferenceServer</ua:String>
</BaseAddresses>
<!--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
</TransportQuotas>
<ServerConfiguration>
<BaseAddresses>
<ua:String>https://localhost:62540/Quickstarts/ReferenceServer</ua:String>
<ua:String>opc.https://localhost:62540/Quickstarts/ReferenceServer</ua:String>
<ua:String>opc.tcp://localhost:62541/Quickstarts/ReferenceServer</ua:String>
</BaseAddresses>
<!--
Expand Down
107 changes: 52 additions & 55 deletions Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ X509Certificate2Collection instanceCertificateChain

for (int ii = 0; ii < baseAddresses.Count; ii++)
{
if (!baseAddresses[ii].StartsWith(Utils.UriSchemeHttps, StringComparison.Ordinal))
if (!Utils.IsUriHttpsScheme(baseAddresses[ii]))
{
continue;
}
Expand All @@ -82,77 +82,74 @@ X509Certificate2Collection instanceCertificateChain

uris.Add(uri.Uri);

if (uri.Scheme == Utils.UriSchemeHttps)
// Only support one policy with HTTPS
// So pick the first policy with security mode sign and encrypt
ServerSecurityPolicy bestPolicy = null;
foreach (ServerSecurityPolicy policy in securityPolicies)
{
// Can only support one policy with HTTPS
// So pick the first policy with security mode sign and encrypt
ServerSecurityPolicy bestPolicy = null;
foreach (ServerSecurityPolicy policy in securityPolicies)
if (policy.SecurityMode != MessageSecurityMode.SignAndEncrypt)
{
if (policy.SecurityMode != MessageSecurityMode.SignAndEncrypt)
{
continue;
}

bestPolicy = policy;
break;
continue;
}

// Pick the first policy from the list if no policies with sign and encrypt defined
if (bestPolicy == null)
{
bestPolicy = securityPolicies[0];
}
bestPolicy = policy;
break;
}

EndpointDescription description = new EndpointDescription();
// Pick the first policy from the list if no policies with sign and encrypt defined
if (bestPolicy == null)
{
bestPolicy = securityPolicies[0];
}

description.EndpointUrl = uri.ToString();
description.Server = serverDescription;
EndpointDescription description = new EndpointDescription();

if (instanceCertificate != null)
{
description.ServerCertificate = instanceCertificate.RawData;
// check if complete chain should be sent.
if (configuration.SecurityConfiguration.SendCertificateChain &&
instanceCertificateChain != null &&
instanceCertificateChain.Count > 1)
{
List<byte> serverCertificateChain = new List<byte>();
description.EndpointUrl = uri.ToString();
description.Server = serverDescription;

for (int i = 0; i < instanceCertificateChain.Count; i++)
{
serverCertificateChain.AddRange(instanceCertificateChain[i].RawData);
}
if (instanceCertificate != null)
{
description.ServerCertificate = instanceCertificate.RawData;
// check if complete chain should be sent.
if (configuration.SecurityConfiguration.SendCertificateChain &&
instanceCertificateChain != null &&
instanceCertificateChain.Count > 1)
{
List<byte> serverCertificateChain = new List<byte>();

description.ServerCertificate = serverCertificateChain.ToArray();
for (int i = 0; i < instanceCertificateChain.Count; i++)
{
serverCertificateChain.AddRange(instanceCertificateChain[i].RawData);
}
}

description.SecurityMode = bestPolicy.SecurityMode;
description.SecurityPolicyUri = bestPolicy.SecurityPolicyUri;
description.SecurityLevel = ServerSecurityPolicy.CalculateSecurityLevel(bestPolicy.SecurityMode, bestPolicy.SecurityPolicyUri);
description.UserIdentityTokens = serverBase.GetUserTokenPolicies(configuration, description);
description.TransportProfileUri = Profiles.HttpsBinaryTransport;

ITransportListener listener = Create();
if (listener != null)
{
endpoints.Add(description);
serverBase.CreateServiceHostEndpoint(uri.Uri, endpoints, endpointConfiguration, listener,
configuration.CertificateValidator.GetChannelValidator());
}
else
{
Utils.LogError("Failed to create endpoint {0} because the transport profile is unsupported.", uri);
description.ServerCertificate = serverCertificateChain.ToArray();
}
}

// create the host.
ServiceHost serviceHost = serverBase.CreateServiceHost(serverBase, uris.ToArray());
description.SecurityMode = bestPolicy.SecurityMode;
description.SecurityPolicyUri = bestPolicy.SecurityPolicyUri;
description.SecurityLevel = ServerSecurityPolicy.CalculateSecurityLevel(bestPolicy.SecurityMode, bestPolicy.SecurityPolicyUri);
description.UserIdentityTokens = serverBase.GetUserTokenPolicies(configuration, description);
description.TransportProfileUri = Profiles.HttpsBinaryTransport;

hosts[hostName] = serviceHost;
ITransportListener listener = Create();
if (listener != null)
{
endpoints.Add(description);
serverBase.CreateServiceHostEndpoint(uri.Uri, endpoints, endpointConfiguration, listener,
configuration.CertificateValidator.GetChannelValidator());
}
else
{
Utils.LogError("Failed to create endpoint {0} because the transport profile is unsupported.", uri);
}
}

// create the host.
ServiceHost serviceHost = serverBase.CreateServiceHost(serverBase, uris.ToArray());

hosts[hostName] = serviceHost;

return endpoints;
}
}
Expand Down

0 comments on commit c7bd19d

Please sign in to comment.