OPCUA标准java实现 Milo库 证书的生成和使用

Milo库中的证书生成和使用

在我的上一篇文章《Milo库OPCUA协议java实现》中发现比较多人留言说到比较困惑在创建客户端过程中的证书的生成和使用。下面我就跟大家说一下。

我自己做的一个相关例程:证书处理的例程

使用Milo库自带的证书生成工具

在上一篇文章中我们可以看到,OPC UA客户端对象的创建是需要一个X509Certificate证书对象,和一个KeyPair密钥对。

下面的代码用到了Milo库中的工具对象来读取或者创建证书文件,代码会有点长,请耐心看下去。(我会在下面代码相应的地方作注释说明)。

class KeyStoreLoader {

    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 static final String CLIENT_ALIAS = "client-ai";
    //获取私钥的密码
    private static final char[] PASSWORD = "password".toCharArray();

    private final Logger logger = LoggerFactory.getLogger(getClass());

    //证书对象
    private X509Certificate clientCertificate;
    //密钥对对象
    private KeyPair clientKeyPair;

    KeyStoreLoader load(Path baseDir) throws Exception {
        //创建一个使用`PKCS12`加密标准的KeyStore。KeyStore在后面将作为读取和生成证书的对象。
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        //PKCS12的加密标准的文件后缀是.pfx,其中包含了公钥和私钥。
        //而其他如.der等的格式只包含公钥,私钥在另外的文件中。
        Path serverKeyStore = baseDir.resolve("example-client.pfx");

        logger.info("Loading KeyStore at {}", serverKeyStore);

        //如果文件不存在则创建.pfx证书文件。
        if (!Files.exists(serverKeyStore)) {
            keyStore.load(null, PASSWORD);

            //用2048位的RAS算法。`SelfSignedCertificateGenerator`为Milo库的对象。
            KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);

            //`SelfSignedCertificateBuilder`也是Milo库的对象,用来生成证书。
            //中间所设置的证书属性可以自行修改。
            SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder(keyPair)
                .setCommonName("Eclipse Milo Example Client")
                .setOrganization("digitalpetri")
                .setOrganizationalUnit("dev")
                .setLocalityName("Folsom")
                .setStateName("CA")
                .setCountryCode("US")
                .setApplicationUri("urn:eclipse:milo:examples:client")
                .addDnsName("localhost")
                .addIpAddress("127.0.0.1");

            // Get as many hostnames and IP addresses as we can listed in the certificate.
            for (String hostname : HostnameUtil.getHostnames("0.0.0.0")) {
                if (IP_ADDR_PATTERN.matcher(hostname).matches()) {
                    builder.addIpAddress(hostname);
                } else {
                    builder.addDnsName(hostname);
                }
            }
            //创建证书
            X509Certificate certificate = builder.build();

            //设置对应私钥的别名,密码,证书链
            keyStore.setKeyEntry(CLIENT_ALIAS, keyPair.getPrivate(), PASSWORD, new X509Certificate[]{certificate});
            try (OutputStream out = Files.newOutputStream(serverKeyStore)) {
                //保存证书到输出流
                keyStore.store(out, PASSWORD);
            }
        } else {
            try (InputStream in = Files.newInputStream(serverKeyStore)) {
                //如果文件存在则读取
                keyStore.load(in, PASSWORD);
            }
        }

        //用密码获取对应别名的私钥。
        Key serverPrivateKey = keyStore.getKey(CLIENT_ALIAS, PASSWORD);
        if (serverPrivateKey instanceof PrivateKey) {
            //获取对应别名的证书对象。
            clientCertificate = (X509Certificate) keyStore.getCertificate(CLIENT_ALIAS);
            //获取公钥
            PublicKey serverPublicKey = clientCertificate.getPublicKey();
            //创建Keypair对象。
            clientKeyPair = new KeyPair(serverPublicKey, (PrivateKey) serverPrivateKey);
        }

        return this;
    }

    //返回证书
    X509Certificate getClientCertificate() {
        return clientCertificate;
    }

    //返回密钥对
    KeyPair getClientKeyPair() {
        return clientKeyPair;
    }

}

上面所返回的证书和密钥对就可以在创建OPC UA客户端对象中使用了。

上面例子来自Milo例程:Milo证书例程


对现有的.der和.pem文件获取证书对象和密钥对

这里我们先讨论怎样获取.der,.pem文件的证书和密钥,关于该类型证书的生成我们下面再来一起讨论。

假设如果我们原本有.der.pem文件的话,想要读取证书和私钥就会稍稍有点复杂,创建OPC客户端对象需要证书和密钥对,那么自然要获取证书对象,和公钥,私钥对象。读取.der证书不是什么难事,难的在于解析.pem文件。私钥就是存放在.pem文件中。

关于.pem文件的解析我们借助bouncycastle包来帮助我们解析,首先需要添加依赖:

maven

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.57</version>
</dependency>

gradle:

compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.57'

证书的获取

获取证书的代码如下:

X509Certificate c = null;
File derFilee = new File("\\...");

FileInputStream in = new FileInputStream(derFile);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
c = (X509Certificate) cf.generateCertificate(in);

密钥的获取

密钥的获取就需要用到bouncycastle包了。

获取密匙对的代码如下:

KeyPair keyPair = null;
File pemFile = new File("\\...");
FileInputStream privatekeyfile = new FileInputStream(pemFile);

//添加BouncyCastleProvider
Security.addProvider(new BouncyCastleProvider());
PEMParser pemParser = new PEMParser(new InputStreamReader(privatekeyfile));
Object object = pemParser.readObject();
PEMDecryptorProvider pemDecryptorProvider = new 

//其中password 是读取私钥所需要的密码
JcePEMDecryptorProviderBuilder().build("password".toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
//获取KeyPair对象。
keyPair = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(pemDecryptorProvider));

至此我们就成功获取到证书对象和密钥对了,就可以使用这两个对象创建OPC客户端了。


OPC Foundation的OPC库中提供的证书处理方法

上一篇我文章也说过,OPC Foundation在Github上也是有OPC UA的java库的,只是因为相比于Milo学习资源不多,官方的例程也做得不够Milo好,所以我就没有选用OPC Foundation的java实现。

但是既然现在说到了关于证书的生成和使用问题,那么就来看一下OPC Foundation 是怎样来创建证书和获取证书的。

//以下程序需要添加OPC Foundation的java实现的依赖
private static KeyPair getOPCCert(String applicationName)
        throws ServiceResultException
{
    File certFile = new File(applicationName + ".der");
    File privKeyFile =  new File(applicationName+ ".pem");
    //尝试获取证书和密钥对。
    try {
        Cert myServerCertificate = Cert.load( certFile );
        PrivKey myServerPrivateKey = PrivKey.load(privKeyFile, "password");
        KeyPair k = new KeyPair(myServerCertificate, myServerPrivateKey);
        return k;
    } catch (CertificateException e) {
        throw new ServiceResultException( e );
    } catch (IOException e) {
        //如果文件不存在的话则创建一个`.der`和`.pem`文件
        try {
            String hostName = InetAddress.getLocalHost().getHostName();
            String applicationUri = "urn:"+hostName+":"+applicationName;
            KeyPair keys = CertificateUtils.createApplicationInstanceCertificate(applicationName, null, applicationUri, 3650, hostName);
            keys.getCertificate().save(certFile);
            PrivKey privKeySecure = keys.getPrivateKey();
            //设置私钥访问密码
            privKeySecure.save(privKeyFile, "password");
            return keys;
        } catch (Exception e1) {
            throw new ServiceResultException( e1 );
        }
    } catch (NoSuchAlgorithmException e) {
        throw new ServiceResultException( e );
    } catch (Exception e) {
        throw new ServiceResultException( e );
    }
}

上面的例程是OPC Foundation 中的一个获取和创建证书的例子,可以看到在OPC Foundation 中正是读取或者创建.der.pem,而且代码更少,更简单。

为什么OPC Foundation 读取.pem这么简单轻松?正是因为上述例程中KeyPair对象的包名是org.opcfoundation.ua.transport.security,也即是由OPC Foundation重新封装过的KeyPair对象。而在Milo库中使用的则是在包为java.security中的KeyPair对象。所以是不能直接用到Milo库中的。

这两个对象的转化如下:

//k 为org.opcfoundation.ua.transport.security包中的KeyPair
java.security.KeyPair keyPair = new java.security.KeyPair(k.getCertificate().getCertificate().getPublicKey(),k.getPrivateKey().getPrivateKey());

以上例程来自OPC Foundation证书例程


总结

以上就是我目前来说所用到的证书处理方法,本人知识有限,如果还有更好的方法或者有什么不对的可以提出。最好的方法还是之间去看源码,什么都一目了然了。

本人公众号,有空就更新更新,谢谢支持。哈哈
公众号ChivaStudio

<think>好的,我现在需要帮助用户解决关于使用Java开发OPC UA Server的问题。首先,用户提到的参考资料中有几个引用,特别是关于使用Eclipse Milo的示例。我记得Milo是一个常用的Java,专门用于OPC UA的实现,所以应该重点推荐这个。 接下来,用户需要示例代码推荐。根据引用[1][3],用户可能希望有一个简单易懂的示例,避免官方示例的复杂性。所以,我应该提供一个基础的服务器创建步骤,包括添加节点读写操作。 然后,考虑用户可能的痛点,比如本地测试环境搭建困难,引用[3]提到使用KEPServerEX6比较麻烦,所以Milo的简便性很重要。此外,用户可能需要对节点的动态读写,这部分在代码示例中应该体现出来。 另外,需要确保代码符合用户的环境配置,比如Maven依赖,引用[4]提到了Milo的GitHub仓,所以需要正确引入依赖项。同时,代码结构要清晰,注释详细,方便用户理解每一步的作用。 还要注意用户提到的性能优化常见问题,比如内存管理或安全策略配置,这些在开发中可能会遇到,需要在回答中提前给出建议,帮助用户避免常见错误。 最后,生成相关问题,引导用户进一步学习,比如性能优化、安全配置客户端开发,这些都能帮助用户更全面地应用OPC UA技术。</think>### Java实现OPC UA Server开发指南 #### 一、开发工具选择 推荐使用Eclipse Milo开源,这是目前Java领域最成熟的OPC UA协议实现框架。相比KEPServerEX等商业方案,Milo提供更灵活的API免授权使用特性[^1][^3]。 #### 二、开发环境搭建 1. Maven依赖配置: ```xml <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>sdk-client</artifactId> <version>0.6.8</version> </dependency> <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>server-examples</artifactId> <version>0.6.8</version> </dependency> ``` #### 三、基础服务器实现 ```java public class BasicServer { public static void main(String[] args) throws Exception { // 1. 创建服务器实例 OpcUaServer server = OpcUaServer.create( EndpointConfiguration.builder() .bindAddress("localhost") .bindPort(12686) .build(), new DefaultNamespaceManager(), SecurityPolicy.None // 测试环境禁用安全策略 ); // 2. 添加自定义节点 server.getNamespaceManager().addNamespace( Namespace.builder() .uri("urn:my-namespace") .nodeId(2) .build() ); // 3. 创建数据节点 UaVariableNode temperatureNode = new UaVariableNode.UaVariableNodeBuilder(server) .setNodeId(new NodeId(2, "Temperature")) .setBrowseName(new QualifiedName(2, "CurrentTemp")) .setDataType(Identifiers.Double) .setValue(new DataValue(new Variant(25.0))) .build(); // 4. 启动服务 server.startup().get(); System.out.println("OPC UA服务已启动"); } } ``` #### 四、核心功能实现 1. **动态数据更新**: ```java // 创建可写节点 UaVariableNode writableNode = new UaVariableNode.UaVariableNodeBuilder(server) .setAccessLevel(AccessLevel.READ_WRITE) .setUserAccessLevel(AccessLevel.READ_WRITE) .build(); // 修改节点值 writableNode.setValue(new DataValue(new Variant(30.0))); ``` 2. **历史数据存储**(需配合数据): ```java // 配置历史记录 writableNode.setHistorizing(true); server.getHistoryManager().registerNode(writableNode); ``` #### 五、开发建议 1. 生产环境必须配置安全策略(Basic256Sha256等) 2. 建议使用线程池管理数据更新任务 3. 节点ID命名遵循IEC 61360规范 4. 使用OPC UA客户端工具(如UaExpert)进行调试 #### 六、进阶功能扩展 1. 事件通知机制 2. 方法调用功能 3. 订阅/发布模式 4. 证书管理(X.509)
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值