package org.ovirt.engine.core.uutils.ssh;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
public class OpenSSHUtilsTest {
private static PublicKey decodeKey(final String encoding) throws Exception {
final byte[] bytes = Base64.decodeBase64(encoding);
final KeyFactory factory = KeyFactory.getInstance("RSA");
final X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
return factory.generatePublic(spec);
}
private static void testFingerprintString(final String keyEncoding, final String goodFingerprintString, String algo)
throws Exception {
final PublicKey key = decodeKey(keyEncoding);
final String fingerprintString = OpenSSHUtils.getKeyFingerprint(key, algo);
assertEquals(goodFingerprintString, fingerprintString);
StringBuilder actual = new StringBuilder();
assertTrue(OpenSSHUtils.checkKeyFingerprint(goodFingerprintString, key, actual));
assertEquals(goodFingerprintString, actual.toString());
}
@Test
public void testFingerprintStrings() throws Exception {
for (String[] key : KEYS) {
testFingerprintString(key[0], key[1], "MD5");
testFingerprintString(key[0], key[2], "SHA-256");
}
}
@Test
public void testFingerprintStringsMD5() throws Exception {
assertTrue(OpenSSHUtils.checkKeyFingerprint(KEYS[0][1].replace("MD5:", ""), decodeKey(KEYS[0][0]), null));
}
private static void testKeyString(final String keyEncoding, final String goodKeyString) throws Exception {
final PublicKey key = decodeKey(keyEncoding);
final String keyString = OpenSSHUtils.getKeyString(key, null);
assertEquals(goodKeyString, keyString);
assertEquals(key, OpenSSHUtils.decodeKeyString(keyString));
}
@Test
public void testKeyStrings() throws Exception {
for (String[] key : KEYS) {
testKeyString(key[0], key[3]);
}
}
@Test
public void testGoodKeyIsPublicKeyValid() throws Exception {
for (String[] key : KEYS) {
assertTrue(OpenSSHUtils.isPublicKeyValid(key[3]));
}
}
@Test
public void testBadKeyNotIsPublicKeyValid() throws Exception {
for (String key : BAD_SSH_KEYS) {
assertFalse(OpenSSHUtils.isPublicKeyValid(key));
}
}
@Test
public void testNotRsaKeyIsPublicKeyValid() throws Exception {
for (String key : EXTRA_SSH_KEYS) {
assertTrue(OpenSSHUtils.isPublicKeyValid(key));
}
}
@Test
public void testMutliKeys() throws Exception {
assertTrue(OpenSSHUtils.arePublicKeysValid(EXTRA_SSH_KEYS[0] + "\n" + EXTRA_SSH_KEYS[1] + "\n"));
assertTrue(OpenSSHUtils.arePublicKeysValid(EXTRA_SSH_KEYS[0] + "\n" + EXTRA_SSH_KEYS[1]));
assertTrue(OpenSSHUtils.arePublicKeysValid(EXTRA_SSH_KEYS[0] + "\n"));
assertTrue(OpenSSHUtils.arePublicKeysValid(EXTRA_SSH_KEYS[0]));
}
/**
* This test data has been generated as follows:
*
* <pre>
* # Generate a self signed certificate:
* # Generate a dummy self signed certificate:
* keytool \
* -keystore test.jks \
* -genkey \
* -alias test \
* -keyalg rsa \
* -keysize 1024 \
* -keypass test \
* -storepass test \
* -dname cn=test
*
* # Export the certificate:
* keytool \
* -keystore test.jks \
* -rfc \
* -export \
* -storepass password \
* -alias test \
* -file test.pem
*
* # Extract the public key:
* openssl x509 -noout -in test.pem -pubkey > test.tmp
*
* # Convert the public key to ssh format:
* ssh-keygen -i -m pkcs8 -f test.tmp > test.ssh
*
* # Generate the fingerprint:
* ssh-keygen -f test.ssh -l > test.fp
* </pre>
*/
private static final String[][] KEYS = {
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCa3+YrPFsT7orhMQx0VIs+xqj/" +
"zcVBN6zLv2lzIZIW/sDQ+sKmZKIT4wWj0GIW8ShD2dW3QNS/18GSq/MXeaih9kUJ" +
"2Mx+DapWIHxEhDR2fBAlQgxB9/+XyNzSxWwrrNFox7tlvNmCEqN5HxdBR5fxqw4O" +
"ODNh3JfzLcVNzqDsqwIDAQAB",
// Fingerprint MD5
"MD5:16:e1:9e:89:1e:ed:cc:3d:d8:af:d1:83:6e:b0:da:ae",
// Fingerprint SHA256
"SHA256:I4ud9yJLWcxsanCu0bXL6SxjTxj9/wbPi4JqtR1ophw",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCa3+YrPFsT7orhMQx0VIs+xqj/zcVBN6zLv2lzIZIW/sDQ+sKmZKIT4wWj0GIW8ShD2dW3QNS/18GSq/MXeaih9kUJ2Mx+DapWIHxEhDR2fBAlQgxB9/+XyNzSxWwrrNFox7tlvNmCEqN5HxdBR5fxqw4OODNh3JfzLcVNzqDsqw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCP5HriASnFNB0PqE9M/QLMR2kB" +
"bcD7v/4yVsvosyIHw4cpRdfWTsqZAYgMHnwSsvDWTPhx6XCmyx/41pjR4H0bLINh" +
"qjbpQUjSwiDrXTLUiU4MJcDAFsFWabbj3cZksVSTuqxR6ljdXMLJd8lrJXz1mLi1" +
"gYKAEfF6MbwzZwcwhwIDAQAB",
// Fingerprint MD5
"MD5:a2:55:07:d3:b6:69:7c:ca:8f:33:e7:22:f2:12:48:d9",
// Fingerprint SHA256
"SHA256:5xWt5k1RhhX+EHqhzLxlqEW50QxiBIN2ng78SFbf2Rk",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCP5HriASnFNB0PqE9M/QLMR2kBbcD7v/4yVsvosyIHw4cpRdfWTsqZAYgMHnwSsvDWTPhx6XCmyx/41pjR4H0bLINhqjbpQUjSwiDrXTLUiU4MJcDAFsFWabbj3cZksVSTuqxR6ljdXMLJd8lrJXz1mLi1gYKAEfF6MbwzZwcwhw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5AkL8nfbs0ANq1MGQL9WYISuQ" +
"8NtYMZ7MiH/7af0Mvy5K1nDUysqZt0BFP2Yd9/bScyxdgSp7jux//i2UVINrVFCn" +
"B5JOzCzO79d3W5glGavSiUqaqOXBLfCFNcNhmJvKVhFAXyJ4JM3v2e8Dg/PtBT73" +
"5+YCSkrnZOSr+if8GwIDAQAB",
// Fingerprint MD5
"MD5:0e:82:e9:96:e7:b1:35:2b:c0:14:49:09:1c:8d:80:ee",
// Fingerprint SHA256
"SHA256:KLeBSl0NAL6T1Z8EEqsvpW1c3y9mtVGmogUNxIuL9is",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC5AkL8nfbs0ANq1MGQL9WYISuQ8NtYMZ7MiH/7af0Mvy5K1nDUysqZt0BFP2Yd9/bScyxdgSp7jux//i2UVINrVFCnB5JOzCzO79d3W5glGavSiUqaqOXBLfCFNcNhmJvKVhFAXyJ4JM3v2e8Dg/PtBT735+YCSkrnZOSr+if8Gw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCRYaSHFlFePROfmsj82O6KMCW3" +
"wMlF93ifYXA8T1b87AybzORNhR49uCi9jccEpEcRzOmC9lpHYt3iouGCtFfrBWgR" +
"Pv1i4Iln5gqJFbaT9/48Zli3AraKbVWBJQeDKQL0EywU0sXz2upN0OMwyehQAZsa" +
"9KWvwt2LV2c8cbMprwIDAQAB",
// Fingerprint MD5
"MD5:b0:d1:fc:40:95:39:25:20:c4:3f:7b:b8:6f:18:4d:ae",
// Fingerprint SHA256
"SHA256:hDXnC4yi0dCY8uqtecpi7x3qPk4hwetfZigGpwoMrCo",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCRYaSHFlFePROfmsj82O6KMCW3wMlF93ifYXA8T1b87AybzORNhR49uCi9jccEpEcRzOmC9lpHYt3iouGCtFfrBWgRPv1i4Iln5gqJFbaT9/48Zli3AraKbVWBJQeDKQL0EywU0sXz2upN0OMwyehQAZsa9KWvwt2LV2c8cbMprw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMJJqXjfcpxpb3VPUXvWl+4R2K" +
"qf5piN3YNwIbBQiZobSnvoY7oMPVFBh0AW1DJa3VD0JOSRqcYn+zbo3/mEln7+/Z" +
"DXYWsZY1/UgL9QNl0PrrugWKzQfU1lB7T+TFJQNeYH4xUtORGdnfO+uMTK9h2yC/" +
"uCMvqv3dLKR1SGRzEQIDAQAB",
// Fingerprint MD5
"MD5:56:c1:e3:c5:bc:75:21:00:67:65:c2:06:39:82:bf:9f",
// Fingerprint SHA256
"SHA256:tO9ZbfmciAOQYdr/yk5+EGeEW51jBmMM/bDhc2Y47x8",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDMJJqXjfcpxpb3VPUXvWl+4R2Kqf5piN3YNwIbBQiZobSnvoY7oMPVFBh0AW1DJa3VD0JOSRqcYn+zbo3/mEln7+/ZDXYWsZY1/UgL9QNl0PrrugWKzQfU1lB7T+TFJQNeYH4xUtORGdnfO+uMTK9h2yC/uCMvqv3dLKR1SGRzEQ==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHlrWc38JjFHNvZ7gs6MOlvrFL" +
"F2K+U8CHkqV+7/WFCszZGeJPo9va9uIjdVD7RHYKOiOt2r6xulO/RRjxY4h8coU9" +
"rNVUmaCRUcsqclJpVURFrLUbdIn4fGMVnxeFrI+cKW34A9JFu4cGbZ2s7eOQNBJT" +
"LKktR9T/nxc8D9H+/wIDAQAB",
// Fingerprint MD5
"MD5:55:d5:de:fc:17:d4:b1:06:22:73:67:f5:e0:08:bf:25",
// Fingerprint SHA256
"SHA256:GtqEmRC7wauTPZcuI14NeyIq/OBRIZfO8A5IoFyCWl8",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDHlrWc38JjFHNvZ7gs6MOlvrFLF2K+U8CHkqV+7/WFCszZGeJPo9va9uIjdVD7RHYKOiOt2r6xulO/RRjxY4h8coU9rNVUmaCRUcsqclJpVURFrLUbdIn4fGMVnxeFrI+cKW34A9JFu4cGbZ2s7eOQNBJTLKktR9T/nxc8D9H+/w==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYDKTQXJWxY5GNtQyz40osYjui" +
"aqP5B+C0xN8lteW/zrQ9rwyZ+ijm15uY0vH4gggpn5oYkIbu/5mrk7cNan5Ygs5M" +
"VP7QfQ6OSV1c8alckmAA4aFjq84O3dRIM4Vj97FwiENuzcLsBSlPxU4WFhKNrLEL" +
"NNuIVKPltQVnJUA0AwIDAQAB",
// Fingerprint MD5
"MD5:23:90:4e:18:11:fc:44:f8:4a:3e:5b:f3:a7:3c:cb:14",
// Fingerprint SHA256
"SHA256:FmRM9fOZfn3yAkik/vE799kR0msftllHsxWh4WK+WDU",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCYDKTQXJWxY5GNtQyz40osYjuiaqP5B+C0xN8lteW/zrQ9rwyZ+ijm15uY0vH4gggpn5oYkIbu/5mrk7cNan5Ygs5MVP7QfQ6OSV1c8alckmAA4aFjq84O3dRIM4Vj97FwiENuzcLsBSlPxU4WFhKNrLELNNuIVKPltQVnJUA0Aw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbfXqtv9/jI022H5t4T9qI3oBB" +
"aLFBSLx2J/MP4XQ32L5/arQIyiu25mPNwcnwo7h1teCVr722TS2m8Sg9TXWwnd13" +
"l5VwwKqOrlOVhi3lj6ljpWBI/viBMMJNOeG1K4x8ZO1x6L3h8UtmIU599VqjpaPg" +
"wQNFlOweUqh4h0sRtwIDAQAB",
// Fingerprint MD5
"MD5:61:a8:d6:8d:ca:27:86:50:ad:5f:de:1e:a6:17:c0:42",
// Fingerprint SHA256
"SHA256:N0jkalb2Z9nK/tjmYlfECOiTSOVP/OSRHmHmj1BOePk",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCbfXqtv9/jI022H5t4T9qI3oBBaLFBSLx2J/MP4XQ32L5/arQIyiu25mPNwcnwo7h1teCVr722TS2m8Sg9TXWwnd13l5VwwKqOrlOVhi3lj6ljpWBI/viBMMJNOeG1K4x8ZO1x6L3h8UtmIU599VqjpaPgwQNFlOweUqh4h0sRtw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJmCyxIsgvYvhymxcqZF0eX3bL" +
"/IA26Ygr4hZ+Q4NidYXZZ3cYOJvgdj8zoJu/+I3jW2re0Kltj+BqHssWD1WIO2rX" +
"0/1UZP95KRlCLfa8Nnqi889NNpUhvHJnfBqzbyBbgDFDMZoi2NVEx9nUpZRr8e6D" +
"1rA4kS4jQURTLODjrwIDAQAB",
// Fingerprint MD5
"MD5:37:49:1d:28:20:98:1a:da:e7:29:b3:96:61:2b:f1:40",
// Fingerprint SHA256
"SHA256:OQfj4/W7qD5rfqy81+2gUiX+cPdlVGWupfxZ5Z6GGIM",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDJmCyxIsgvYvhymxcqZF0eX3bL/IA26Ygr4hZ+Q4NidYXZZ3cYOJvgdj8zoJu/+I3jW2re0Kltj+BqHssWD1WIO2rX0/1UZP95KRlCLfa8Nnqi889NNpUhvHJnfBqzbyBbgDFDMZoi2NVEx9nUpZRr8e6D1rA4kS4jQURTLODjrw==\n",
},
{
// Key:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3Cz4oruqQv9fz+NOZnhvGugWv" +
"Ppuwh44aGVdYm0iXJZCq76bgw0ajDF6XhVs5xYagWEO31vVKVu7lTMIv7OcoAw3V" +
"C3giBDJotkkXO7uR3iAQAGZrARxRrOOhUNqVKIuslw/+YcvgsQl5TdgflvrdH2zQ" +
"yVm2/0qLjdCN8lYahwIDAQAB",
// Fingerprint MD5
"MD5:6d:cd:bc:99:c0:83:ca:b1:8e:58:10:c3:b8:4d:56:ee",
// Fingerprint SHA256
"SHA256:pbpMFSx/C7wm34+zg3ky8ALQytzn1QzDOYE1ohHWGWw",
// SSH:
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC3Cz4oruqQv9fz+NOZnhvGugWvPpuwh44aGVdYm0iXJZCq76bgw0ajDF6XhVs5xYagWEO31vVKVu7lTMIv7OcoAw3VC3giBDJotkkXO7uR3iAQAGZrARxRrOOhUNqVKIuslw/+YcvgsQl5TdgflvrdH2zQyVm2/0qLjdCN8lYahw==\n",
},
};
private static final String[] EXTRA_SSH_KEYS = {
// DSA
"ssh-dss AAAAB3NzaC1kc3MAAACBAMIf8c7Sv8j/NwXIzTLByHrB24cFexOJkTxFv+HMoBdgzr8BAIQojpIRq9z0xm9HJgWGR6Njla1wEEJVC2rj+XP8el4+doTo1jfgAPZIZBeh80PvnX6dgm/JkKNLgAeHZqEFa68UmOk+vOio/Z2guPam93Yt3MAlVHSYMKrylXI9AAAAFQCJDsrpr6isE/BVGn/4utGX5EArRwAAAIA/hLqJPr00s4uORq49c8jegg+Zqgawpf9fnnI4PUelhG+tGDzW7aWwVYntMvkQNBbG8oww7GCQFTuAbPSU/RNh4HUZTlWFJq47RVGtEtPTYmR0dMloMwQTmxP8ObTFRPoR+NX3XLcOCuXHUW6MExpbL7RD9IiZK9xMXU4oop0wEgAAAIBY+WxFurd0VchCJWPFbXkqUxGQ0VPvxOAcBlf+rGs+hmHMQYc792b+AEml6t2UzXTX1tIh0W5q++65sIPDC7jVRfrrSEn+mtM3/N+p36902dtyRzvp0UMv/Kq/IIiwSZPn5FBHATj0ssb9wSb9uYNLvcigMThKrAbNlCdSE5In8g== ",
// DSA with third field
"ssh-dss AAAAB3NzaC1kc3MAAACBAMIf8c7Sv8j/NwXIzTLByHrB24cFexOJkTxFv+HMoBdgzr8BAIQojpIRq9z0xm9HJgWGR6Njla1wEEJVC2rj+XP8el4+doTo1jfgAPZIZBeh80PvnX6dgm/JkKNLgAeHZqEFa68UmOk+vOio/Z2guPam93Yt3MAlVHSYMKrylXI9AAAAFQCJDsrpr6isE/BVGn/4utGX5EArRwAAAIA/hLqJPr00s4uORq49c8jegg+Zqgawpf9fnnI4PUelhG+tGDzW7aWwVYntMvkQNBbG8oww7GCQFTuAbPSU/RNh4HUZTlWFJq47RVGtEtPTYmR0dMloMwQTmxP8ObTFRPoR+NX3XLcOCuXHUW6MExpbL7RD9IiZK9xMXU4oop0wEgAAAIBY+WxFurd0VchCJWPFbXkqUxGQ0VPvxOAcBlf+rGs+hmHMQYc792b+AEml6t2UzXTX1tIh0W5q++65sIPDC7jVRfrrSEn+mtM3/N+p36902dtyRzvp0UMv/Kq/IIiwSZPn5FBHATj0ssb9wSb9uYNLvcigMThKrAbNlCdSE5In8g== test@ovirt.org",
// ECDSA
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHUkn6B7HOUceagWGLynYOHZ4QtH/OhHc5URksntfUrSbxMQNKfws1aVgzymFqFrninzcyBgaHOcG/LK+U2EwXU= ",
// ECDSA with third field
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHUkn6B7HOUceagWGLynYOHZ4QtH/OhHc5URksntfUrSbxMQNKfws1aVgzymFqFrninzcyBgaHOcG/LK+U2EwXU= test@ovirt.org",
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHUkn6B7HOUceagWGLynYOHZ4QtH/OhHc5URksntfUrSbxMQNKfws1aVgzymFqFrninzcyBgaHOcG/LK+U2EwXU= test@ovirt.org\n",
};
private static final String[] BAD_SSH_KEYS = {
// RSA with broken identifier (first field)
"1RandomTextWith2NumbersWithin",
"ssh%rsa%corrupted AAAAB3NzaC1yc2EAAAADAQABAAAAgQC3Cz4oruqQv9fz+NOZnhvGugWvPpuwh44aGVdYm0iXJZCq76bgw0ajDF6XhVs5xYagWEO31vVKVu7lTMIv7OcoAw3VC3giBDJotkkXO7uR3iAQAGZrARxRrOOhUNqVKIuslw/+YcvgsQl5TdgflvrdH2zQyVm2/0qLjdCN8lYahw==\n",
// RSA with not-base64 data
"ssh-rsa \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHUkn6B7HOUceagWGLynYOHZ4QtH/OhHc5URksntfUrSbxMQNKfws1aVgzymFqFrninzcyBgaHOcG/LK+U2EwXU= test@ovirt.org\nadasd",
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHUkn6B7HOUceagWGLynYOHZ4QtH/OhHc5URksntfUrSbxMQNKfws1aVgzymFqFrninzcyBgaHOcG/LK+U2EwXU= test@ovirt.org\nadasd\n",
};
}