-
Notifications
You must be signed in to change notification settings - Fork 476
Description
I'm using eclipse milo version 0.3.6
And OPC UA Server is KEPServerEX6
This is the KEPServerEX6 Configuration.

And This is the OPC UA Client Code.
** KeyStoreLoader.java
`/*
- Copyright (c) 2016 Kevin Herron
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License v1.0
- and Eclipse Distribution License v1.0 which accompany this distribution.
- The Eclipse Public License is available at
- http://www.eclipse.org/legal/epl-v10.html
- and the Eclipse Distribution License is available at
- http://www.eclipse.org/org/documents/edl-v10.html.
*/
package com.sit.stdplf.aqst.agent.opcua01.milo.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.regex.Pattern;
import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateBuilder;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sit.stdplf.aqst.agent.opcua01.common.config.Props;
import com.sit.stdplf.aqst.agent.opcua01.common.constant.Consts;
public class KeyStoreLoader
{
private static Logger LOGGER = LoggerFactory.getLogger ( Consts.LOGGER_NAME );
private static final String CLIENT_ALIAS = "client-ai";
private static final char [] PASSWORD = "password".toCharArray ();
private X509Certificate clientCertificate;
private KeyPair clientKeyPair;
private static final Pattern IP_ADDR_PATTERN = Pattern.compile (
"^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$" );
private final String agentId = Props.AGENT_ID;
public KeyStoreLoader load ( final File baseDir ) throws Exception
{
final KeyStore keyStore = KeyStore.getInstance ( "PKCS12" );
final File serverKeyStore = baseDir.toPath ().resolve ( "example-client.pfx" ).toFile ();
LOGGER.info ( "Loading KeyStore at {}", serverKeyStore );
if ( !serverKeyStore.exists () )
{
keyStore.load ( null, PASSWORD );
final KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair ( 2048 );
final SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder ( keyPair )
.setCommonName ( "InterSysLink_Client["+this.agentId+"]" )
.setOrganization ( "hanwhaconvergence" )
.setCountryCode ( "KO" )
.setApplicationUri ( "urn:hwcv:agent:opcua:client")
.addDnsName ( "localhost" )
.addIpAddress ( "127.0.0.1" )
;
// Get as many hostnames and IP addresses as we can listed in the certificate.
for ( final String hostname : HostnameUtil.getHostnames ( "0.0.0.0" ) )
{
if ( IP_ADDR_PATTERN.matcher ( hostname ).matches () )
{
builder.addIpAddress ( hostname );
} else
{
builder.addDnsName ( hostname );
}
}
final X509Certificate certificate = builder.build ();
keyStore.setKeyEntry ( CLIENT_ALIAS, keyPair.getPrivate (), PASSWORD, new X509Certificate [] { certificate } );
keyStore.store ( new FileOutputStream ( serverKeyStore ), PASSWORD );
} else
{
keyStore.load ( new FileInputStream ( serverKeyStore ), PASSWORD );
}
final Key serverPrivateKey = keyStore.getKey ( CLIENT_ALIAS, PASSWORD );
if ( serverPrivateKey instanceof PrivateKey )
{
this.clientCertificate = ( X509Certificate ) keyStore.getCertificate ( CLIENT_ALIAS );
final PublicKey serverPublicKey = this.clientCertificate.getPublicKey ();
this.clientKeyPair = new KeyPair ( serverPublicKey, ( PrivateKey ) serverPrivateKey );
}
return this;
}
public X509Certificate getClientCertificate ()
{
return this.clientCertificate;
}
public KeyPair getClientKeyPair ()
{
return this.clientKeyPair;
}
}
`
** OPCClient.java
`package com.sit.stdplf.aqst.agent.opcua01.milo;
import java.io.File;
import java.net.URI;
import java.util.List;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
import org.eclipse.milo.opcua.stack.client.DiscoveryClient;
import org.eclipse.milo.opcua.stack.core.channel.MessageLimits;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sit.stdplf.aqst.agent.opcua01.common.config.Props;
import com.sit.stdplf.aqst.agent.opcua01.common.constant.Consts;
import com.sit.stdplf.aqst.agent.opcua01.common.constant.ErrCds;
import com.sit.stdplf.aqst.agent.opcua01.common.message.LangMessage;
import com.sit.stdplf.aqst.agent.opcua01.milo.util.KeyStoreLoader;
import com.sit.stdplf.base.common.config.BaseProps;
import com.sit.stdplf.base.common.constant.BaseConsts;
import com.sit.stdplf.base.logmgt.exception.SPExceptionHandler;
import com.sit.stdplf.base.logmgt.exception.network.SPNetworkException;
import com.sit.stdplf.commons.util.LogMsgUtil;
public class OPCClient
{
private static final Logger LOGGER = LoggerFactory.getLogger ( Consts.LOGGER_NAME );
private final KeyStoreLoader loader = new KeyStoreLoader ();
public OpcUaClient opcUAClient;
public static final int DEFAULT_MAX_MESSAGE_SIZE = 4 * 1024 * 1024;
/**
* The default maximum size of a single chunk.
*/
public static final int DEFAULT_MAX_CHUNK_SIZE = 65535;
/**
* The default maximum number of chunks that a message can break down into.
* <p>
* More than chunks than constitute {@link #DEFAULT_MAX_MESSAGE_SIZE} are needed because of overhead
* when constructing chunks; not all of the chunk size is dedicated to message bytes.
*/
public static final int DEFAULT_MAX_CHUNK_COUNT = ( DEFAULT_MAX_MESSAGE_SIZE / DEFAULT_MAX_CHUNK_SIZE ) * 2;
public OpcUaClient createClient ( final String connectionUrl,
final String ip,
final int connectionTimeout ) throws Exception
{
final File securityTempDir = new File ( BaseConsts.CACHE_INFO_FULL_PATH + "driver" + BaseConsts.FILE_SEPER + Props.AGENT_ID,
"security" );
if ( !securityTempDir.exists () && !securityTempDir.mkdirs () )
{
throw new Exception ( "unable to create security dir: " + securityTempDir );
}
SecurityPolicy tempSecurityPolicy = null;
if ( Props.SECURITY_POLICY.equals ( Consts.SECURITY_POLICY_0 ) )
{
tempSecurityPolicy = SecurityPolicy.None;
} else if ( Props.SECURITY_POLICY.equals ( Consts.SECURITY_POLICY_1 ) )
{
tempSecurityPolicy = SecurityPolicy.Basic256;
} else if ( Props.SECURITY_POLICY.equals ( Consts.SECURITY_POLICY_2 ) )
{
tempSecurityPolicy = SecurityPolicy.Basic256Sha256;
} else if ( Props.SECURITY_POLICY.equals ( Consts.SECURITY_POLICY_3 ) )
{
tempSecurityPolicy = SecurityPolicy.Basic256Sha256;
}
final SecurityPolicy securityPolicy = tempSecurityPolicy;
List<EndpointDescription> endpoints;
try
{
endpoints = DiscoveryClient.getEndpoints ( connectionUrl ).get ();
} catch ( final Throwable ex )
{
// try the explicit discovery endpoint as well
String discoveryUrl = connectionUrl;
if ( !discoveryUrl.endsWith ( "/" ) )
{
discoveryUrl += "/";
}
discoveryUrl += "discovery";
LOGGER.info ( "Trying explicit discovery URL: {}", discoveryUrl );
endpoints = DiscoveryClient.getEndpoints ( discoveryUrl ).get ();
}
EndpointDescription endpoint = endpoints.stream ()
.filter ( e -> e.getSecurityPolicyUri ().equals ( securityPolicy.getUri () ) )
.filter ( e -> true )
.findFirst ()
.orElseThrow ( () -> new Exception ( "no desired endpoints returned" ) );
final URI uri = new URI ( endpoint.getEndpointUrl () ).parseServerAuthority ();
final String endpointUrl = String.format (
"%s://%s:%s%s",
uri.getScheme (),
ip,
uri.getPort (),
uri.getPath () );
endpoint = new EndpointDescription (
endpointUrl,
endpoint.getServer (),
endpoint.getServerCertificate (),
endpoint.getSecurityMode (),
endpoint.getSecurityPolicyUri (),
endpoint.getUserIdentityTokens (),
endpoint.getTransportProfileUri (),
endpoint.getSecurityLevel ()
);
LOGGER.info ( LogMsgUtil.infoFormat ( "Using endpoint: {} [{}]" ), endpoint.getEndpointUrl (), endpoint.getSecurityMode () );
final UInteger timeout = UInteger.valueOf ( connectionTimeout );
this.loader.load ( securityTempDir );
final MessageLimits messageLimits = new MessageLimits ( DEFAULT_MAX_CHUNK_SIZE, DEFAULT_MAX_CHUNK_COUNT,
DEFAULT_MAX_MESSAGE_SIZE );
OpcUaClientConfig config = null;
if ( Props.USER_AUTHENTICATION_MODE.equals ( Consts.USER_AUTHENTICATION_MODE_0 ) )
{
config = OpcUaClientConfig.builder ()
.setApplicationName ( LocalizedText.english ( BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" ) )
.setApplicationUri ( "urn:hwcv:agent:opcua:client" )
.setCertificate ( this.loader.getClientCertificate () )
.setKeyPair ( this.loader.getClientKeyPair () )
.setEndpoint ( endpoint )
.setIdentityProvider ( new AnonymousProvider () )
.setRequestTimeout ( timeout )
.setMessageLimits ( messageLimits )
.build ();
} else if ( Props.USER_AUTHENTICATION_MODE.equals ( Consts.USER_AUTHENTICATION_MODE_1 ) )
{
config = OpcUaClientConfig.builder ()
.setApplicationName ( LocalizedText.english ( BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" ) )
.setApplicationUri ( "urn:opcua:" + BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" )
.setCertificate ( this.loader.getClientCertificate () )
.setKeyPair ( this.loader.getClientKeyPair () )
.setEndpoint ( endpoint )
.setIdentityProvider ( new UsernameProvider ( Props.USER_ID, Props.USER_PASSWORD ) )
.setRequestTimeout ( timeout )
.setMessageLimits ( messageLimits )
.build ();
} else if ( Props.USER_AUTHENTICATION_MODE.equals ( Consts.USER_AUTHENTICATION_MODE_2 ) )
{
config = OpcUaClientConfig.builder ()
.setApplicationName ( LocalizedText.english ( BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" ) )
.setApplicationUri ( "urn:opcua:" + BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" )
.setCertificate ( this.loader.getClientCertificate () )
.setKeyPair ( this.loader.getClientKeyPair () )
.setEndpoint ( endpoint )
.setIdentityProvider ( new AnonymousProvider () )
.setRequestTimeout ( timeout )
.setMessageLimits ( messageLimits )
.build ();
} else if ( Props.USER_AUTHENTICATION_MODE.equals ( Consts.USER_AUTHENTICATION_MODE_3 ) )
{
config = OpcUaClientConfig.builder ()
.setApplicationName ( LocalizedText.english ( BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" ) )
.setApplicationUri ( "urn:opcua:" + BaseProps.SYSTEM_SERVICE_NAME + " OPC-UA Client" )
.setCertificate ( this.loader.getClientCertificate () )
.setKeyPair ( this.loader.getClientKeyPair () )
.setEndpoint ( endpoint )
.setIdentityProvider ( new AnonymousProvider () )
.setRequestTimeout ( timeout )
.setMessageLimits ( messageLimits )
.build ();
}
this.opcUAClient = OpcUaClient.create ( config );
return this.opcUAClient;
}
public void destroyClient ()
{
if ( this.opcUAClient != null )
{
try
{
this.opcUAClient.disconnect ();
} catch ( final Exception e )
{
final String errTraceMsg = LogMsgUtil.makeErrTraceMessage ( this.getClass (),
new Throwable ().getStackTrace () [0].getMethodName () );
final String errUsrMsg = errTraceMsg + "Error disconnecting";
final SPNetworkException spNetworkException = new SPNetworkException ( Consts.BUNDLE_ID, ErrCds.ERR_02_0106,
LangMessage.getMessage ( ErrCds.ERR_02_0106 ), errUsrMsg );
SPExceptionHandler.exceptionLogging ( spNetworkException, LOGGER );
}
}
}
}
`
If I set KEPServerEx6 securitymode to Sign. It works well.
But If I set that to Sign and Encrypt mode, OPC Client can't connect to Server.
It there any problem in my code?
