This is an automated email from the ASF dual-hosted git repository.
RosiKyu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 1b2095125a2 allow EC private keys when uploading a custom certificate
(#14317)
1b2095125a2 is described below
commit 1b2095125a23b4a0505c5917851239be294b11ee
Author: Daman Arora <[email protected]>
AuthorDate: Thu Nov 12 08:04:58 2026 -0500
allow EC private keys when uploading a custom certificate (#14317)
* allow EC private keys when uploading a custom certificate
* say which key types are supported when the private key cannot be read
---
.../cloud/utils/security/CertificateHelper.java | 13 +++-
.../utils/security/CertificateHelperTest.java | 79 ++++++++++++++++++++++
2 files changed, 90 insertions(+), 2 deletions(-)
diff --git
a/utils/src/main/java/com/cloud/utils/security/CertificateHelper.java
b/utils/src/main/java/com/cloud/utils/security/CertificateHelper.java
index b3333620939..486f22c393b 100644
--- a/utils/src/main/java/com/cloud/utils/security/CertificateHelper.java
+++ b/utils/src/main/java/com/cloud/utils/security/CertificateHelper.java
@@ -48,6 +48,8 @@ import java.util.ArrayList;
import java.util.List;
public class CertificateHelper {
+ private static final String[] PRIVATE_KEY_ALGORITHMS = {"RSA", "EC",
"DSA"};
+
public static byte[] buildAndSaveKeystore(final String alias, final String
cert, final String privateKey, final String storePassword) throws
KeyStoreException, CertificateException,
NoSuchAlgorithmException, InvalidKeySpecException, IOException {
Preconditions.checkArgument(StringUtils.isNotEmpty(alias),
"Certificate alias cannot be blank");
@@ -133,9 +135,16 @@ public class CertificateHelper {
public static Key buildPrivateKey(final String base64EncodedKeyContent)
throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
Preconditions.checkNotNull(base64EncodedKeyContent);
- final KeyFactory kf = KeyFactory.getInstance("RSA");
final PKCS8EncodedKeySpec keysp = new
PKCS8EncodedKeySpec(Base64.decodeBase64(base64EncodedKeyContent));
- return kf.generatePrivate(keysp);
+ InvalidKeySpecException lastException = null;
+ for (final String algorithm : PRIVATE_KEY_ALGORITHMS) {
+ try {
+ return
KeyFactory.getInstance(algorithm).generatePrivate(keysp);
+ } catch (final InvalidKeySpecException e) {
+ lastException = e;
+ }
+ }
+ throw new InvalidKeySpecException("Private key is not one of the
supported types: " + String.join(", ", PRIVATE_KEY_ALGORITHMS), lastException);
}
public static List<Certificate> parseChain(final String chain) throws
IOException, CertificateException {
diff --git
a/utils/src/test/java/com/cloud/utils/security/CertificateHelperTest.java
b/utils/src/test/java/com/cloud/utils/security/CertificateHelperTest.java
new file mode 100644
index 00000000000..86c02409625
--- /dev/null
+++ b/utils/src/test/java/com/cloud/utils/security/CertificateHelperTest.java
@@ -0,0 +1,79 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.utils.security;
+
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+
+import org.apache.cloudstack.utils.security.CertUtils;
+import org.apache.commons.codec.binary.Base64;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CertificateHelperTest {
+
+ private static String encodeKey(final KeyPair keyPair) {
+ return Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
+ }
+
+ @Test
+ public void testBuildPrivateKeyRsa() throws Exception {
+ final KeyPair keyPair = CertUtils.generateRandomKeyPair(2048);
+ final Key key = CertificateHelper.buildPrivateKey(encodeKey(keyPair));
+ Assert.assertEquals("RSA", key.getAlgorithm());
+ Assert.assertArrayEquals(keyPair.getPrivate().getEncoded(),
key.getEncoded());
+ }
+
+ @Test
+ public void testBuildPrivateKeyEc() throws Exception {
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+ generator.initialize(256);
+ final KeyPair keyPair = generator.generateKeyPair();
+ final Key key = CertificateHelper.buildPrivateKey(encodeKey(keyPair));
+ Assert.assertEquals("EC", key.getAlgorithm());
+ Assert.assertArrayEquals(keyPair.getPrivate().getEncoded(),
key.getEncoded());
+ }
+
+ @Test
+ public void testBuildPrivateKeyInvalid() throws Exception {
+ try {
+ CertificateHelper.buildPrivateKey(Base64.encodeBase64String("not a
key".getBytes()));
+ Assert.fail("Expected InvalidKeySpecException");
+ } catch (final InvalidKeySpecException e) {
+ Assert.assertEquals("Private key is not one of the supported
types: RSA, EC, DSA", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBuildKeystoreWithEcCertificate() throws Exception {
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+ generator.initialize(256);
+ final KeyPair keyPair = generator.generateKeyPair();
+ final X509Certificate certificate =
CertUtils.generateV3Certificate(null, keyPair, keyPair.getPublic(), "CN=test",
"SHA256withECDSA", 365, null, null);
+
+ final KeyStore ks = CertificateHelper.buildKeystore("test",
CertUtils.x509CertificateToPem(certificate), encodeKey(keyPair), "password");
+ Assert.assertTrue(ks.isKeyEntry("test"));
+ Assert.assertEquals("EC", ks.getKey("test",
"password".toCharArray()).getAlgorithm());
+ }
+}