External service integration support for TLS transport
[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 org.bouncycastle.asn1.x500.X500Name;
22 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
23 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
24 import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
25 import org.bouncycastle.crypto.util.PublicKeyFactory;
26 import org.bouncycastle.jce.provider.BouncyCastleProvider;
27 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev230417.EndEntityCertCms;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev230417.PrivateKeyFormat;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev230417.PublicKeyFormat;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev230417.TrustAnchorCertCms;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev230417.asymmetric.key.pair.grouping._private.key.type.CleartextPrivateKeyBuilder;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev230417.InlineOrKeystoreAsymmetricKeyGrouping;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev230417.InlineOrKeystoreEndEntityCertWithKeyGrouping;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev230417.tls.server.grouping.server.identity.auth.type.raw._private.key.RawPrivateKeyBuilder;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev230417.inline.or.truststore.certs.grouping.InlineOrTruststore;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev230417.inline.or.truststore.certs.grouping.inline.or.truststore.inline.inline.definition.CertificateBuilder;
38 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
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 InlineOrTruststore buildInlineOrTruststore(final Map<String, byte[]> certNameToBytesMap) {
48         return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev230417
49             .inline.or.truststore.certs.grouping.inline.or.truststore.InlineBuilder()
50             .setInlineDefinition(new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.truststore.rev230417
51                 .inline.or.truststore.certs.grouping.inline.or.truststore.inline.InlineDefinitionBuilder()
52                 .setCertificate(certNameToBytesMap.entrySet().stream()
53                     .map(entry -> new CertificateBuilder()
54                         .setName(entry.getKey())
55                         .setCertData(new TrustAnchorCertCms(entry.getValue()))
56                         .build())
57                     .collect(BindingMap.toMap()))
58                 .build())
59             .build();
60     }
61
62     public static InlineOrKeystoreAsymmetricKeyGrouping buildAsymmetricKeyGrouping(
63             final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
64             final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes) {
65         return new RawPrivateKeyBuilder()
66             .setInlineOrKeystore(new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev230417
67                 .inline.or.keystore.asymmetric.key.grouping.inline.or.keystore.InlineBuilder()
68                 .setInlineDefinition(new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore
69                     .rev230417.inline.or.keystore.asymmetric.key.grouping.inline.or.keystore.inline
70                     .InlineDefinitionBuilder()
71                         .setPublicKeyFormat(publicKeyFormat)
72                         .setPublicKey(publicKeyBytes)
73                         .setPrivateKeyFormat(privateKeyFormat)
74                         .setPrivateKeyType(new CleartextPrivateKeyBuilder()
75                             .setCleartextPrivateKey(privateKeyBytes)
76                             .build())
77                         .build())
78                 .build())
79             .build();
80     }
81
82     public static InlineOrKeystoreEndEntityCertWithKeyGrouping buildEndEntityCertWithKeyGrouping(
83             final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
84             final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes, final byte[] certificateBytes) {
85         return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.server.rev230417
86             .tls.server.grouping.server.identity.auth.type.certificate.CertificateBuilder()
87             .setInlineOrKeystore(new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore.rev230417
88                 .inline.or.keystore.end.entity.cert.with.key.grouping.inline.or.keystore.InlineBuilder()
89                 .setInlineDefinition(new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.keystore
90                     .rev230417.inline.or.keystore.end.entity.cert.with.key.grouping.inline.or.keystore.inline
91                     .InlineDefinitionBuilder()
92                     .setPublicKeyFormat(publicKeyFormat)
93                     .setPublicKey(publicKeyBytes)
94                     .setPrivateKeyFormat(privateKeyFormat)
95                     .setPrivateKeyType(new CleartextPrivateKeyBuilder().setCleartextPrivateKey(privateKeyBytes).build())
96                     .setCertData(new EndEntityCertCms(certificateBytes))
97                     .build())
98                 .build())
99             .build();
100     }
101
102     public static X509CertData generateX509CertData(final String algorithm) throws Exception {
103         final var keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
104         if (isRSA(algorithm)) {
105             keyPairGenerator.initialize(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4), SECURE_RANDOM);
106         } else {
107             keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"), SECURE_RANDOM);
108         }
109         final var keyPair = keyPairGenerator.generateKeyPair();
110         final var certificate = generateCertificate(keyPair, isRSA(algorithm) ? "SHA256withRSA" : "SHA256withECDSA");
111         final var publicKeyBytes = keyPair.getPublic().getEncoded();
112         final var privateKeyBytes = keyPair.getPrivate().getEncoded();
113         return new X509CertData(certificate, keyPair, certificate.getEncoded(), publicKeyBytes, privateKeyBytes,
114                 OpenSSHPublicKeyUtil.encodePublicKey(PublicKeyFactory.createKey(publicKeyBytes)));
115     }
116
117     private static X509Certificate generateCertificate(final KeyPair keyPair, final String hashAlgorithm)
118             throws Exception {
119         final var now = Instant.now();
120         final var contentSigner = new JcaContentSignerBuilder(hashAlgorithm).build(keyPair.getPrivate());
121
122         final var x500Name = new X500Name("CN=TestCertificate");
123         final var certificateBuilder = new JcaX509v3CertificateBuilder(x500Name,
124                 BigInteger.valueOf(now.toEpochMilli()),
125                 Date.from(now), Date.from(now.plus(Duration.ofDays(365))),
126                 x500Name,
127                 keyPair.getPublic());
128         return new JcaX509CertificateConverter()
129                 .setProvider(new BouncyCastleProvider()).getCertificate(certificateBuilder.build(contentSigner));
130     }
131
132     public static boolean isRSA(final String algorithm) {
133         return KeyUtils.RSA_ALGORITHM.equals(algorithm);
134     }
135
136     public record X509CertData(X509Certificate certificate, KeyPair keyPair, byte[] certBytes, byte[] publicKey,
137         byte[] privateKey, byte[] sshPublicKey) {
138     }
139 }