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 static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertFalse;
12 import static org.junit.jupiter.api.Assertions.assertNotNull;
13 import static org.junit.jupiter.api.Assertions.assertTrue;
14 import static org.opendaylight.netconf.transport.tls.ConfigUtils.DEFAULT_CERTIFICATE_ALIAS;
15 import static org.opendaylight.netconf.transport.tls.ConfigUtils.DEFAULT_PRIVATE_KEY_ALIAS;
16 import static org.opendaylight.netconf.transport.tls.ConfigUtils.EMPTY_SECRET;
17 import static org.opendaylight.netconf.transport.tls.TestUtils.buildAsymmetricKeyGrouping;
18 import static org.opendaylight.netconf.transport.tls.TestUtils.buildEndEntityCertWithKeyGrouping;
19 import static org.opendaylight.netconf.transport.tls.TestUtils.buildInlineOrTruststore;
20 import static org.opendaylight.netconf.transport.tls.TestUtils.generateX509CertData;
22 import java.security.KeyStore;
23 import java.util.Collections;
24 import java.util.List;
27 import java.util.stream.Stream;
28 import org.junit.jupiter.api.BeforeEach;
29 import org.junit.jupiter.api.Disabled;
30 import org.junit.jupiter.api.Test;
31 import org.junit.jupiter.params.ParameterizedTest;
32 import org.junit.jupiter.params.provider.Arguments;
33 import org.junit.jupiter.params.provider.MethodSource;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.EcPrivateKeyFormat;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.PrivateKeyFormat;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.PublicKeyFormat;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.RsaPrivateKeyFormat;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.SshPublicKeyFormat;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.SubjectPublicKeyInfoFormat;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.client.rev231228.tls.client.grouping.server.authentication.CaCertsBuilder;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.client.rev231228.tls.client.grouping.server.authentication.EeCertsBuilder;
43 class ConfigUtilsTest {
45 private KeyStore keyStore;
48 void setup() throws Exception {
49 keyStore = KeyStoreUtils.newKeyStore();
53 void setX509Certificates() throws Exception {
54 final var rsaCertData = generateX509CertData("RSA");
55 final var ecCertData = generateX509CertData("EC");
57 // not defined -- ignore
58 ConfigUtils.setX509Certificates(keyStore, null, null);
59 assertFalse(keyStore.aliases().hasMoreElements());
62 final var inlineOrTruststore = buildInlineOrTruststore(
63 Map.of("cert-rsa", rsaCertData.certBytes(), "cert-ec", ecCertData.certBytes()));
64 final var caCerts = new CaCertsBuilder().setInlineOrTruststore(inlineOrTruststore).build();
65 final var eeCerts = new EeCertsBuilder().setInlineOrTruststore(inlineOrTruststore).build();
66 ConfigUtils.setX509Certificates(keyStore, caCerts, eeCerts);
68 final List<String> aliases = Collections.list(keyStore.aliases());
69 final Set<String> expectedAliases = Set.of("ca-cert-rsa", "ca-cert-ec", "ee-cert-rsa", "ee-cert-ec");
70 assertNotNull(aliases);
71 assertEquals(4, aliases.size());
72 assertEquals(expectedAliases, Set.copyOf(aliases));
73 for (String alias : aliases) {
74 assertTrue(keyStore.isCertificateEntry(alias));
75 assertNotNull(keyStore.getCertificate(alias));
79 @ParameterizedTest(name = "Set private key from pair: {0}")
80 @MethodSource("asymmetricKeyArgs")
82 // raw public key is not implemented yet
83 void setPrivateKeyFromKeyPair(final String testDesc,
84 final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
85 final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes,
86 final byte[] certificateBytes) throws Exception {
87 final var rawPrivateKey = buildAsymmetricKeyGrouping(publicKeyFormat, publicKeyBytes,
88 privateKeyFormat, privateKeyBytes);
89 ConfigUtils.setAsymmetricKey(keyStore, rawPrivateKey);
90 assertTrue(keyStore.containsAlias(DEFAULT_PRIVATE_KEY_ALIAS));
91 assertTrue(keyStore.isKeyEntry(DEFAULT_PRIVATE_KEY_ALIAS));
92 assertNotNull(keyStore.getKey(DEFAULT_PRIVATE_KEY_ALIAS, EMPTY_SECRET));
95 @ParameterizedTest(name = "End entity certificate: {0}")
96 @MethodSource("asymmetricKeyArgs")
97 void setEndEntityCertificateWithKey(final String testDesc,
98 final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
99 final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes,
100 final byte[] certificateBytes) throws Exception {
101 final var endEntityCert = buildEndEntityCertWithKeyGrouping(publicKeyFormat, publicKeyBytes,
102 privateKeyFormat, privateKeyBytes, certificateBytes);
103 ConfigUtils.setEndEntityCertificateWithKey(keyStore, endEntityCert);
105 assertTrue(keyStore.containsAlias(DEFAULT_PRIVATE_KEY_ALIAS));
106 assertTrue(keyStore.isKeyEntry(DEFAULT_PRIVATE_KEY_ALIAS));
107 assertNotNull(keyStore.getKey(DEFAULT_PRIVATE_KEY_ALIAS, EMPTY_SECRET));
109 assertTrue(keyStore.containsAlias(DEFAULT_CERTIFICATE_ALIAS));
110 assertTrue(keyStore.isCertificateEntry(DEFAULT_CERTIFICATE_ALIAS));
111 assertNotNull(keyStore.getCertificate(DEFAULT_CERTIFICATE_ALIAS));
114 private static Stream<Arguments> asymmetricKeyArgs() throws Exception {
115 // (test case descriptor, public key format, public key bytes, private key format, private key bytes,
116 // certificate bytes)
117 final var rsaCertData = generateX509CertData("RSA");
118 final var ecCertData = generateX509CertData("EC");
120 Arguments.of("RSA / subject-public-key-info",
121 SubjectPublicKeyInfoFormat.VALUE, rsaCertData.publicKey(),
122 RsaPrivateKeyFormat.VALUE, rsaCertData.privateKey(),
123 rsaCertData.certBytes()),
124 Arguments.of("RSA / ssh-public-key",
125 SshPublicKeyFormat.VALUE, rsaCertData.sshPublicKey(),
126 RsaPrivateKeyFormat.VALUE, rsaCertData.privateKey(),
127 rsaCertData.certBytes()),
128 Arguments.of("EC / subject-public-key-info",
129 SubjectPublicKeyInfoFormat.VALUE, ecCertData.publicKey(),
130 EcPrivateKeyFormat.VALUE, ecCertData.privateKey(),
131 ecCertData.certBytes()),
132 Arguments.of("EC / ssh-public-key",
133 SshPublicKeyFormat.VALUE, ecCertData.sshPublicKey(),
134 EcPrivateKeyFormat.VALUE, ecCertData.privateKey(),
135 ecCertData.certBytes())