4

I am new to opc ua and not a pro in java. While setting up a client in java I'm having trouble with the certificate dealing. I want to connect to the server via Basic 256, SignAndEncrypt. As I understand, in this stage of security a certificate, created or loaded by the client, is send to the server, where it must be accepted. The server then sends a certificate back to the client, which then needs to be accepted by the client. Please, correct me, if I'm wrong.

Creating/Loading a certificate on the client side and sending it to the server does already work fine (see code below) and I can then accept it on the server side manually. But after that I'm stuck: How can I see this certificate validation in my code and how can I find the server certificate, let alone accept it? I used the SampleConsoleClient of opc ua for some orientation during implementation. But in contrast to there, I do not use any user input.

Here's some of my code so far.

Initialization:

try {
        client = new UaClient(serverUri);
    } catch (final URISyntaxException e) {
        throw new InitializationException("The server uri has an invalid syntax.", e);
    }
    try {
        client.setApplicationIdentity(createApplicationIdentity());
    } catch (final SecureIdentityException e) {
        throw new InitializationException(
                "Application Identity could not be created due to a Security Identity Exception.", e);
    } catch (final IOException e) {
        throw new InitializationException("Application Identity could not be created due to an IO Exception.",
                e);
    }

createApplicationIdentity():

final ApplicationDescription appDescription = new ApplicationDescription();
    appDescription.setApplicationName(new LocalizedText(APPLICATION_NAME, Locale.ENGLISH));
    appDescription.setApplicationUri(APPLICATION_URI);
    appDescription.setProductUri(PRODUCT_URI);
    appDescription.setApplicationType(ApplicationType.Client);

    // Setting security features
    client.setSecurityMode(SecurityMode.BASIC256_SIGN_ENCRYPT);
    client.setCertificateValidator(validator);
    validator.setValidationListener(myValidationListener); //myValidationListener is similar to most lines in MyCertificateValidationListener in the opc ua samples
    final File privatePath = new File(validator.getBaseDir(), "private");
    final KeyPair issuerCertificate = null;
    final int[] keySizes = null;
    final ApplicationIdentity identity = ApplicationIdentity.loadOrCreateCertificate(appDescription,
            "Sample Organisation", "opcua", privatePath, issuerCertificate, keySizes, true);
    identity.setApplicationDescription(appDescription);
    return identity; 

After initializing, I try to connect like this (with annotation, how I imagine the connection could work properly):

final String securityPolicy = client.getEndpoint() == null
            ? client.getSecurityMode().getSecurityPolicy().getPolicyUri()
                    : client.getEndpoint().getSecurityPolicyUri();

            client.setSessionName(String.format("%s@%s/Session%d", APPLICATION_NAME,
                    ApplicationIdentity.getActualHostNameWithoutDomain(), ++sessionCount));
            try {
                //Idea: catch the server certificate and accept it. Only if that was possible: connect
                client.connect();
            } catch (final ServiceException e) {
                e.printStackTrace();
            }
            client.setKeepSubscriptions(false);
            // After that resolving namespace index (works fine)
            }

And the error, that is thrown:

WARN  (?:?): /<IPofServer> Error org.opcfoundation.ua.common.ServiceResultException: Bad_SecurityChecksFailed
(0x80130000) "An error occurred verifying security." at
org.opcfoundation.ua.transport.tcp.io.TcpConnection$ReadThread.run(Unknown Source)
com.prosysopc.ua.client.ConnectException: Failed to create secure channel to server: : opc.tcp://<IPofServer>
[http://opcfoundation.org/UA/SecurityPolicy#Basic256,SignAndEncrypt]
ServiceResult=Bad_SecurityChecksFailed (0x80130000) "An error occurred verifying security."
at com.prosysopc.ua.client.UaClient.n(Unknown Source)
at com.prosysopc.ua.client.UaClient.connect(Unknown Source)
at *lineOfCode*
Caused by: org.opcfoundation.ua.common.ServiceResultException:
Bad_SecurityChecksFailed (0x80130000) "An error occurred verifying security."
at org.opcfoundation.ua.transport.tcp.io.TcpConnection$ReadThread.run(Unknown Source)

With the lineOfCode being client.connect().

Thanks in advance for the help!!

Nanda
  • 51
  • 1
  • 6

3 Answers3

2

The server will send it's certificate to the client. The client then has to

  1. verify the validity of the certificate. This amounts to verifying the signature of the certificate, checking the validity, whether the hostname in the certificate matches the hostname in the endpoint, checking CRLs and so forth. Usually the SDK (the validator) should do this for you, but you might need to feed some parameters into the validator which checks should actually be performed. The security policy Basic256 imposes some minimal requirements on the certificate which the certificate should meet, of course. You can check the requirements here: http://opcfoundation-onlineapplications.org/profilereporting/ -- go to Security Category -> Facets -> Security policy.
  2. check whether the server certificate is trusted. This usually amounts to checking whether a copy of the (puclic key) certificate has been put into some certicate store chosen as a trust store. If you write the client it's up to you to say which store to choose, but you will need to tell the validator where to look. I don't know that much about OPc UA development in Java, but you should check which certificate stores the validator expects. Maybe there is a default keyfile.

(On server side the same happens with the client certificate).

This asssumes you are starting out with self-signed certificates. If you are using certificates signed by a CA both applications (server and client) will need to be able to verify the whole chain of the other party. It can be stored locally in some store or can be send by the other party. At least one certificate in the chain has to be trustest (has to be put into the trust store).

For a general description on how UA security works have a look at this link: https://opcfoundation.org/wp-content/uploads/2014/08/11_OPC_UA_Security_How_It_Works.pdf

For a detailed account you should consult the specification, available at GitHub.

Edit: one addtional remark which may help here: you seem to be using some SDK for the purpose in question. While validation of certificates, i.e. doing the signature checks etc, is usually covered by such an SDK the configuration of the application is the task of the application (programmer). This includes the location where you store trusted certificates and where and how you gather together missing parts of certificate chains. You might first try to check how demo clients and servers deal with this task, in other words check out the configuration tasks for such applications by trying to create a secure connection from, say, UA Expert to the sample servers from the OPC foundation. In the .Net SDK of the OPC foundation the location for the trust store defaults to a certain directory in the file system (a subfolder of C:\ProgramData\OpcFoundation, it's Windows only). You can, however, overwrite this when you initialize the validator. Other clients use their own directory structure for the storage of trusted certificates

Thomas
  • 1,160
  • 3
  • 16
  • 34
  • Thank you for your answer! I do understand that I have to deal with the certificate sent by the server. My question was more _programmatically_, because I'm really blank here: I have set a validator (see code above) and when I check the certificates before and after `client.connect()` via `validator.getRejected / Revoked / TrustedCertificates.length()` I get `0` as an answer for all three kinds of certificates both before and after connecting. Shouldn't there be at least one in the rejected directory? – Nanda Jul 17 '17 at 09:30
  • @Nanda I have more experience with the .Net base case, but I would expect a similar approach in Java. In Opc UA the client has to trust the server (step 2 in my answer). This is usually done by putting the server certificate into some specific location. This location has to be made known to your application, and this is where you need to take action (programatically). You have to figure out how to tell the validator where to search for the (trusted) certificates. If the validator does not supply that kind of properties you need to check the trust yourself somehow, but I don't believe this.One – Thomas Jul 17 '17 at 16:24
  • reason for me to believe this is that the validator has a TrustedCertifcates attribute. I'd expect the application to load the content of some store into this variable at some point in tiem. If you debug how this 'TrustedCertificates' Variable is initialized you should get a hint on how to do this. – Thomas Jul 17 '17 at 16:26
0

You are obviously referring to the Prosys OPC UA Java SDK.

What always happens first, when you try to establish a secure connection for the first time, is that the server will deny access to your client application - and returns Bad_SecurityChecksFailed.

Only, after you have told the server to trust (the certificate of) your client application, will you get to the phase where the client application will try to verify the server's certificate - and your 'validationListener' will be triggered.

Jouni Aro
  • 2,099
  • 14
  • 30
0

Thank you all for your answers. In the meantime, I tried basically copy/paste and modifying the connect() and initalize() methods from the SampleConsoleClient in the Prosys SDK samples And that worked. Guess it had something to do with renewing some information, but I'm not quite sure of that... Fact is, my application is now working, but thanks for your efforts!

Nanda
  • 51
  • 1
  • 6