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());
+    }
+}

Reply via email to