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.buildLocalOrTruststore;
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.rev221212.EcPrivateKeyFormat;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.PrivateKeyFormat;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.PublicKeyFormat;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.RsaPrivateKeyFormat;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.SshPublicKeyFormat;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev221212.SubjectPublicKeyInfoFormat;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.client.rev221212.tls.client.grouping.server.authentication.CaCerts;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.client.rev221212.tls.client.grouping.server.authentication.CaCertsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.client.rev221212.tls.client.grouping.server.authentication.EeCerts;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tls.client.rev221212.tls.client.grouping.server.authentication.EeCertsBuilder;
45 class ConfigUtilsTest {
47 private KeyStore keyStore;
50 void setup() throws Exception {
51 keyStore = KeyStoreUtils.newKeyStore();
55 void setX509Certificates() throws Exception {
56 final var rsaCertData = generateX509CertData("RSA");
57 final var ecCertData = generateX509CertData("EC");
59 // not defined -- ignore
60 ConfigUtils.setX509Certificates(keyStore, null, null);
61 assertFalse(keyStore.aliases().hasMoreElements());
64 final var localOrTruststore = buildLocalOrTruststore(
65 Map.of("cert-rsa", rsaCertData.certBytes(), "cert-ec", ecCertData.certBytes()));
66 final CaCerts caCerts = new CaCertsBuilder().setLocalOrTruststore(localOrTruststore).build();
67 final EeCerts eeCerts = new EeCertsBuilder().setLocalOrTruststore(localOrTruststore).build();
68 ConfigUtils.setX509Certificates(keyStore, caCerts, eeCerts);
70 final List<String> aliases = Collections.list(keyStore.aliases());
71 final Set<String> expectedAliases = Set.of("ca-cert-rsa", "ca-cert-ec", "ee-cert-rsa", "ee-cert-ec");
72 assertNotNull(aliases);
73 assertEquals(4, aliases.size());
74 assertEquals(expectedAliases, Set.copyOf(aliases));
75 for (String alias : aliases) {
76 assertTrue(keyStore.isCertificateEntry(alias));
77 assertNotNull(keyStore.getCertificate(alias));
81 @ParameterizedTest(name = "Set private key from pair: {0}")
82 @MethodSource("asymmetricKeyArgs")
84 // raw public key is not implemented yet
85 void setPrivateKeyFromKeyPair(final String testDesc,
86 final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
87 final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes,
88 final byte[] certificateBytes) throws Exception {
89 final var rawPrivateKey = buildAsymmetricKeyGrouping(publicKeyFormat, publicKeyBytes,
90 privateKeyFormat, privateKeyBytes);
91 ConfigUtils.setAsymmetricKey(keyStore, rawPrivateKey);
92 assertTrue(keyStore.containsAlias(DEFAULT_PRIVATE_KEY_ALIAS));
93 assertTrue(keyStore.isKeyEntry(DEFAULT_PRIVATE_KEY_ALIAS));
94 assertNotNull(keyStore.getKey(DEFAULT_PRIVATE_KEY_ALIAS, EMPTY_SECRET));
97 @ParameterizedTest(name = "End entity certificate: {0}")
98 @MethodSource("asymmetricKeyArgs")
99 void setEndEntityCertificateWithKey(final String testDesc,
100 final PublicKeyFormat publicKeyFormat, final byte[] publicKeyBytes,
101 final PrivateKeyFormat privateKeyFormat, final byte[] privateKeyBytes,
102 final byte[] certificateBytes) throws Exception {
103 final var endEntityCert = buildEndEntityCertWithKeyGrouping(publicKeyFormat, publicKeyBytes,
104 privateKeyFormat, privateKeyBytes, certificateBytes);
105 ConfigUtils.setEndEntityCertificateWithKey(keyStore, endEntityCert);
107 assertTrue(keyStore.containsAlias(DEFAULT_PRIVATE_KEY_ALIAS));
108 assertTrue(keyStore.isKeyEntry(DEFAULT_PRIVATE_KEY_ALIAS));
109 assertNotNull(keyStore.getKey(DEFAULT_PRIVATE_KEY_ALIAS, EMPTY_SECRET));
111 assertTrue(keyStore.containsAlias(DEFAULT_CERTIFICATE_ALIAS));
112 assertTrue(keyStore.isCertificateEntry(DEFAULT_CERTIFICATE_ALIAS));
113 assertNotNull(keyStore.getCertificate(DEFAULT_CERTIFICATE_ALIAS));
116 private static Stream<Arguments> asymmetricKeyArgs() throws Exception {
117 // (test case descriptor, public key format, public key bytes, private key format, private key bytes,
118 // certificate bytes)
119 final var rsaCertData = generateX509CertData("RSA");
120 final var ecCertData = generateX509CertData("EC");
122 Arguments.of("RSA / subject-public-key-info",
123 SubjectPublicKeyInfoFormat.VALUE, rsaCertData.publicKey(),
124 RsaPrivateKeyFormat.VALUE, rsaCertData.privateKey(),
125 rsaCertData.certBytes()),
126 Arguments.of("RSA / ssh-public-key",
127 SshPublicKeyFormat.VALUE, rsaCertData.sshPublicKey(),
128 RsaPrivateKeyFormat.VALUE, rsaCertData.privateKey(),
129 rsaCertData.certBytes()),
130 Arguments.of("EC / subject-public-key-info",
131 SubjectPublicKeyInfoFormat.VALUE, ecCertData.publicKey(),
132 EcPrivateKeyFormat.VALUE, ecCertData.privateKey(),
133 ecCertData.certBytes()),
134 Arguments.of("EC / ssh-public-key",
135 SshPublicKeyFormat.VALUE, ecCertData.sshPublicKey(),
136 EcPrivateKeyFormat.VALUE, ecCertData.privateKey(),
137 ecCertData.certBytes())