comparison keyimport.c @ 1907:3e0aacf0a4f3

Fix ed25519 dropbear to openssh conversion This introduces buf_put_ed25519_priv_ossh and buf_get_ed25519_priv_ossh to handle OpenSSH internal private key format. Previously writing OpenSSH format keys didn't write the private part correctly.
author Matt Johnston <matt@ucc.asn.au>
date Tue, 29 Mar 2022 16:46:06 +0800
parents 064f5be2fc45
children eadd023fde4d
comparison
equal deleted inserted replaced
1906:46f68ace1c3c 1907:3e0aacf0a4f3
46 "\0\0\0\4none" /* kdf name */ 46 "\0\0\0\4none" /* kdf name */
47 "\0\0\0\0" /* kdf */ 47 "\0\0\0\0" /* kdf */
48 "\0\0\0\1"; /* key num */ 48 "\0\0\0\1"; /* key num */
49 #define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1) 49 #define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
50 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
51 #if DROPBEAR_ECDSA 54 #if DROPBEAR_ECDSA
52 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; 55 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
53 static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22}; 56 static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
54 static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23}; 57 static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
55 #endif 58 #endif
367 enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY }; 370 enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY };
368 struct openssh_key { 371 struct openssh_key {
369 int type; 372 int type;
370 int encrypted; 373 int encrypted;
371 char iv[32]; 374 char iv[32];
375 /* keyblob is publickey1 onwards (ref OpenSSH PROTOCOL.key) */
372 unsigned char *keyblob; 376 unsigned char *keyblob;
373 unsigned int keyblob_len, keyblob_size; 377 unsigned int keyblob_len, keyblob_size;
374 }; 378 };
375 379
376 static struct openssh_key *load_openssh_key(const char *filename) 380 static struct openssh_key *load_openssh_key(const char *filename)
599 des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, 603 des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
600 key->keyblob, key->keyblob_len); 604 key->keyblob, key->keyblob_len);
601 605
602 memset(&md5c, 0, sizeof(md5c)); 606 memset(&md5c, 0, sizeof(md5c));
603 memset(keybuf, 0, sizeof(keybuf)); 607 memset(keybuf, 0, sizeof(keybuf));
604 #endif 608 #endif
605 } 609 }
606 610
607 /* 611 /*
608 * Now we have a decrypted key blob, which contains OpenSSH 612 * Now we have a decrypted key blob, which contains OpenSSH
609 * encoded private key. We must now untangle the OpenSSH format. 613 * encoded private key. We must now untangle the OpenSSH format.
611 if (key->type == OSSH_PKEY) { 615 if (key->type == OSSH_PKEY) {
612 blobbuf = buf_new(key->keyblob_len); 616 blobbuf = buf_new(key->keyblob_len);
613 buf_putbytes(blobbuf, key->keyblob, key->keyblob_len); 617 buf_putbytes(blobbuf, key->keyblob, key->keyblob_len);
614 buf_setpos(blobbuf, 0); 618 buf_setpos(blobbuf, 0);
615 619
616 /* limit length of private key blob */ 620 /* limit length of public key blob */
617 len = buf_getint(blobbuf); 621 len = buf_getint(blobbuf);
618 buf_setlen(blobbuf, blobbuf->pos + len);
619 622
620 type = DROPBEAR_SIGNKEY_ANY; 623 type = DROPBEAR_SIGNKEY_ANY;
621 if (buf_get_pub_key(blobbuf, retkey, &type) 624 if (buf_get_pub_key(blobbuf, retkey, &type)
622 != DROPBEAR_SUCCESS) { 625 != DROPBEAR_SUCCESS) {
623 errmsg = "Error parsing OpenSSH key"; 626 errmsg = "Error parsing OpenSSH key";
625 } 628 }
626 629
627 /* restore full length */ 630 /* restore full length */
628 buf_setlen(blobbuf, key->keyblob_len); 631 buf_setlen(blobbuf, key->keyblob_len);
629 632
633 /* length of private key part. we can discard it */
634 buf_getint(blobbuf);
635
636 /* discard checkkey1 */
637 buf_getint(blobbuf);
638 /* discard checkkey2 */
639 buf_getint(blobbuf);
640
630 if (type != DROPBEAR_SIGNKEY_NONE) { 641 if (type != DROPBEAR_SIGNKEY_NONE) {
631 retkey->type = type; 642 retkey->type = type;
632 /* limit length of private key blob */
633 len = buf_getint(blobbuf);
634 buf_setlen(blobbuf, blobbuf->pos + len);
635 #if DROPBEAR_ED25519 643 #if DROPBEAR_ED25519
636 if (type == DROPBEAR_SIGNKEY_ED25519) { 644 if (type == DROPBEAR_SIGNKEY_ED25519) {
637 buf_incrpos(blobbuf, 8); 645 if (buf_get_ed25519_priv_ossh(blobbuf, retkey)
638 buf_eatstring(blobbuf); 646 == DROPBEAR_SUCCESS) {
639 buf_eatstring(blobbuf);
640 buf_decrpos(blobbuf, SSH_SIGNKEY_ED25519_LEN+4);
641 if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key)
642 == DROPBEAR_SUCCESS) {
643 errmsg = NULL; 647 errmsg = NULL;
644 retval = retkey; 648 retval = retkey;
645 goto error; 649 goto error;
646 } 650 }
647 } 651 }
911 fprintf(stderr, "Error: %s\n", errmsg); 915 fprintf(stderr, "Error: %s\n", errmsg);
912 } 916 }
913 return retval; 917 return retval;
914 } 918 }
915 919
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
916 static int openssh_write(const char *filename, sign_key *key, 971 static int openssh_write(const char *filename, sign_key *key,
917 const char *passphrase) 972 const char *passphrase)
918 { 973 {
919 buffer * keyblob = NULL; 974 buffer * keyblob = NULL;
920 buffer * extrablob = NULL; /* used for calculated values to write */ 975 buffer * extrablob = NULL; /* used for calculated values to write */
1218 } 1273 }
1219 #endif 1274 #endif
1220 1275
1221 #if DROPBEAR_ED25519 1276 #if DROPBEAR_ED25519
1222 if (key->type == DROPBEAR_SIGNKEY_ED25519) { 1277 if (key->type == DROPBEAR_SIGNKEY_ED25519) {
1223 buffer *buf = buf_new(300); 1278 buffer *buf = buf_new(1200);
1224 keyblob = buf_new(100); 1279 keyblob = buf_new(1000);
1225 extrablob = buf_new(200); 1280 extrablob = buf_new(1100);
1226 1281
1227 /* private key blob w/o header */ 1282 /* private key blob w/o header */
1228 buf_put_priv_key(keyblob, key, key->type); 1283 buf_put_ed25519_priv_ossh(keyblob, key);
1229 buf_setpos(keyblob, 0);
1230 buf_incrpos(keyblob, buf_getint(keyblob));
1231 len = buf_getint(keyblob);
1232 1284
1233 /* header */ 1285 /* header */
1234 buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN); 1286 buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
1235 1287
1236 /* public key */ 1288 /* public key */
1237 buf_put_pub_key(buf, key, key->type); 1289 buf_put_pub_key(buf, key, key->type);
1238 1290
1239 /* private key */ 1291 /* private key */
1240 buf_incrwritepos(extrablob, 4); 1292 buf_putint(extrablob, 0); /* checkint 1 */
1241 buf_put_pub_key(extrablob, key, key->type); 1293 buf_putint(extrablob, 0); /* checkint 2 */
1242 buf_putstring(extrablob, buf_getptr(keyblob, len), len); 1294 /* raw openssh private key */
1295 buf_putbytes(extrablob, keyblob->data, keyblob->len);
1243 /* comment */ 1296 /* comment */
1244 buf_putstring(extrablob, "", 0); 1297 buf_putstring(extrablob, "", 0);
1245 /* padding to cipher block length */ 1298 /* padding to cipher block length */
1246 len = (extrablob->len+8) & ~7; 1299 len = (extrablob->len+8) & ~7;
1247 for (i = 1; len - extrablob->len > 0; i++) 1300 for (i = 1; len - extrablob->len > 0; i++)