有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

EclipseMilo中的java身份验证clientserver

在EclipseMilo中,客户端是否可以使用以下身份验证参数连接到服务器:“证书+私钥”? 还有参数“安全策略”和“消息安全模式”

(与UAExpert客户端一样:http://documentation.unified-automation.com/uaexpert/1.4.0/html/connect.html

如果是的话,怎么办


我有:

  • 一个“.perm”文件格式的私钥
  • 一份“.der”文件格式的证书
  • 服务器的一个CA,文件格式为“.der”
  • 以及服务器的CA(4096位at“.der”文件格式)

共 (2) 个答案

  1. # 1 楼答案

    是的,目前这是可能的,尽管它不像现在使用用户名/密码那样“简单”

    客户端SDK公开了一个名为IdentityProvider的接口,该接口在客户端连接时被委托给,并被赋予端点和服务器nonce。它返回一个包含UserIdentityTokenSignatureData的2元组

    您需要为X509IdentityToken案例实现此接口,并返回您的证书(在X509IdentityToken)以及您拥有该证书密钥的证明(在SignatureData

    一旦有了这个IdentityProvider,您就可以在构建OpcUaClientConfig对象时通过调用setIdentityProvider告诉客户机在配置它时使用它

    因为这有点麻烦,而SDK的目的是减轻用户的负担,所以我也将把它作为Milo的功能标签。如果你自己不能实现它,我可以在本周开始

  2. # 2 楼答案

    Kevin Herron的帮助下,我通过使用他的类X509IdentityProvider解决了我的问题

    以下是解决方案代码:

    PemFile.java

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    
    public class PemFile {
    
        private PemObject pemObject;
    
        public PemFile(String filename) throws FileNotFoundException, IOException {
            PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename)));
            try {
                this.pemObject = pemReader.readPemObject();
            } finally {
                pemReader.close();
            }
        }
    
        public PemObject getPemObject() {
            return pemObject;
        }
    }
    

    X509IdentityProvider.java

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.ByteBuffer;
    import java.security.GeneralSecurityException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.PrivateKey;
    import java.security.Security;
    import java.security.cert.CertificateException;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.util.Arrays;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.eclipse.milo.opcua.sdk.client.api.identity.IdentityProvider;
    import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
    import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
    import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType;
    import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
    import org.eclipse.milo.opcua.stack.core.types.structured.SignatureData;
    import org.eclipse.milo.opcua.stack.core.types.structured.UserIdentityToken;
    import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy;
    import org.eclipse.milo.opcua.stack.core.types.structured.X509IdentityToken;
    import org.eclipse.milo.opcua.stack.core.util.SignatureUtil;
    import org.jooq.lambda.tuple.Tuple2;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class X509IdentityProvider implements IdentityProvider {
        private final Logger logger = LoggerFactory.getLogger(getClass());
        private final X509Certificate certificate;
        private final PrivateKey privateKey;
    
        public X509Certificate getCertificate() {
            return certificate;
        }
    
        public PrivateKey getPrivateKey() {
            return privateKey;
        }
    
        public X509IdentityProvider(X509Certificate certificate, PrivateKey privateKey) {
            this.certificate = certificate;
            this.privateKey = privateKey;
        }
    
        public X509IdentityProvider(String certificate, String privateKey) {
            this.certificate = loadCertificateFromDerFile(certificate);
    
            Security.addProvider(new BouncyCastleProvider());
            KeyFactory kf;
            PrivateKey privateKeyTmp = null;
            try {
                kf = KeyFactory.getInstance("RSA", "BC");
                privateKeyTmp = loadPrivateKeyFromPemFile(kf, privateKey);
            } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException | IOException e) {
                e.printStackTrace();
            }
            this.privateKey = privateKeyTmp;
    
        }
    
        @Override
        public Tuple2<UserIdentityToken, SignatureData> getIdentityToken(EndpointDescription endpoint,
                ByteString serverNonce) throws Exception {
            UserTokenPolicy tokenPolicy = Arrays.stream(endpoint.getUserIdentityTokens())
                    .filter(t -> t.getTokenType() == UserTokenType.Certificate).findFirst()
                    .orElseThrow(() -> new Exception("no x509 certificate token policy found"));
            String policyId = tokenPolicy.getPolicyId();
            SecurityPolicy securityPolicy = SecurityPolicy.Basic256;
            String securityPolicyUri = tokenPolicy.getSecurityPolicyUri();
            try {
                if (securityPolicyUri != null && !securityPolicyUri.isEmpty()) {
                    securityPolicy = SecurityPolicy.fromUri(securityPolicyUri);
                } else {
                    securityPolicyUri = endpoint.getSecurityPolicyUri();
                    securityPolicy = SecurityPolicy.fromUri(securityPolicyUri);
                }
            } catch (Throwable t) {
                logger.warn("Error parsing SecurityPolicy for uri={}", securityPolicyUri);
            }
            X509IdentityToken token = new X509IdentityToken(policyId, ByteString.of(certificate.getEncoded()));
            SignatureData signatureData;
            ByteString serverCertificate = endpoint.getServerCertificate();
            byte[] serverCertificateBytes = serverCertificate.isNotNull() ? serverCertificate.bytes() : new byte[0];
            byte[] serverNonceBytes = serverNonce.isNotNull() ? serverNonce.bytes() : new byte[0];
            assert serverCertificateBytes != null;
            assert serverNonceBytes != null;
            byte[] signature = SignatureUtil.sign(securityPolicy.getAsymmetricSignatureAlgorithm(), privateKey,
                    ByteBuffer.wrap(serverCertificateBytes), ByteBuffer.wrap(serverNonceBytes));
            signatureData = new SignatureData(securityPolicy.getAsymmetricSignatureAlgorithm().getUri(),
                    ByteString.of(signature));
            return new Tuple2<>(token, signatureData);
        }
    
    
        private static X509Certificate loadCertificateFromDerFile(String filename) {
            InputStream in;
            X509Certificate cert = null;
            try {
                in = new FileInputStream(filename);
    
                CertificateFactory factory = CertificateFactory.getInstance("X.509");
                 cert = (X509Certificate) factory.generateCertificate(in);
            } catch (FileNotFoundException | CertificateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return cert;
        }
    
        private static PrivateKey loadPrivateKeyFromPemFile(KeyFactory factory, String filename)
                throws InvalidKeySpecException, FileNotFoundException, IOException {
            PemFile pemFile = new PemFile(filename);
            byte[] content = pemFile.getPemObject().getContent();
            PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
            return factory.generatePrivate(privKeySpec);
        }
    
    }
    

    ClientRunner.java

    ...
    ...
    
    private OpcUaClient createClient() throws Exception {
            SecurityPolicy securityPolicy = clientExample.getSecurityPolicy(); // For example : SecurityPolicy.Basic256
            String securityMode = clientExample.getSecurityMode(); // For example : "SignAndEncrypt"
    
            EndpointDescription[] endpoints = UaTcpStackClient.getEndpoints(endpointUrl).get();
    
            EndpointDescription endpoint = Arrays.stream(endpoints)
                    .filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getSecurityPolicyUri()))//
                    .filter(e -> e.getSecurityMode().toString().compareTo(securityMode) == 0)//
                    .findFirst()//
                    .orElseThrow(() -> new Exception("no desired endpoints returned"));
    
            logger.info("Using endpoint: {} [{}]", endpoint.getEndpointUrl(), securityPolicy);
    
            loader.load();
    
            // Mode : securityPolicy == SecurityPolicy.Basic256 && securityMode.compareTo("SignAndEncrypt") == 0)
            X509IdentityProvider x509IdentityProvider = new X509IdentityProvider("/certificate.der",
                    "/privateKey.pem");
            X509Certificate cert = x509IdentityProvider.getCertificate();
            KeyPair keyPair = new KeyPair(cert.getPublicKey(), x509IdentityProvider.getPrivateKey());
            OpcUaClientConfig config = OpcUaClientConfig.builder().setApplicationName(LocalizedText.english("opc-ua client"))//
                    .setApplicationUri("urn:opcua client")//
                    .setCertificate(cert)//
                    .setKeyPair(keyPair)//
                    .setEndpoint(endpoint)//
                    .setIdentityProvider(x509IdentityProvider)//
                    .setIdentityProvider(clientExample.getIdentityProvider())//
                    .setRequestTimeout(uint(5000))//
                    .build();
    
    
            return new OpcUaClient(config);
        }