Skip to content

Commit b0ea02e

Browse files
committed
Allow DSA public keys.
DSA can't be used for encryption with the bouncycastle library, so make sure this situation is properly handled.
1 parent 76d3c27 commit b0ea02e

4 files changed

Lines changed: 143 additions & 41 deletions

File tree

server/src/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -509,18 +509,7 @@ public UserVm resetVMPassword(ResetVMPasswordCmd cmd, String password)
509509
// update the password in vm_details table too
510510
// Check if an SSH key pair was selected for the instance and if so
511511
// use it to encrypt & save the vm password
512-
String sshPublicKey = userVm.getDetail("SSH.PublicKey");
513-
if (sshPublicKey != null && !sshPublicKey.equals("")
514-
&& password != null && !password.equals("saved_password")) {
515-
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(
516-
sshPublicKey, password);
517-
if (encryptedPasswd == null) {
518-
throw new CloudRuntimeException("Error encrypting password");
519-
}
520-
521-
userVm.setDetail("Encrypted.Password", encryptedPasswd);
522-
_vmDao.saveDetails(userVm);
523-
}
512+
encryptAndStorePassword(userVm, password);
524513
} else {
525514
throw new CloudRuntimeException(
526515
"Failed to reset password for the virtual machine ");
@@ -643,13 +632,7 @@ public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd)
643632
if (template != null && template.getEnablePassword()) {
644633
userVm.setPassword(password);
645634
//update the encrypted password in vm_details table too
646-
if (sshPublicKey != null && !sshPublicKey.equals("") && password != null && !password.equals("saved_password")) {
647-
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(sshPublicKey, password);
648-
if (encryptedPasswd == null) {
649-
throw new CloudRuntimeException("Error encrypting password");
650-
}
651-
userVm.setDetail("Encrypted.Password", encryptedPasswd);
652-
}
635+
encryptAndStorePassword(userVm, password);
653636
}
654637
_vmDao.saveDetails(userVm);
655638
} else {
@@ -3304,18 +3287,7 @@ public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMach
33043287

33053288
// Check if an SSH key pair was selected for the instance and if so
33063289
// use it to encrypt & save the vm password
3307-
String sshPublicKey = vm.getDetail("SSH.PublicKey");
3308-
if (sshPublicKey != null && !sshPublicKey.equals("")
3309-
&& password != null && !password.equals("saved_password")) {
3310-
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(
3311-
sshPublicKey, password);
3312-
if (encryptedPasswd == null) {
3313-
throw new CloudRuntimeException("Error encrypting password");
3314-
}
3315-
3316-
vm.setDetail("Encrypted.Password", encryptedPasswd);
3317-
_vmDao.saveDetails(vm);
3318-
}
3290+
encryptAndStorePassword(vm, password);
33193291

33203292
params = new HashMap<VirtualMachineProfile.Param, Object>();
33213293
if (additionalParams != null) {
@@ -4621,15 +4593,7 @@ public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId)
46214593
// update the password in vm_details table too
46224594
// Check if an SSH key pair was selected for the instance and if so
46234595
// use it to encrypt & save the vm password
4624-
String sshPublicKey = vm.getDetail("SSH.PublicKey");
4625-
if (sshPublicKey != null && !sshPublicKey.equals("") && password != null && !password.equals("saved_password")) {
4626-
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(sshPublicKey, password);
4627-
if (encryptedPasswd == null) {
4628-
throw new CloudRuntimeException("VM reset is completed but error occurred when encrypting newly created password");
4629-
}
4630-
vm.setDetail("Encrypted.Password", encryptedPasswd);
4631-
_vmDao.saveDetails(vm);
4632-
}
4596+
encryptAndStorePassword(vm, password);
46334597
} else {
46344598
throw new CloudRuntimeException("VM reset is completed but failed to reset password for the virtual machine ");
46354599
}
@@ -4717,5 +4681,24 @@ public void prepareStop(VirtualMachineProfile<UserVmVO> profile) {
47174681
if (vm.getState() == State.Running)
47184682
collectVmDiskStatistics(vm);
47194683
}
4684+
4685+
private void encryptAndStorePassword(UserVmVO vm, String password) {
4686+
String sshPublicKey = vm.getDetail("SSH.PublicKey");
4687+
if (sshPublicKey != null && !sshPublicKey.equals("")
4688+
&& password != null && !password.equals("saved_password")) {
4689+
if (!sshPublicKey.startsWith("ssh-rsa")) {
4690+
s_logger.warn("Only RSA public keys can be used to encrypt a vm password.");
4691+
return;
4692+
}
4693+
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(
4694+
sshPublicKey, password);
4695+
if (encryptedPasswd == null) {
4696+
throw new CloudRuntimeException("Error encrypting password");
4697+
}
4698+
4699+
vm.setDetail("Encrypted.Password", encryptedPasswd);
4700+
_vmDao.saveDetails(vm);
4701+
}
4702+
}
47204703

47214704
}

utils/src/com/cloud/utils/ssh/SSHKeysHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public static String getPublicKeyFromKeyMaterial(String keyMaterial) {
8282
if (!keyMaterial.contains(" "))
8383
keyMaterial = new String(Base64.decodeBase64(keyMaterial.getBytes()));
8484

85-
if (!keyMaterial.startsWith("ssh-rsa") || !keyMaterial.contains(" "))
85+
if ((!keyMaterial.startsWith("ssh-rsa") && !keyMaterial.startsWith("ssh-dss")) || !keyMaterial.contains(" "))
8686
return null;
8787

8888
String[] key = keyMaterial.split(" ");
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.utils.crypto;
18+
19+
import static org.junit.Assert.*;
20+
21+
import org.junit.Test;
22+
23+
import com.cloud.utils.crypt.RSAHelper;
24+
25+
public class RSAHelperTest {
26+
@Test
27+
public void testEncryptWithRSA() {
28+
String rsaKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2D2Cs0XAEqm+ajJpumIPrMpKp0CWtIW+8ZY2/MJCW" +
29+
"hge1eY18u9I3PPnkMVJsTOaN0wQojjw4AkKgKjNZXA9wyUq56UyN/stmipu8zifWPgxQGDRkuzzZ6buk" +
30+
"ef8q2Awjpo8hv5/0SRPJxQLEafESnUP+Uu/LUwk5VVC7PHzywJRUGFuzDl/uT72+6hqpL2YpC6aTl4/P" +
31+
"2eDvUQhCdL9dBmUSFX8ftT53W1jhsaQl7mPElVgSCtWz3IyRkogobMPrpJW/IPKEiojKIuvNoNv4CDR6" +
32+
"ybeVjHOJMb9wi62rXo+CzUsW0Y4jPOX/OykAm5vrNOhQhw0aaBcv5XVv8BRX";
33+
String encryptedString = RSAHelper.encryptWithSSHPublicKey(rsaKey, "content");
34+
assertNotNull(encryptedString);
35+
}
36+
37+
@Test
38+
public void testEncryptWithDSA() {
39+
String dssKey = "ssh-dss AAAAB3NzaC1kc3MAAACBALbaewDnzZ5AcGbZno7VW1m7Si3Q+yEANXZioVupfSwOP0q9aP2iV"+
40+
"tyqq575JnUVZXMDR2Gr254F/qCJ0TKAvucN0gcd2XslX4jBcu1Z7s7YZf6d7fC58k0NE6/keokJNKhQO" +
41+
"i56iirRzSA/YFrD64mzfq6rEmai0q7GjGGP0RT1AAAAFQDO5++6JonyqnoRkV9Yl1OaEOPjVwAAAIAYA" +
42+
"tqtKtU/INlTIuL3wt3nyKzwPUnz3fqxP5Ger3OlRZsOahalTFt2OF5jGGmCunyBTRteOetZObr0QhUIF" +
43+
"4bSDr6UiYYYbH1ES0ws/t1mDIeTh3UUHV1QYACN6c07FKyKLMtB9AthiG2FMLKCEedG3NeXItuNzsuQD" +
44+
"+n/K1rzMAAAAIBi5SM4pFPiB7BvTZvARV56vrG5QNgWVazSwbwgl/EACiWYbRauHDUQA9f+Rq+ayWcsR" +
45+
"os1CD+Q81y9SmlQaZVKkSPZLxXfu5bi3s4o431xjilhZdt4vKbj2pK364IjghJPNBBfmRXzlj9awKxr/" +
46+
"UebZcBgNRyeky7VZSbbF2jQSQ==";
47+
String encryptedString = RSAHelper.encryptWithSSHPublicKey(dssKey, "content");
48+
assertNull(encryptedString);
49+
}
50+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.utils.ssh;
18+
19+
import static org.junit.Assert.*;
20+
21+
import org.junit.Test;
22+
23+
public class SSHKeysHelperTest {
24+
@Test
25+
public void rsaKeyTest() {
26+
String rsaKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2D2Cs0XAEqm+ajJpumIPrMpKp0CWtIW+8ZY2/MJCW" +
27+
"hge1eY18u9I3PPnkMVJsTOaN0wQojjw4AkKgKjNZXA9wyUq56UyN/stmipu8zifWPgxQGDRkuzzZ6buk" +
28+
"ef8q2Awjpo8hv5/0SRPJxQLEafESnUP+Uu/LUwk5VVC7PHzywJRUGFuzDl/uT72+6hqpL2YpC6aTl4/P" +
29+
"2eDvUQhCdL9dBmUSFX8ftT53W1jhsaQl7mPElVgSCtWz3IyRkogobMPrpJW/IPKEiojKIuvNoNv4CDR6" +
30+
"ybeVjHOJMb9wi62rXo+CzUsW0Y4jPOX/OykAm5vrNOhQhw0aaBcv5XVv8BRX test@testkey";
31+
String storedRsaKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2D2Cs0XAEqm+ajJpumIPrMpKp0CWtIW+8ZY2/MJCW" +
32+
"hge1eY18u9I3PPnkMVJsTOaN0wQojjw4AkKgKjNZXA9wyUq56UyN/stmipu8zifWPgxQGDRkuzzZ6buk" +
33+
"ef8q2Awjpo8hv5/0SRPJxQLEafESnUP+Uu/LUwk5VVC7PHzywJRUGFuzDl/uT72+6hqpL2YpC6aTl4/P" +
34+
"2eDvUQhCdL9dBmUSFX8ftT53W1jhsaQl7mPElVgSCtWz3IyRkogobMPrpJW/IPKEiojKIuvNoNv4CDR6" +
35+
"ybeVjHOJMb9wi62rXo+CzUsW0Y4jPOX/OykAm5vrNOhQhw0aaBcv5XVv8BRX";
36+
String parsedKey = SSHKeysHelper.getPublicKeyFromKeyMaterial(rsaKey);
37+
String fingerprint = SSHKeysHelper.getPublicKeyFingerprint(parsedKey);
38+
39+
assertTrue(storedRsaKey.equals(parsedKey));
40+
assertTrue("f6:96:3f:f4:78:f7:80:11:6c:f8:e3:2b:40:20:f1:14".equals(fingerprint));
41+
42+
}
43+
44+
@Test
45+
public void dsaKeyTest() {
46+
String dssKey = "ssh-dss AAAAB3NzaC1kc3MAAACBALbaewDnzZ5AcGbZno7VW1m7Si3Q+yEANXZioVupfSwOP0q9aP2iV"+
47+
"tyqq575JnUVZXMDR2Gr254F/qCJ0TKAvucN0gcd2XslX4jBcu1Z7s7YZf6d7fC58k0NE6/keokJNKhQO" +
48+
"i56iirRzSA/YFrD64mzfq6rEmai0q7GjGGP0RT1AAAAFQDO5++6JonyqnoRkV9Yl1OaEOPjVwAAAIAYA" +
49+
"tqtKtU/INlTIuL3wt3nyKzwPUnz3fqxP5Ger3OlRZsOahalTFt2OF5jGGmCunyBTRteOetZObr0QhUIF" +
50+
"4bSDr6UiYYYbH1ES0ws/t1mDIeTh3UUHV1QYACN6c07FKyKLMtB9AthiG2FMLKCEedG3NeXItuNzsuQD" +
51+
"+n/K1rzMAAAAIBi5SM4pFPiB7BvTZvARV56vrG5QNgWVazSwbwgl/EACiWYbRauHDUQA9f+Rq+ayWcsR" +
52+
"os1CD+Q81y9SmlQaZVKkSPZLxXfu5bi3s4o431xjilhZdt4vKbj2pK364IjghJPNBBfmRXzlj9awKxr/" +
53+
"UebZcBgNRyeky7VZSbbF2jQSQ== test key";
54+
String storedDssKey = "ssh-dss AAAAB3NzaC1kc3MAAACBALbaewDnzZ5AcGbZno7VW1m7Si3Q+yEANXZioVupfSwOP0q9aP2iV"+
55+
"tyqq575JnUVZXMDR2Gr254F/qCJ0TKAvucN0gcd2XslX4jBcu1Z7s7YZf6d7fC58k0NE6/keokJNKhQO" +
56+
"i56iirRzSA/YFrD64mzfq6rEmai0q7GjGGP0RT1AAAAFQDO5++6JonyqnoRkV9Yl1OaEOPjVwAAAIAYA" +
57+
"tqtKtU/INlTIuL3wt3nyKzwPUnz3fqxP5Ger3OlRZsOahalTFt2OF5jGGmCunyBTRteOetZObr0QhUIF" +
58+
"4bSDr6UiYYYbH1ES0ws/t1mDIeTh3UUHV1QYACN6c07FKyKLMtB9AthiG2FMLKCEedG3NeXItuNzsuQD" +
59+
"+n/K1rzMAAAAIBi5SM4pFPiB7BvTZvARV56vrG5QNgWVazSwbwgl/EACiWYbRauHDUQA9f+Rq+ayWcsR" +
60+
"os1CD+Q81y9SmlQaZVKkSPZLxXfu5bi3s4o431xjilhZdt4vKbj2pK364IjghJPNBBfmRXzlj9awKxr/" +
61+
"UebZcBgNRyeky7VZSbbF2jQSQ==";
62+
String parsedKey = SSHKeysHelper.getPublicKeyFromKeyMaterial(dssKey);
63+
String fingerprint = SSHKeysHelper.getPublicKeyFingerprint(parsedKey);
64+
65+
assertTrue(storedDssKey.equals(parsedKey));
66+
assertTrue("fc:6e:ef:31:93:f8:92:2b:a9:03:c7:06:90:f5:ec:bb".equals(fingerprint));
67+
68+
}
69+
}

0 commit comments

Comments
 (0)