Mercurial > dropbear
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++) |