Mercurial > dropbear
comparison keyimport.c @ 1733:d529a52b2f7c coverity coverity
merge coverity from main
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 26 Jun 2020 21:07:34 +0800 |
parents | 1051e4eea25a |
children | 064f5be2fc45 |
comparison
equal
deleted
inserted
replaced
1643:b59623a64678 | 1733:d529a52b2f7c |
---|---|
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 #include "rsa.h" | |
40 #include "dss.h" | |
41 #include "ed25519.h" | |
42 | |
43 static const unsigned char OSSH_PKEY_BLOB[] = | |
44 "openssh-key-v1\0" /* AUTH_MAGIC */ | |
45 "\0\0\0\4none" /* cipher name*/ | |
46 "\0\0\0\4none" /* kdf name */ | |
47 "\0\0\0\0" /* kdf */ | |
48 "\0\0\0\1"; /* key num */ | |
49 #define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1) | |
38 | 50 |
39 #if DROPBEAR_ECDSA | 51 #if DROPBEAR_ECDSA |
40 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}; |
41 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}; |
42 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}; |
350 | 362 |
351 /* ---------------------------------------------------------------------- | 363 /* ---------------------------------------------------------------------- |
352 * Code to read and write OpenSSH private keys. | 364 * Code to read and write OpenSSH private keys. |
353 */ | 365 */ |
354 | 366 |
355 enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; | 367 enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY }; |
356 struct openssh_key { | 368 struct openssh_key { |
357 int type; | 369 int type; |
358 int encrypted; | 370 int encrypted; |
359 char iv[32]; | 371 char iv[32]; |
360 unsigned char *keyblob; | 372 unsigned char *keyblob; |
362 }; | 374 }; |
363 | 375 |
364 static struct openssh_key *load_openssh_key(const char *filename) | 376 static struct openssh_key *load_openssh_key(const char *filename) |
365 { | 377 { |
366 struct openssh_key *ret; | 378 struct openssh_key *ret; |
379 buffer *buf = NULL; | |
367 FILE *fp = NULL; | 380 FILE *fp = NULL; |
368 char buffer[256]; | 381 char buffer[256]; |
369 char *errmsg = NULL, *p = NULL; | 382 char *errmsg = NULL, *p = NULL; |
370 int headers_done; | 383 int headers_done; |
371 unsigned long len, outlen; | 384 unsigned long len; |
372 | 385 |
373 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); | 386 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); |
374 ret->keyblob = NULL; | 387 ret->keyblob = NULL; |
375 ret->keyblob_len = ret->keyblob_size = 0; | 388 ret->keyblob_len = ret->keyblob_size = 0; |
376 ret->encrypted = 0; | 389 ret->encrypted = 0; |
395 ret->type = OSSH_RSA; | 408 ret->type = OSSH_RSA; |
396 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) | 409 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) |
397 ret->type = OSSH_DSA; | 410 ret->type = OSSH_DSA; |
398 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) | 411 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) |
399 ret->type = OSSH_EC; | 412 ret->type = OSSH_EC; |
413 else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n")) | |
414 ret->type = OSSH_PKEY; | |
400 else { | 415 else { |
401 errmsg = "Unrecognised key type"; | 416 errmsg = "Unrecognised key type"; |
402 goto error; | 417 goto error; |
403 } | 418 } |
404 | 419 |
405 headers_done = 0; | 420 headers_done = 0; |
421 buf = buf_new(0); | |
406 while (1) { | 422 while (1) { |
407 if (!fgets(buffer, sizeof(buffer), fp)) { | 423 if (!fgets(buffer, sizeof(buffer), fp)) { |
408 errmsg = "Unexpected end of file"; | 424 errmsg = "Unexpected end of file"; |
409 goto error; | 425 goto error; |
410 } | 426 } |
446 } | 462 } |
447 } | 463 } |
448 } else { | 464 } else { |
449 headers_done = 1; | 465 headers_done = 1; |
450 len = strlen(buffer); | 466 len = strlen(buffer); |
451 outlen = len*4/3; | 467 buf = buf_resize(buf, buf->size + len); |
452 if (ret->keyblob_len + outlen > ret->keyblob_size) { | 468 buf_putbytes(buf, buffer, len); |
453 ret->keyblob_size = ret->keyblob_len + outlen + 256; | 469 } |
454 ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, | 470 } |
455 ret->keyblob_size); | 471 |
456 } | 472 if (buf && buf->len) { |
457 outlen = ret->keyblob_size - ret->keyblob_len; | 473 ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256; |
458 if (base64_decode((const unsigned char *)buffer, len, | 474 ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size); |
459 ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ | 475 len = ret->keyblob_size; |
460 errmsg = "Error decoding base64"; | 476 if (base64_decode((const unsigned char *)buf->data, buf->len, |
461 goto error; | 477 ret->keyblob, &len) != CRYPT_OK){ |
462 } | 478 errmsg = "Error decoding base64"; |
463 ret->keyblob_len += outlen; | 479 goto error; |
464 } | 480 } |
481 ret->keyblob_len = len; | |
482 } | |
483 | |
484 if (ret->type == OSSH_PKEY) { | |
485 if (ret->keyblob_len < OSSH_PKEY_BLOBLEN || | |
486 memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) { | |
487 errmsg = "Error decoding OpenSSH key"; | |
488 goto error; | |
489 } | |
490 ret->keyblob_len -= OSSH_PKEY_BLOBLEN; | |
491 memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len); | |
465 } | 492 } |
466 | 493 |
467 if (ret->keyblob_len == 0 || !ret->keyblob) { | 494 if (ret->keyblob_len == 0 || !ret->keyblob) { |
468 errmsg = "Key body not present"; | 495 errmsg = "Key body not present"; |
469 goto error; | 496 goto error; |
472 if (ret->encrypted && ret->keyblob_len % 8 != 0) { | 499 if (ret->encrypted && ret->keyblob_len % 8 != 0) { |
473 errmsg = "Encrypted key blob is not a multiple of cipher block size"; | 500 errmsg = "Encrypted key blob is not a multiple of cipher block size"; |
474 goto error; | 501 goto error; |
475 } | 502 } |
476 | 503 |
504 if (buf) { | |
505 buf_burn(buf); | |
506 buf_free(buf); | |
507 } | |
477 m_burn(buffer, sizeof(buffer)); | 508 m_burn(buffer, sizeof(buffer)); |
478 return ret; | 509 return ret; |
479 | 510 |
480 error: | 511 error: |
512 if (buf) { | |
513 buf_burn(buf); | |
514 buf_free(buf); | |
515 } | |
481 m_burn(buffer, sizeof(buffer)); | 516 m_burn(buffer, sizeof(buffer)); |
482 if (ret) { | 517 if (ret) { |
483 if (ret->keyblob) { | 518 if (ret->keyblob) { |
484 m_burn(ret->keyblob, ret->keyblob_size); | 519 m_burn(ret->keyblob, ret->keyblob_size); |
485 m_free(ret->keyblob); | 520 m_free(ret->keyblob); |
565 key->keyblob, key->keyblob_len); | 600 key->keyblob, key->keyblob_len); |
566 | 601 |
567 memset(&md5c, 0, sizeof(md5c)); | 602 memset(&md5c, 0, sizeof(md5c)); |
568 memset(keybuf, 0, sizeof(keybuf)); | 603 memset(keybuf, 0, sizeof(keybuf)); |
569 #endif | 604 #endif |
605 } | |
606 | |
607 /* | |
608 * Now we have a decrypted key blob, which contains OpenSSH | |
609 * encoded private key. We must now untangle the OpenSSH format. | |
610 */ | |
611 if (key->type == OSSH_PKEY) { | |
612 blobbuf = buf_new(key->keyblob_len); | |
613 buf_putbytes(blobbuf, key->keyblob, key->keyblob_len); | |
614 buf_setpos(blobbuf, 0); | |
615 | |
616 /* limit length of private key blob */ | |
617 len = buf_getint(blobbuf); | |
618 buf_setlen(blobbuf, blobbuf->pos + len); | |
619 | |
620 type = DROPBEAR_SIGNKEY_ANY; | |
621 if (buf_get_pub_key(blobbuf, retkey, &type) | |
622 != DROPBEAR_SUCCESS) { | |
623 errmsg = "Error parsing OpenSSH key"; | |
624 goto ossh_error; | |
625 } | |
626 | |
627 /* restore full length */ | |
628 buf_setlen(blobbuf, key->keyblob_len); | |
629 | |
630 if (type != DROPBEAR_SIGNKEY_NONE) { | |
631 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 | |
636 if (type == DROPBEAR_SIGNKEY_ED25519) { | |
637 buf_incrpos(blobbuf, 8); | |
638 buf_eatstring(blobbuf); | |
639 buf_eatstring(blobbuf); | |
640 buf_incrpos(blobbuf, -SSH_SIGNKEY_ED25519_LEN-4); | |
641 if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key) | |
642 == DROPBEAR_SUCCESS) { | |
643 errmsg = NULL; | |
644 retval = retkey; | |
645 goto error; | |
646 } | |
647 } | |
648 #endif | |
649 } | |
650 | |
651 errmsg = "Unsupported OpenSSH key type"; | |
652 ossh_error: | |
653 sign_key_free(retkey); | |
654 retkey = NULL; | |
655 goto error; | |
570 } | 656 } |
571 | 657 |
572 /* | 658 /* |
573 * Now we have a decrypted key blob, which contains an ASN.1 | 659 * Now we have a decrypted key blob, which contains an ASN.1 |
574 * encoded private key. We must now untangle the ASN.1. | 660 * encoded private key. We must now untangle the ASN.1. |
779 if (!ecc) { | 865 if (!ecc) { |
780 errmsg = "Error parsing ECC key"; | 866 errmsg = "Error parsing ECC key"; |
781 goto error; | 867 goto error; |
782 } | 868 } |
783 m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL); | 869 m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL); |
784 if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len) | 870 if (mp_from_ubin(ecc->k, private_key_bytes, private_key_len) |
785 != MP_OKAY) { | 871 != MP_OKAY) { |
786 errmsg = "Error parsing ECC key"; | 872 errmsg = "Error parsing ECC key"; |
787 goto error; | 873 goto error; |
788 } | 874 } |
789 | 875 |
1054 int curve_oid_len = 0; | 1140 int curve_oid_len = 0; |
1055 const void* curve_oid = NULL; | 1141 const void* curve_oid = NULL; |
1056 unsigned long pubkey_size = 2*curve_size+1; | 1142 unsigned long pubkey_size = 2*curve_size+1; |
1057 int k_size; | 1143 int k_size; |
1058 int err = 0; | 1144 int err = 0; |
1145 size_t written; | |
1059 | 1146 |
1060 /* version. less than 10 bytes */ | 1147 /* version. less than 10 bytes */ |
1061 buf_incrwritepos(seq_buf, | 1148 buf_incrwritepos(seq_buf, |
1062 ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0)); | 1149 ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0)); |
1063 buf_putbyte(seq_buf, 1); | 1150 buf_putbyte(seq_buf, 1); |
1064 | 1151 |
1065 /* privateKey */ | 1152 /* privateKey */ |
1066 k_size = mp_unsigned_bin_size((*eck)->k); | 1153 k_size = mp_ubin_size((*eck)->k); |
1067 dropbear_assert(k_size <= curve_size); | 1154 dropbear_assert(k_size <= curve_size); |
1068 buf_incrwritepos(seq_buf, | 1155 buf_incrwritepos(seq_buf, |
1069 ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0)); | 1156 ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0)); |
1070 mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size)); | 1157 if (mp_to_ubin((*eck)->k, buf_getwriteptr(seq_buf, k_size), k_size, &written) != MP_OKAY) { |
1071 buf_incrwritepos(seq_buf, k_size); | 1158 dropbear_exit("ECC error"); |
1159 } | |
1160 buf_incrwritepos(seq_buf, written); | |
1072 | 1161 |
1073 /* SECGCurveNames */ | 1162 /* SECGCurveNames */ |
1074 switch (key->type) | 1163 switch (key->type) |
1075 { | 1164 { |
1076 case DROPBEAR_SIGNKEY_ECDSA_NISTP256: | 1165 case DROPBEAR_SIGNKEY_ECDSA_NISTP256: |
1124 buf_free(seq_buf); | 1213 buf_free(seq_buf); |
1125 seq_buf = NULL; | 1214 seq_buf = NULL; |
1126 | 1215 |
1127 header = "-----BEGIN EC PRIVATE KEY-----\n"; | 1216 header = "-----BEGIN EC PRIVATE KEY-----\n"; |
1128 footer = "-----END EC PRIVATE KEY-----\n"; | 1217 footer = "-----END EC PRIVATE KEY-----\n"; |
1218 } | |
1219 #endif | |
1220 | |
1221 #if DROPBEAR_ED25519 | |
1222 if (key->type == DROPBEAR_SIGNKEY_ED25519) { | |
1223 buffer *buf = buf_new(300); | |
1224 keyblob = buf_new(100); | |
1225 extrablob = buf_new(200); | |
1226 | |
1227 /* private key blob w/o header */ | |
1228 buf_put_priv_key(keyblob, key, key->type); | |
1229 buf_setpos(keyblob, 0); | |
1230 buf_incrpos(keyblob, buf_getint(keyblob)); | |
1231 len = buf_getint(keyblob); | |
1232 | |
1233 /* header */ | |
1234 buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN); | |
1235 | |
1236 /* public key */ | |
1237 buf_put_pub_key(buf, key, key->type); | |
1238 | |
1239 /* private key */ | |
1240 buf_incrwritepos(extrablob, 4); | |
1241 buf_put_pub_key(extrablob, key, key->type); | |
1242 buf_putstring(extrablob, buf_getptr(keyblob, len), len); | |
1243 /* comment */ | |
1244 buf_putstring(extrablob, "", 0); | |
1245 /* padding to cipher block length */ | |
1246 len = (extrablob->len+8) & ~7; | |
1247 for (i = 1; len - extrablob->len > 0; i++) | |
1248 buf_putbyte(extrablob, i); | |
1249 buf_setpos(extrablob, 0); | |
1250 buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8); | |
1251 buf_putbufstring(buf, extrablob); | |
1252 | |
1253 outlen = len = pos = buf->len; | |
1254 outblob = (unsigned char*)m_malloc(outlen); | |
1255 memcpy(outblob, buf->data, buf->len); | |
1256 | |
1257 buf_burn(buf); | |
1258 buf_free(buf); | |
1259 buf = NULL; | |
1260 | |
1261 header = "-----BEGIN OPENSSH PRIVATE KEY-----\n"; | |
1262 footer = "-----END OPENSSH PRIVATE KEY-----\n"; | |
1129 } | 1263 } |
1130 #endif | 1264 #endif |
1131 | 1265 |
1132 /* | 1266 /* |
1133 * Padding on OpenSSH keys is deterministic. The number of | 1267 * Padding on OpenSSH keys is deterministic. The number of |