2 * Copyright (c) 2023 PANTHEON.tech s.r.o. All rights reserved.
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
8 package org.opendaylight.netconf.transport.tls;
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;
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;
40 public final class TestUtils {
41 private static final SecureRandom SECURE_RANDOM = new SecureRandom();
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()))
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();
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())
72 return new RawPrivateKeyBuilder()
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())
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))
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()
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())
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);
105 keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"), SECURE_RANDOM);
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)));
115 private static X509Certificate generateCertificate(final KeyPair keyPair, final String hashAlgorithm)
117 final var now = Instant.now();
118 final var contentSigner = new JcaContentSignerBuilder(hashAlgorithm).build(keyPair.getPrivate());
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))),
125 keyPair.getPublic());
126 return new JcaX509CertificateConverter()
127 .setProvider(new BouncyCastleProvider()).getCertificate(certificateBuilder.build(contentSigner));
130 public static boolean isRSA(final String algorithm) {
131 return KeyUtils.RSA_ALGORITHM.equals(algorithm);
134 public record X509CertData(byte[] certBytes, byte[] publicKey, byte[] privateKey, byte[] sshPublicKey) {