comparison keyimport.c @ 1908:eadd023fde4d

Support RSA OpenSSH new format in dropbearconvert Added support for reading and writing. PEM writing support has been removed. OpenSSH file format routines have been moved to signkey_ossh.c
author Matt Johnston <matt@ucc.asn.au>
date Tue, 29 Mar 2022 22:27:55 +0800
parents 3e0aacf0a4f3
children ced53051e200
comparison
equal deleted inserted replaced
1907:3e0aacf0a4f3 1908:eadd023fde4d
37 #include "ecc.h" 37 #include "ecc.h"
38 #include "ssh.h" 38 #include "ssh.h"
39 #include "rsa.h" 39 #include "rsa.h"
40 #include "dss.h" 40 #include "dss.h"
41 #include "ed25519.h" 41 #include "ed25519.h"
42 #include "signkey_ossh.h"
42 43
43 static const unsigned char OSSH_PKEY_BLOB[] = 44 static const unsigned char OSSH_PKEY_BLOB[] =
44 "openssh-key-v1\0" /* AUTH_MAGIC */ 45 "openssh-key-v1\0" /* AUTH_MAGIC */
45 "\0\0\0\4none" /* cipher name*/ 46 "\0\0\0\4none" /* cipher name*/
46 "\0\0\0\4none" /* kdf name */ 47 "\0\0\0\4none" /* kdf name */
47 "\0\0\0\0" /* kdf */ 48 "\0\0\0\0" /* kdf */
48 "\0\0\0\1"; /* key num */ 49 "\0\0\0\1"; /* key num */
49 #define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1) 50 #define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
50
51 void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey);
52 int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey);
53
54 #if DROPBEAR_ECDSA 51 #if DROPBEAR_ECDSA
55 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; 52 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
56 static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22}; 53 static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
57 static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23}; 54 static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
58 #endif 55 #endif
569 566
570 if (!key) 567 if (!key)
571 return NULL; 568 return NULL;
572 569
573 if (key->encrypted) { 570 if (key->encrypted) {
574 errmsg = "encrypted keys not supported currently"; 571 errmsg = "Encrypted keys are not supported. Please convert with ssh-keygen first";
575 goto error; 572 goto error;
576 #if 0
577 /* matt TODO */
578 /*
579 * Derive encryption key from passphrase and iv/salt:
580 *
581 * - let block A equal MD5(passphrase || iv)
582 * - let block B equal MD5(A || passphrase || iv)
583 * - block C would be MD5(B || passphrase || iv) and so on
584 * - encryption key is the first N bytes of A || B
585 */
586 struct MD5Context md5c;
587 unsigned char keybuf[32];
588
589 MD5Init(&md5c);
590 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
591 MD5Update(&md5c, (unsigned char *)key->iv, 8);
592 MD5Final(keybuf, &md5c);
593
594 MD5Init(&md5c);
595 MD5Update(&md5c, keybuf, 16);
596 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
597 MD5Update(&md5c, (unsigned char *)key->iv, 8);
598 MD5Final(keybuf+16, &md5c);
599
600 /*
601 * Now decrypt the key blob.
602 */
603 des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
604 key->keyblob, key->keyblob_len);
605
606 memset(&md5c, 0, sizeof(md5c));
607 memset(keybuf, 0, sizeof(keybuf));
608 #endif
609 } 573 }
610 574
611 /* 575 /*
612 * Now we have a decrypted key blob, which contains OpenSSH 576 * Now we have a decrypted key blob, which contains OpenSSH
613 * encoded private key. We must now untangle the OpenSSH format. 577 * encoded private key. We must now untangle the OpenSSH format.
638 /* discard checkkey2 */ 602 /* discard checkkey2 */
639 buf_getint(blobbuf); 603 buf_getint(blobbuf);
640 604
641 if (type != DROPBEAR_SIGNKEY_NONE) { 605 if (type != DROPBEAR_SIGNKEY_NONE) {
642 retkey->type = type; 606 retkey->type = type;
607 #if DROPBEAR_RSA
608 if (type == DROPBEAR_SIGNKEY_RSA) {
609 if (buf_get_rsa_priv_ossh(blobbuf, retkey)
610 == DROPBEAR_SUCCESS) {
611 errmsg = NULL;
612 retval = retkey;
613 goto error;
614 } else {
615 errmsg = "Error parsing OpenSSH RSA key";
616 goto ossh_error;
617 }
618 }
619 #endif
643 #if DROPBEAR_ED25519 620 #if DROPBEAR_ED25519
644 if (type == DROPBEAR_SIGNKEY_ED25519) { 621 if (type == DROPBEAR_SIGNKEY_ED25519) {
645 if (buf_get_ed25519_priv_ossh(blobbuf, retkey) 622 if (buf_get_ed25519_priv_ossh(blobbuf, retkey)
646 == DROPBEAR_SUCCESS) { 623 == DROPBEAR_SUCCESS) {
647 errmsg = NULL; 624 errmsg = NULL;
648 retval = retkey; 625 retval = retkey;
649 goto error; 626 goto error;
627 } else {
628 errmsg = "Error parsing OpenSSH ed25519 key";
629 goto ossh_error;
650 } 630 }
651 } 631 }
652 #endif 632 #endif
653 } 633 }
654 634
915 fprintf(stderr, "Error: %s\n", errmsg); 895 fprintf(stderr, "Error: %s\n", errmsg);
916 } 896 }
917 return retval; 897 return retval;
918 } 898 }
919 899
920 #if DROPBEAR_ED25519
921 /* OpenSSH raw private ed25519 format is
922 string "ssh-ed25519"
923 uint32 32
924 byte[32] pubkey
925 uint32 64
926 byte[32] privkey
927 byte[32] pubkey
928 */
929
930 void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey) {
931 const dropbear_ed25519_key *key = akey->ed25519key;
932 dropbear_assert(key != NULL);
933 buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
934 buf_putint(buf, CURVE25519_LEN);
935 buf_putbytes(buf, key->pub, CURVE25519_LEN);
936 buf_putint(buf, CURVE25519_LEN*2);
937 buf_putbytes(buf, key->priv, CURVE25519_LEN);
938 buf_putbytes(buf, key->pub, CURVE25519_LEN);
939 }
940
941 int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
942 dropbear_ed25519_key *key = akey->ed25519key;
943 uint32_t len;
944
945 dropbear_assert(key != NULL);
946
947 /* Parse past the first string and pubkey */
948 if (buf_get_ed25519_pub_key(buf, key, DROPBEAR_SIGNKEY_ED25519)
949 == DROPBEAR_FAILURE) {
950 dropbear_log(LOG_ERR, "Error parsing ed25519 key, pubkey");
951 return DROPBEAR_FAILURE;
952 }
953 len = buf_getint(buf);
954 if (len != 2*CURVE25519_LEN) {
955 dropbear_log(LOG_ERR, "Error parsing ed25519 key, bad length");
956 return DROPBEAR_FAILURE;
957 }
958 memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
959 buf_incrpos(buf, CURVE25519_LEN);
960
961 /* Sanity check */
962 if (memcmp(buf_getptr(buf, CURVE25519_LEN), key->pub,
963 CURVE25519_LEN) != 0) {
964 dropbear_log(LOG_ERR, "Error parsing ed25519 key, mismatch pubkey");
965 return DROPBEAR_FAILURE;
966 }
967 return DROPBEAR_SUCCESS;
968 }
969 #endif
970
971 static int openssh_write(const char *filename, sign_key *key, 900 static int openssh_write(const char *filename, sign_key *key,
972 const char *passphrase) 901 const char *passphrase)
973 { 902 {
974 buffer * keyblob = NULL; 903 buffer * keyblob = NULL;
975 buffer * extrablob = NULL; /* used for calculated values to write */ 904 buffer * extrablob = NULL; /* used for calculated values to write */
980 char *header = NULL, *footer = NULL; 909 char *header = NULL, *footer = NULL;
981 char zero[1]; 910 char zero[1];
982 int ret = 0; 911 int ret = 0;
983 FILE *fp; 912 FILE *fp;
984 913
985 #if DROPBEAR_RSA
986 mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
987 #endif
988
989 if ( 914 if (
990 #if DROPBEAR_RSA
991 key->type == DROPBEAR_SIGNKEY_RSA ||
992 #endif
993 #if DROPBEAR_DSS 915 #if DROPBEAR_DSS
994 key->type == DROPBEAR_SIGNKEY_DSS || 916 key->type == DROPBEAR_SIGNKEY_DSS ||
995 #endif 917 #endif
996 0) 918 0)
997 { 919 {
1009 * Find the sequence of integers to be encoded into the OpenSSH 931 * Find the sequence of integers to be encoded into the OpenSSH
1010 * key blob, and also decide on the header line. 932 * key blob, and also decide on the header line.
1011 */ 933 */
1012 numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; 934 numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
1013 935
1014 #if DROPBEAR_RSA
1015 if (key->type == DROPBEAR_SIGNKEY_RSA) {
1016
1017 if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
1018 fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
1019 goto error;
1020 }
1021
1022 /* e */
1023 numbers[2].bytes = buf_getint(keyblob);
1024 numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
1025 buf_incrpos(keyblob, numbers[2].bytes);
1026
1027 /* n */
1028 numbers[1].bytes = buf_getint(keyblob);
1029 numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
1030 buf_incrpos(keyblob, numbers[1].bytes);
1031
1032 /* d */
1033 numbers[3].bytes = buf_getint(keyblob);
1034 numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
1035 buf_incrpos(keyblob, numbers[3].bytes);
1036
1037 /* p */
1038 numbers[4].bytes = buf_getint(keyblob);
1039 numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
1040 buf_incrpos(keyblob, numbers[4].bytes);
1041
1042 /* q */
1043 numbers[5].bytes = buf_getint(keyblob);
1044 numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
1045 buf_incrpos(keyblob, numbers[5].bytes);
1046
1047 /* now calculate some extra parameters: */
1048 m_mp_init(&tmpval);
1049 m_mp_init(&dmp1);
1050 m_mp_init(&dmq1);
1051 m_mp_init(&iqmp);
1052
1053 /* dmp1 = d mod (p-1) */
1054 if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
1055 fprintf(stderr, "Bignum error for p-1\n");
1056 goto error;
1057 }
1058 if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
1059 fprintf(stderr, "Bignum error for dmp1\n");
1060 goto error;
1061 }
1062
1063 /* dmq1 = d mod (q-1) */
1064 if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
1065 fprintf(stderr, "Bignum error for q-1\n");
1066 goto error;
1067 }
1068 if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
1069 fprintf(stderr, "Bignum error for dmq1\n");
1070 goto error;
1071 }
1072
1073 /* iqmp = (q^-1) mod p */
1074 if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
1075 fprintf(stderr, "Bignum error for iqmp\n");
1076 goto error;
1077 }
1078
1079 extrablob = buf_new(2000);
1080 buf_putmpint(extrablob, &dmp1);
1081 buf_putmpint(extrablob, &dmq1);
1082 buf_putmpint(extrablob, &iqmp);
1083 buf_setpos(extrablob, 0);
1084 mp_clear(&dmp1);
1085 mp_clear(&dmq1);
1086 mp_clear(&iqmp);
1087 mp_clear(&tmpval);
1088
1089 /* dmp1 */
1090 numbers[6].bytes = buf_getint(extrablob);
1091 numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
1092 buf_incrpos(extrablob, numbers[6].bytes);
1093
1094 /* dmq1 */
1095 numbers[7].bytes = buf_getint(extrablob);
1096 numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
1097 buf_incrpos(extrablob, numbers[7].bytes);
1098
1099 /* iqmp */
1100 numbers[8].bytes = buf_getint(extrablob);
1101 numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
1102 buf_incrpos(extrablob, numbers[8].bytes);
1103
1104 nnumbers = 9;
1105 header = "-----BEGIN RSA PRIVATE KEY-----\n";
1106 footer = "-----END RSA PRIVATE KEY-----\n";
1107 }
1108 #endif /* DROPBEAR_RSA */
1109
1110 #if DROPBEAR_DSS 936 #if DROPBEAR_DSS
1111 if (key->type == DROPBEAR_SIGNKEY_DSS) { 937 if (key->type == DROPBEAR_SIGNKEY_DSS) {
1112 938
1113 /* p */ 939 /* p */
1114 numbers[1].bytes = buf_getint(keyblob); 940 numbers[1].bytes = buf_getint(keyblob);
1172 for (i = 0; i < nnumbers; i++) { 998 for (i = 0; i < nnumbers; i++) {
1173 pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0); 999 pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
1174 memcpy(outblob+pos, numbers[i].start, numbers[i].bytes); 1000 memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
1175 pos += numbers[i].bytes; 1001 pos += numbers[i].bytes;
1176 } 1002 }
1177 } /* end RSA and DSS handling */ 1003 } /* end DSS handling */
1178 1004
1179 #if DROPBEAR_ECDSA 1005 #if DROPBEAR_ECDSA
1180 if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 1006 if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
1181 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 1007 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
1182 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { 1008 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
1271 header = "-----BEGIN EC PRIVATE KEY-----\n"; 1097 header = "-----BEGIN EC PRIVATE KEY-----\n";
1272 footer = "-----END EC PRIVATE KEY-----\n"; 1098 footer = "-----END EC PRIVATE KEY-----\n";
1273 } 1099 }
1274 #endif 1100 #endif
1275 1101
1102 if (0
1103 #if DROPBEAR_RSA
1104 || key->type == DROPBEAR_SIGNKEY_RSA
1105 #endif
1276 #if DROPBEAR_ED25519 1106 #if DROPBEAR_ED25519
1277 if (key->type == DROPBEAR_SIGNKEY_ED25519) { 1107 || key->type == DROPBEAR_SIGNKEY_ED25519
1278 buffer *buf = buf_new(1200); 1108 #endif
1279 keyblob = buf_new(1000); 1109 ) {
1280 extrablob = buf_new(1100); 1110 buffer *buf = buf_new(3200);
1111 keyblob = buf_new(3000);
1112 extrablob = buf_new(3100);
1281 1113
1282 /* private key blob w/o header */ 1114 /* private key blob w/o header */
1283 buf_put_ed25519_priv_ossh(keyblob, key); 1115 #if DROPBEAR_RSA
1116 if (key->type == DROPBEAR_SIGNKEY_RSA) {
1117 buf_put_rsa_priv_ossh(keyblob, key);
1118 }
1119 #endif
1120 #if DROPBEAR_ED25519
1121 if (key->type == DROPBEAR_SIGNKEY_ED25519) {
1122 buf_put_ed25519_priv_ossh(keyblob, key);
1123 }
1124 #endif
1284 1125
1285 /* header */ 1126 /* header */
1286 buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN); 1127 buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
1287 1128
1288 /* public key */ 1129 /* public key */
1312 buf = NULL; 1153 buf = NULL;
1313 1154
1314 header = "-----BEGIN OPENSSH PRIVATE KEY-----\n"; 1155 header = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
1315 footer = "-----END OPENSSH PRIVATE KEY-----\n"; 1156 footer = "-----END OPENSSH PRIVATE KEY-----\n";
1316 } 1157 }
1317 #endif
1318 1158
1319 /* 1159 /*
1320 * Padding on OpenSSH keys is deterministic. The number of 1160 * Padding on OpenSSH keys is deterministic. The number of
1321 * padding bytes is always more than zero, and always at most 1161 * padding bytes is always more than zero, and always at most
1322 * the cipher block length. The value of each padding byte is 1162 * the cipher block length. The value of each padding byte is