Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not authenticate using SecurityPolicy Basic256 #13

Closed
Ttberg opened this issue Apr 17, 2020 · 11 comments
Closed

Can not authenticate using SecurityPolicy Basic256 #13

Ttberg opened this issue Apr 17, 2020 · 11 comments

Comments

@Ttberg
Copy link
Contributor

Ttberg commented Apr 17, 2020

I was unable to authenticate using the SecurityPolicy Basic256 and the reference server of the OPC foundation.

I was able to open a secure channel and creating a session using:
m_client.OpenSecureChannel(MessageSecurityMode.SignAndEncrypt, SecurityPolicy.Basic256, serverCert);
m_client.CreateSession(appDesc, "urn:Application", 2);

But activating the session using:
m_client.ActivateSession( new UserIdentityUsernameToken(usernamePolicyDesc, "Name", (new UTF8Encoding()).GetBytes("password"), "http://www.w3.org/2001/04/xmlenc#rsa-oaep"), new[] { "en" });

did not work.

After looking at the code to activate the session, shouldn't the actual SecurityPolicy (which is available in the config member) be used when calculating the padding size and when encrypting the password instead of the hard coded Basic128Rsa15 SecurityPolicy?

@nauful
Copy link
Owner

nauful commented Apr 18, 2020

Security for session activation (secrets exchange) was fixed to Basic128Rsa15 according to the spec when implemented ~2015, but I'll take a look and see what the current behaviour is now.

@nauful
Copy link
Owner

nauful commented Apr 18, 2020

image

18-Apr-20 13:25:23.430 ***EXCEPTION*** BadSecurityPolicyRejected 'The security policy is not supported.' The security policy is not supported.
18-Apr-20 13:25:23.446 TCPSERVERCHANNEL ForceChannelFault Socket=000AF38C, ChannelId=0, TokenId=0, Reason=Id: BadSecurityPolicyRejected
Description: Could not verify security on OpenSecureChannel request.
===
Id: BadSecurityPolicyRejected
Description: The security policy is not supported.
>>> The security policy is not supported.
---    at Opc.Ua.Bindings.UaSCUaBinaryChannel.ReadAsymmetricMessage(ArraySegment`1 buffer, X509Certificate2 receiverCertificate, UInt32& channelId, X509Certificate2& senderCertificate, UInt32& requestId, UInt32& sequenceNumber)
---    at Opc.Ua.Bindings.TcpServerChannel.ProcessOpenSecureChannelRequest(UInt32 messageType, ArraySegment`1 messageChunk)
18-Apr-20 13:25:23.452 Channel 16: SendErrorMessage()
18-Apr-20 13:25:23.458 Channel 16 in Faulted state.

The latest OPC Foundation reference server doesn't seem to expose Basic256 as a security policy for its endpoint. I've tested an older version which did and it works. Although the latest OPC Foundation policy may have changed, the previous behaviour was for any security policy other than None, Basic128Rsa15 is used to exchange the secret key used for further encryption according to the selected policy.

Could you please share the client code that you are using until the line that fails, and a zipped version of source for the UA server so I can investigate the point at which it rejects the request?

@nauful
Copy link
Owner

nauful commented Apr 18, 2020

For reference, to connect as Basic256:
Check that you have this policy (not sure if it works with the latest reference server sample):

<ServerSecurityPolicy>
    <SecurityMode>SignAndEncrypt_3</SecurityMode>
    <SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri>
</ServerSecurityPolicy>

image

The following code allows me to connect:

var appDesc = new ApplicationDescription(
  "urn:qs:DemoClient", "uri:qs:DemoClient", new LocalizedText("UA SDK client"),
  ApplicationType.Client, null, null, null);

ApplicationDescription[] appDescs = null;
EndpointDescription[] endpointDescs = null;

var client = new DemoClient("127.0.0.1", 51210, 1000);
client.Connect();
client.OpenSecureChannel(MessageSecurityMode.None, SecurityPolicy.None, null);
client.FindServers(out appDescs, new[] { "en" });
client.GetEndpoints(out endpointDescs, new[] { "en" });
client.Disconnect();

// Check matching message security mode and security policy too
// Lazy way to find server certificate is just grab any endpoint with one
byte[] serverCert = endpointDescs
  .First(e => e.ServerCertificate != null && e.ServerCertificate.Length > 0)
  .ServerCertificate;

var usernamePolicyDesc = endpointDescs
  .First(e => e.UserIdentityTokens.Any(t => t.TokenType == UserTokenType.UserName))
  .UserIdentityTokens.First(t => t.TokenType == UserTokenType.UserName)
  .PolicyId;

client = new DemoClient("127.0.0.1", 51210, 1000);
var connectRes = client.Connect();
var openRes = client.OpenSecureChannel(MessageSecurityMode.SignAndEncrypt, SecurityPolicy.Basic256, serverCert);
var createRes = client.CreateSession(appDesc, "urn:qs:DemoClient", 120);
var activateRes = client.ActivateSession(new UserIdentityAnonymousToken("0"), new[] { "en" });

/// All good from here
...

@Ttberg
Copy link
Contributor Author

Ttberg commented Apr 20, 2020

image

18-Apr-20 13:25:23.430 ***EXCEPTION*** BadSecurityPolicyRejected 'The security policy is not supported.' The security policy is not supported.
18-Apr-20 13:25:23.446 TCPSERVERCHANNEL ForceChannelFault Socket=000AF38C, ChannelId=0, TokenId=0, Reason=Id: BadSecurityPolicyRejected
Description: Could not verify security on OpenSecureChannel request.
===
Id: BadSecurityPolicyRejected
Description: The security policy is not supported.
>>> The security policy is not supported.
---    at Opc.Ua.Bindings.UaSCUaBinaryChannel.ReadAsymmetricMessage(ArraySegment`1 buffer, X509Certificate2 receiverCertificate, UInt32& channelId, X509Certificate2& senderCertificate, UInt32& requestId, UInt32& sequenceNumber)
---    at Opc.Ua.Bindings.TcpServerChannel.ProcessOpenSecureChannelRequest(UInt32 messageType, ArraySegment`1 messageChunk)
18-Apr-20 13:25:23.452 Channel 16: SendErrorMessage()
18-Apr-20 13:25:23.458 Channel 16 in Faulted state.

The latest OPC Foundation reference server doesn't seem to expose Basic256 as a security policy for its endpoint. I've tested an older version which did and it works. Although the latest OPC Foundation policy may have changed, the previous behaviour was for any security policy other than None, Basic128Rsa15 is used to exchange the secret key used for further encryption according to the selected policy.

Could you please share the client code that you are using until the line that fails, and a zipped version of source for the UA server so I can investigate the point at which it rejects the request?

For the server I just take the latest server code from the OPC Foundation, but I added

<ServerSecurityPolicy> <SecurityMode>SignAndEncrypt_3</SecurityMode> <SecurityPolicyUri>http://opcfoundation.org/UA/SecurityPolicy#Basic256</SecurityPolicyUri> </ServerSecurityPolicy>

to the server config to enable the Basic256 security policy.

This is part of the client code I'm using:
StatusCode s = m_client.Connect(); Log($"Connecting..."); if (s == StatusCode.Good) { Log($"Connected"); } else { Log($"Not connected: {s}"); } Log($"opening non secure channel"); StatusCode s2 = m_client.OpenSecureChannel(MessageSecurityMode.None, SecurityPolicy.None, null); Log($"result: {s2}"); //get all the different endpoints Log($"getting endpoints"); s2 = m_client.GetEndpoints(out m_endpointDescs, new[] { "en" }); Log($"result: {s2}"); foreach (EndpointDescription ed in m_endpointDescs) { Log($"Endpoint: {ed.EndpointUrl}, {ed.SecurityLevel}, {ed.SecurityMode}, {ed.SecurityPolicyUri}"); } Log($"disconnecting"); s2 = m_client.Disconnect(); Log($"result: {s2}"); ApplicationDescription appDesc = new ApplicationDescription("urn:OPCUAAdapter", "uri:OPCUAAdapter", new LocalizedText("OPC-UA Adapter"), ApplicationType.Client, null, null, null); // as long as there's 1 server, just use any of the server certificates byte[] serverCert = m_endpointDescs .First(e => e.ServerCertificate != null && e.ServerCertificate.Length > 0) .ServerCertificate; //connect to the client again StatusCode s3 = m_client.Connect(); Log($"result: {s3}"); if (s3 == StatusCode.Good) { Log("opening secure channel"); try { s3 = m_client.OpenSecureChannel(MessageSecurityMode.SignAndEncrypt, SecurityPolicy.Basic256, serverCert); Log("creating session"); var createRes = m_client.CreateSession(appDesc, "urn:OPCUAAdapter", 2); Log($"create session result: {createRes}"); //var activateRes = m_client.ActivateSession(new UserIdentityAnonymousToken("0"), new[] { "en" }); var usernamePolicyDesc = m_endpointDescs .First(e => e.UserIdentityTokens.Any(t => t.TokenType == UserTokenType.UserName)) .UserIdentityTokens.First(t => t.TokenType == UserTokenType.UserName && t.SecurityPolicyUri.Equals("http://opcfoundation.org/UA/SecurityPolicy#Basic256")) .PolicyId; var activateRes2 = m_client.ActivateSession( new UserIdentityUsernameToken(usernamePolicyDesc, "a username", (new UTF8Encoding()).GetBytes("a password"), "http://www.w3.org/2001/04/xmlenc#rsa-oaep"), new[] { "en" }); Log($"Activate session result: {activateRes2}"); CurrentState = State.ObtainNamespaces; } catch (Exception ex) { Log($"{ex}"); } }

Where activeRes2 equals BadUnkownResponse with the existing libua. When changing the libua code into using Basic256 as the security policy in the activate session method, the response equals Good and everything works OK

@nauful
Copy link
Owner

nauful commented Apr 20, 2020

The code I pasted here works for me after adding that security configuration XML to the latest OPC Foundation reference server: #13 (comment)

Please confirm that it works for you, or let me know modification made it to work for you and I can merge it in.

@Ttberg
Copy link
Contributor Author

Ttberg commented Apr 21, 2020

Your code worked for me as well. However, you are using the UserIdentityAnonymousToken, while I'm trying to authenticate using the UserIdentityUsernameToken. The OPC reference server accepts every user as long as the password is not IsNullOrEmpty, so it doesn't really matter what you use to authenticate.

The modification I made to let this work is a change the ActivateSession method of client.cs. I've replaced all occurrences (2) of "SecurityPolicy.Basic128Rsa15" with "config.SecurityPolicy". This works when I'm using the Basic256 security policy, but I'm not sure this will work with e.g. the Basic256sha256 security policy.

@nauful
Copy link
Owner

nauful commented Apr 21, 2020

I'm not sure that this is intended behaviour because according to the specification, security policy defines the transport layer security, not for encrypting an identity token. I'll verify compatibility again and commit a change if there's an issue.

By the way, I have started adding Basic256Sha256 as a security mode. The current source now fully supports this on the server side.

@nauful nauful closed this as completed Apr 21, 2020
@Ttberg
Copy link
Contributor Author

Ttberg commented Apr 22, 2020

Yes I've seen you've added Basic256Sha256 as a security mode. I'm trying it now, but I'm once again unable to connect to the reference server of the OPC foundation. It's complaining about the CertificateThumbprintSize length which should be 20 but is 32. I'm looking into it right now.

By the way, have you tried using your code from 3 days ago to connect to the reference server and change the activate session argument into using a user identity token instead of the anonymous token?

@nauful
Copy link
Owner

nauful commented Apr 22, 2020

The reference server seemed to accept and ignore it, although I didn't expect that the SecurityPolicy would affect anything above the transport layer.

If CertificateThumbprintSize length is wrong, try using Basic128Rsa15, or if not, Basic256Sha256
here:
var thumbprint = UASecurity.RsaPkcs15Sha_Sign(new ArraySegment(signMsg),
ApplicationPrivateKey, config.SecurityPolicy);

Let me know what works there.

Different UA servers seem to have different policies and don't all work with the OPC Foundation client/servers, so I've added an optional parameter userIdentitySecurityPolicy to Client.ActivateSession.

@nauful nauful reopened this Apr 22, 2020
@Ttberg
Copy link
Contributor Author

Ttberg commented Apr 23, 2020

When trying to get Basic256Sha256 to work in my own code, I still had some changes left from trying to get the authentication to work when using SecurityPolicy Basic256. They conflicted which each other, which resulted in both not working. I went back to using your master branch and both now work fine. Basic256Sha256 is working and I'm able to authenticate.

However, I went back to try and use the version of April 19th, and the authentication did not work with that version when using Basic256 as a SecurityPolicy. Somehow after adding the Basic256Sha256 SecurityPolicy the authentication now works for both security policies.

I think this issue can now be closed. Thanks for the help.

@nauful
Copy link
Owner

nauful commented Apr 23, 2020

Was probably a bug I fixed while cleaning up the security code. Sometimes the UA specification can get confusing between whether to use the security policy for symmetric wrapping or Basic128Rsa15 as the asymmetric wrapping policy in places.

Glad it works for you now.

@nauful nauful closed this as completed Apr 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants