Add transport-tls
[netconf.git] / transport / transport-tls / src / test / java / org / opendaylight / netconf / transport / tls / TestUtils.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech s.r.o. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.transport.tls;
9
10 import java.math.BigInteger;
11 import java.security.KeyPair;
12 import java.security.KeyPairGenerator;
13 import java.security.SecureRandom;
14 import java.security.cert.X509Certificate;
15 import java.security.spec.ECGenParameterSpec;
16 import java.security.spec.RSAKeyGenParameterSpec;
17 import java.time.Duration;
18 import java.time.Instant;
19 import java.util.Date;
20 import java.util.Map;
21 import java.util.stream.Collectors;
22 import org.bouncycastle.asn1.x500.X500Name;
23 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
24 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
25 import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
26 import org.bouncycastle.crypto.util.PublicKeyFactory;
27 import org.bouncycastle.jce.provider.BouncyCastleProvider;
28 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.EndEntityCertCms;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.PrivateKeyFormat;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.PublicKeyFormat;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.TrustAnchorCertCms;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.asymmetric.key.pair.grouping._private.key.type.CleartextPrivateKeyBuilder;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev221212.LocalOrKeystoreAsymmetricKeyGrouping;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev221212.LocalOrKeystoreEndEntityCertWithKeyGrouping;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev221212.tls.server.grouping.server.identity.auth.type.raw._private.key.RawPrivateKeyBuilder;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev221212.local.or.truststore.certs.grouping.LocalOrTruststore;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev221212.local.or.truststore.certs.grouping.local.or.truststore.local.local.definition.CertificateBuilder;
39
40 public final class TestUtils {
41     private static final SecureRandom SECURE_RANDOM = new SecureRandom();
42
43     private TestUtils() {
44         // utility class
45     }
46
47     public static LocalOrTruststore buildLocalOrTruststore(Map<String, byte[]> certNameToBytesMap) {
48         final var certMap = certNameToBytesMap.entrySet().stream()
49                 .map(entry -> new CertificateBuilder()
50                         .setName(entry.getKey())
51                         .setCertData(new TrustAnchorCertCms(entry.getValue()))
52                         .build()
53                 ).collect(Collectors.toMap(cert -> cert.key(), cert -> cert));
54         final var localDef = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev221212
55                 .local.or.truststore.certs.grouping.local.or.truststore.local.LocalDefinitionBuilder()
56                 .setCertificate(certMap).build();
57         return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev221212
58                 .local.or.truststore.certs.grouping.local.or.truststore.LocalBuilder()
59                 .setLocalDefinition(localDef).build();
60     }
61
62     public static LocalOrKeystoreAsymmetricKeyGrouping buildAsymmetricKeyGrouping(
63             final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
64             final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes) {
65         final var localDef = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev221212
66                 .local.or.keystore.asymmetric.key.grouping.local.or.keystore.local.LocalDefinitionBuilder()
67                 .setPublicKeyFormat(publicKeyFormat)
68                 .setPublicKey(publicKeyBytes)
69                 .setPrivateKeyFormat(privateKeyFormat)
70                 .setPrivateKeyType(new CleartextPrivateKeyBuilder().setCleartextPrivateKey(privateKeyBytes).build())
71                 .build();
72         return new RawPrivateKeyBuilder()
73                 .setLocalOrKeystore(
74                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev221212
75                                 .local.or.keystore.asymmetric.key.grouping.local.or.keystore.LocalBuilder()
76                                 .setLocalDefinition(localDef).build())
77                 .build();
78     }
79
80     public static LocalOrKeystoreEndEntityCertWithKeyGrouping buildEndEntityCertWithKeyGrouping(
81             final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
82             final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes, final byte[] certificateBytes) {
83         final var localDef = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev221212
84                 .local.or.keystore.end.entity.cert.with.key.grouping.local.or.keystore.local.LocalDefinitionBuilder()
85                 .setPublicKeyFormat(publicKeyFormat)
86                 .setPublicKey(publicKeyBytes)
87                 .setPrivateKeyFormat(privateKeyFormat)
88                 .setPrivateKeyType(new CleartextPrivateKeyBuilder().setCleartextPrivateKey(privateKeyBytes).build())
89                 .setCertData(new EndEntityCertCms(certificateBytes))
90                 .build();
91         return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev221212
92                 .tls.server.grouping.server.identity.auth.type.certificate.CertificateBuilder()
93                 .setLocalOrKeystore(
94                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev221212
95                                 .local.or.keystore.end.entity.cert.with.key.grouping.local.or.keystore.LocalBuilder()
96                                 .setLocalDefinition(localDef).build())
97                 .build();
98     }
99
100     public static X509CertData generateX509CertData(final String algorithm) throws Exception {
101         final var keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
102         if (isRSA(algorithm)) {
103             keyPairGenerator.initialize(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4), SECURE_RANDOM);
104         } else {
105             keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"), SECURE_RANDOM);
106         }
107         final var keyPair = keyPairGenerator.generateKeyPair();
108         final var certificate = generateCertificate(keyPair, isRSA(algorithm) ? "SHA256withRSA" : "SHA256withECDSA");
109         final var publicKeyBytes = keyPair.getPublic().getEncoded();
110         final var privateKeyBytes = keyPair.getPrivate().getEncoded();
111         return new X509CertData(certificate.getEncoded(), publicKeyBytes, privateKeyBytes,
112                 OpenSSHPublicKeyUtil.encodePublicKey(PublicKeyFactory.createKey(publicKeyBytes)));
113     }
114
115     private static X509Certificate generateCertificate(final KeyPair keyPair, final String hashAlgorithm)
116             throws Exception {
117         final var now = Instant.now();
118         final var contentSigner = new JcaContentSignerBuilder(hashAlgorithm).build(keyPair.getPrivate());
119
120         final var x500Name = new X500Name("CN=TestCertificate");
121         final var certificateBuilder = new JcaX509v3CertificateBuilder(x500Name,
122                 BigInteger.valueOf(now.toEpochMilli()),
123                 Date.from(now), Date.from(now.plus(Duration.ofDays(365))),
124                 x500Name,
125                 keyPair.getPublic());
126         return new JcaX509CertificateConverter()
127                 .setProvider(new BouncyCastleProvider()).getCertificate(certificateBuilder.build(contentSigner));
128     }
129
130     public static boolean isRSA(final String algorithm) {
131         return KeyUtils.RSA_ALGORITHM.equals(algorithm);
132     }
133
134     public record X509CertData(byte[] certBytes, byte[] publicKey, byte[] privateKey, byte[] sshPublicKey) {
135     }
136 }