comparison keyimport.c @ 1659:d32bcb5c557d

Add Ed25519 support (#91) * Add support for Ed25519 as a public key type Ed25519 is a elliptic curve signature scheme that offers better security than ECDSA and DSA and good performance. It may be used for both user and host keys. OpenSSH key import and fuzzer are not supported yet. Initially inspired by Peter Szabo. * Add curve25519 and ed25519 fuzzers * Add import and export of Ed25519 keys
author Vladislav Grishenko <themiron@users.noreply.github.com>
date Wed, 11 Mar 2020 21:09:45 +0500
parents 315fcba6960e
children ba6fc7afe1c5
comparison
equal deleted inserted replaced
1658:7402218141d4 1659:d32bcb5c557d
33 #include "keyimport.h" 33 #include "keyimport.h"
34 #include "bignum.h" 34 #include "bignum.h"
35 #include "buffer.h" 35 #include "buffer.h"
36 #include "dbutil.h" 36 #include "dbutil.h"
37 #include "ecc.h" 37 #include "ecc.h"
38 #include "ssh.h"
39
40 static const unsigned char OSSH_PKEY_BLOB[] =
41 "openssh-key-v1\0" /* AUTH_MAGIC */
42 "\0\0\0\4none" /* cipher name*/
43 "\0\0\0\4none" /* kdf name */
44 "\0\0\0\0" /* kdf */
45 "\0\0\0\1"; /* key num */
46 #define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
38 47
39 #if DROPBEAR_ECDSA 48 #if DROPBEAR_ECDSA
40 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; 49 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
41 static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22}; 50 static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
42 static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23}; 51 static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
350 359
351 /* ---------------------------------------------------------------------- 360 /* ----------------------------------------------------------------------
352 * Code to read and write OpenSSH private keys. 361 * Code to read and write OpenSSH private keys.
353 */ 362 */
354 363
355 enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; 364 enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY };
356 struct openssh_key { 365 struct openssh_key {
357 int type; 366 int type;
358 int encrypted; 367 int encrypted;
359 char iv[32]; 368 char iv[32];
360 unsigned char *keyblob; 369 unsigned char *keyblob;
362 }; 371 };
363 372
364 static struct openssh_key *load_openssh_key(const char *filename) 373 static struct openssh_key *load_openssh_key(const char *filename)
365 { 374 {
366 struct openssh_key *ret; 375 struct openssh_key *ret;
376 buffer *buf = NULL;
367 FILE *fp = NULL; 377 FILE *fp = NULL;
368 char buffer[256]; 378 char buffer[256];
369 char *errmsg = NULL, *p = NULL; 379 char *errmsg = NULL, *p = NULL;
370 int headers_done; 380 int headers_done;
371 unsigned long len, outlen; 381 unsigned long len;
372 382
373 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); 383 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key));
374 ret->keyblob = NULL; 384 ret->keyblob = NULL;
375 ret->keyblob_len = ret->keyblob_size = 0; 385 ret->keyblob_len = ret->keyblob_size = 0;
376 ret->encrypted = 0; 386 ret->encrypted = 0;
395 ret->type = OSSH_RSA; 405 ret->type = OSSH_RSA;
396 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) 406 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
397 ret->type = OSSH_DSA; 407 ret->type = OSSH_DSA;
398 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) 408 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
399 ret->type = OSSH_EC; 409 ret->type = OSSH_EC;
410 else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n"))
411 ret->type = OSSH_PKEY;
400 else { 412 else {
401 errmsg = "Unrecognised key type"; 413 errmsg = "Unrecognised key type";
402 goto error; 414 goto error;
403 } 415 }
404 416
405 headers_done = 0; 417 headers_done = 0;
418 buf = buf_new(0);
406 while (1) { 419 while (1) {
407 if (!fgets(buffer, sizeof(buffer), fp)) { 420 if (!fgets(buffer, sizeof(buffer), fp)) {
408 errmsg = "Unexpected end of file"; 421 errmsg = "Unexpected end of file";
409 goto error; 422 goto error;
410 } 423 }
446 } 459 }
447 } 460 }
448 } else { 461 } else {
449 headers_done = 1; 462 headers_done = 1;
450 len = strlen(buffer); 463 len = strlen(buffer);
451 outlen = len*4/3; 464 buf = buf_resize(buf, buf->size + len);
452 if (ret->keyblob_len + outlen > ret->keyblob_size) { 465 buf_putbytes(buf, buffer, len);
453 ret->keyblob_size = ret->keyblob_len + outlen + 256; 466 }
454 ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, 467 }
455 ret->keyblob_size); 468
456 } 469 if (buf && buf->len) {
457 outlen = ret->keyblob_size - ret->keyblob_len; 470 ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256;
458 if (base64_decode((const unsigned char *)buffer, len, 471 ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size);
459 ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ 472 len = ret->keyblob_size;
460 errmsg = "Error decoding base64"; 473 if (base64_decode((const unsigned char *)buf->data, buf->len,
461 goto error; 474 ret->keyblob, &len) != CRYPT_OK){
462 } 475 errmsg = "Error decoding base64";
463 ret->keyblob_len += outlen; 476 goto error;
464 } 477 }
478 ret->keyblob_len = len;
479 }
480
481 if (ret->type == OSSH_PKEY) {
482 if (ret->keyblob_len < OSSH_PKEY_BLOBLEN ||
483 memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) {
484 errmsg = "Error decoding OpenSSH key";
485 goto error;
486 }
487 ret->keyblob_len -= OSSH_PKEY_BLOBLEN;
488 memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len);
465 } 489 }
466 490
467 if (ret->keyblob_len == 0 || !ret->keyblob) { 491 if (ret->keyblob_len == 0 || !ret->keyblob) {
468 errmsg = "Key body not present"; 492 errmsg = "Key body not present";
469 goto error; 493 goto error;
472 if (ret->encrypted && ret->keyblob_len % 8 != 0) { 496 if (ret->encrypted && ret->keyblob_len % 8 != 0) {
473 errmsg = "Encrypted key blob is not a multiple of cipher block size"; 497 errmsg = "Encrypted key blob is not a multiple of cipher block size";
474 goto error; 498 goto error;
475 } 499 }
476 500
501 if (buf) {
502 buf_burn(buf);
503 buf_free(buf);
504 }
477 m_burn(buffer, sizeof(buffer)); 505 m_burn(buffer, sizeof(buffer));
478 return ret; 506 return ret;
479 507
480 error: 508 error:
509 if (buf) {
510 buf_burn(buf);
511 buf_free(buf);
512 }
481 m_burn(buffer, sizeof(buffer)); 513 m_burn(buffer, sizeof(buffer));
482 if (ret) { 514 if (ret) {
483 if (ret->keyblob) { 515 if (ret->keyblob) {
484 m_burn(ret->keyblob, ret->keyblob_size); 516 m_burn(ret->keyblob, ret->keyblob_size);
485 m_free(ret->keyblob); 517 m_free(ret->keyblob);
565 key->keyblob, key->keyblob_len); 597 key->keyblob, key->keyblob_len);
566 598
567 memset(&md5c, 0, sizeof(md5c)); 599 memset(&md5c, 0, sizeof(md5c));
568 memset(keybuf, 0, sizeof(keybuf)); 600 memset(keybuf, 0, sizeof(keybuf));
569 #endif 601 #endif
602 }
603
604 /*
605 * Now we have a decrypted key blob, which contains OpenSSH
606 * encoded private key. We must now untangle the OpenSSH format.
607 */
608 if (key->type == OSSH_PKEY) {
609 blobbuf = buf_new(key->keyblob_len);
610 buf_putbytes(blobbuf, key->keyblob, key->keyblob_len);
611 buf_setpos(blobbuf, 0);
612
613 /* limit length of private key blob */
614 len = buf_getint(blobbuf);
615 buf_setlen(blobbuf, blobbuf->pos + len);
616
617 type = DROPBEAR_SIGNKEY_ANY;
618 if (buf_get_pub_key(blobbuf, retkey, &type)
619 != DROPBEAR_SUCCESS) {
620 errmsg = "Error parsing OpenSSH key";
621 goto ossh_error;
622 }
623
624 /* restore full length */
625 buf_setlen(blobbuf, key->keyblob_len);
626
627 if (type != DROPBEAR_SIGNKEY_NONE) {
628 retkey->type = type;
629 /* limit length of private key blob */
630 len = buf_getint(blobbuf);
631 buf_setlen(blobbuf, blobbuf->pos + len);
632 #if DROPBEAR_ED25519
633 if (type == DROPBEAR_SIGNKEY_ED25519) {
634 buf_incrpos(blobbuf, 8);
635 buf_eatstring(blobbuf);
636 buf_eatstring(blobbuf);
637 buf_incrpos(blobbuf, -SSH_SIGNKEY_ED25519_LEN-4);
638 if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key)
639 == DROPBEAR_SUCCESS) {
640 errmsg = NULL;
641 retval = retkey;
642 goto error;
643 }
644 }
645 #endif
646 }
647
648 errmsg = "Unsupported OpenSSH key type";
649 ossh_error:
650 sign_key_free(retkey);
651 retkey = NULL;
652 goto error;
570 } 653 }
571 654
572 /* 655 /*
573 * Now we have a decrypted key blob, which contains an ASN.1 656 * Now we have a decrypted key blob, which contains an ASN.1
574 * encoded private key. We must now untangle the ASN.1. 657 * encoded private key. We must now untangle the ASN.1.
1124 buf_free(seq_buf); 1207 buf_free(seq_buf);
1125 seq_buf = NULL; 1208 seq_buf = NULL;
1126 1209
1127 header = "-----BEGIN EC PRIVATE KEY-----\n"; 1210 header = "-----BEGIN EC PRIVATE KEY-----\n";
1128 footer = "-----END EC PRIVATE KEY-----\n"; 1211 footer = "-----END EC PRIVATE KEY-----\n";
1212 }
1213 #endif
1214
1215 #if DROPBEAR_ED25519
1216 if (key->type == DROPBEAR_SIGNKEY_ED25519) {
1217 buffer *buf = buf_new(300);
1218 keyblob = buf_new(100);
1219 extrablob = buf_new(200);
1220
1221 /* private key blob w/o header */
1222 buf_put_priv_key(keyblob, key, key->type);
1223 buf_setpos(keyblob, 0);
1224 buf_incrpos(keyblob, buf_getint(keyblob));
1225 len = buf_getint(keyblob);
1226
1227 /* header */
1228 buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
1229
1230 /* public key */
1231 buf_put_pub_key(buf, key, key->type);
1232
1233 /* private key */
1234 buf_incrwritepos(extrablob, 4);
1235 buf_put_pub_key(extrablob, key, key->type);
1236 buf_putstring(extrablob, buf_getptr(keyblob, len), len);
1237 /* comment */
1238 buf_putstring(extrablob, "", 0);
1239 /* padding to cipher block length */
1240 len = (extrablob->len+8) & ~7;
1241 for (i = 1; len - extrablob->len > 0; i++)
1242 buf_putbyte(extrablob, i);
1243 buf_setpos(extrablob, 0);
1244 buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8);
1245 buf_putbufstring(buf, extrablob);
1246
1247 outlen = len = pos = buf->len;
1248 outblob = (unsigned char*)m_malloc(outlen);
1249 memcpy(outblob, buf->data, buf->len);
1250
1251 buf_burn(buf);
1252 buf_free(buf);
1253 buf = NULL;
1254
1255 header = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
1256 footer = "-----END OPENSSH PRIVATE KEY-----\n";
1129 } 1257 }
1130 #endif 1258 #endif
1131 1259
1132 /* 1260 /*
1133 * Padding on OpenSSH keys is deterministic. The number of 1261 * Padding on OpenSSH keys is deterministic. The number of