Copilot commented on code in PR #12708:
URL: https://github.com/apache/cloudstack/pull/12708#discussion_r2853087050


##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }

Review Comment:
   This method should check if keyPair is null before attempting to access it. 
If the constructor's key generation failed (caught exception at line 51), 
keyPair will be null and this will throw a NullPointerException. Consider 
adding a null check and either throwing a more descriptive exception or 
returning a meaningful error.



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }
 
-    public String getPrivateKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePrivateKey(baos);
+    private static void writeString(ByteArrayOutputStream out, String str) 
throws Exception {
+        byte[] data = str.getBytes("UTF-8");
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
+
+    private static void writeBigInt(ByteArrayOutputStream out, BigInteger 
value) throws Exception {
+        byte[] data = value.toByteArray();
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
 
-        return baos.toString();
+    public String getPrivateKey() {
+        try {
+            return CertUtils.privateKeyToPem(keyPair.getPrivate());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }

Review Comment:
   The new implementation of getPrivateKey that uses CertUtils.privateKeyToPem 
is not covered by tests. Consider adding a test that creates an SSHKeysHelper 
instance, generates a key pair, retrieves both public and private keys, and 
validates that the private key in PEM format can be correctly parsed and used 
to decrypt data encrypted with the corresponding public key.



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }
 
-    public String getPrivateKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePrivateKey(baos);
+    private static void writeString(ByteArrayOutputStream out, String str) 
throws Exception {
+        byte[] data = str.getBytes("UTF-8");
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
+
+    private static void writeBigInt(ByteArrayOutputStream out, BigInteger 
value) throws Exception {
+        byte[] data = value.toByteArray();
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }

Review Comment:
   These helper methods declare throwing a generic Exception which is not a 
best practice. Consider declaring more specific exceptions (e.g., IOException, 
UnsupportedEncodingException) or using StandardCharsets.UTF_8 instead of the 
hardcoded "UTF-8" string to avoid UnsupportedEncodingException entirely.



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }
 
-    public String getPrivateKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePrivateKey(baos);
+    private static void writeString(ByteArrayOutputStream out, String str) 
throws Exception {
+        byte[] data = str.getBytes("UTF-8");
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
+
+    private static void writeBigInt(ByteArrayOutputStream out, BigInteger 
value) throws Exception {
+        byte[] data = value.toByteArray();
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
 
-        return baos.toString();
+    public String getPrivateKey() {
+        try {
+            return CertUtils.privateKeyToPem(keyPair.getPrivate());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }

Review Comment:
   This method catches a generic Exception and uses printStackTrace instead of 
proper logging. Following the codebase convention, a Logger field should be 
added to the class and used here with LOGGER.error.



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }
 
-    public String getPrivateKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePrivateKey(baos);
+    private static void writeString(ByteArrayOutputStream out, String str) 
throws Exception {
+        byte[] data = str.getBytes("UTF-8");
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
+
+    private static void writeBigInt(ByteArrayOutputStream out, BigInteger 
value) throws Exception {
+        byte[] data = value.toByteArray();
+        out.write(ByteBuffer.allocate(4).putInt(data.length).array());
+        out.write(data);
+    }
 
-        return baos.toString();
+    public String getPrivateKey() {
+        try {
+            return CertUtils.privateKeyToPem(keyPair.getPrivate());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }

Review Comment:
   This method should check if keyPair is null before attempting to access it. 
If the constructor's key generation failed, keyPair will be null and this will 
throw a NullPointerException at line 142. Consider adding a null check and 
proper error handling.



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -45,8 +47,8 @@ private static String toHexString(byte[] b) {
 
     public SSHKeysHelper(Integer keyLength) {
         try {
-            keyPair = KeyPair.genKeyPair(new JSch(), KeyPair.RSA, keyLength);
-        } catch (JSchException e) {
+            keyPair = CertUtils.generateRandomKeyPair(keyLength);
+        } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
             e.printStackTrace();
         }
     }

Review Comment:
   The constructor catches exceptions and uses printStackTrace without proper 
logging. Following the codebase convention seen in other utility classes (like 
CertUtils, RSAHelper, SSHCmdHelper), this class should have a Logger field and 
use LOGGER.error to log exceptions instead of printStackTrace. Additionally, if 
the keyPair generation fails, it remains null which could cause 
NullPointerException in getPublicKey and getPrivateKey methods.



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }

Review Comment:
   The new implementation of getPublicKey that uses 
CertUtils.generateRandomKeyPair and manually constructs the SSH public key 
format is not covered by tests. The existing tests only verify static methods 
(getPublicKeyFromKeyMaterial and getPublicKeyFingerprint). Consider adding a 
test that creates an SSHKeysHelper instance, generates a key pair, retrieves 
the public key, and validates that it can be correctly parsed back and used for 
encryption (similar to what RSAHelper.encryptWithSSHPublicKey does).



##########
utils/src/main/java/com/cloud/utils/ssh/SSHKeysHelper.java:
##########
@@ -105,17 +107,43 @@ public static String getPublicKeyFromKeyMaterial(String 
keyMaterial) {
     }
 
     public String getPublicKey() {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        keyPair.writePublicKey(baos, "");
+        try {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            writeString(buffer,"ssh-rsa");
+            writeBigInt(buffer, rsaPublicKey.getPublicExponent());
+            writeBigInt(buffer, rsaPublicKey.getModulus());
 
-        return baos.toString();
+            String base64 = Base64.encodeBase64String(buffer.toByteArray());
+
+            return "ssh-rsa " + base64;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
     }

Review Comment:
   This method catches a generic Exception and uses printStackTrace instead of 
proper logging. Following the codebase convention seen in other utility 
classes, a Logger should be added to the class and used here. Also, the broad 
Exception catch masks specific error conditions that could be helpful for 
debugging.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to