1 /* Copyright (C) 2007 The Written Word, Inc. 2 * Copyright (C) 2008, Simon Josefsson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, 6 * with or without modification, are permitted provided 7 * that the following conditions are met: 8 * 9 * Redistributions of source code must retain the above 10 * copyright notice, this list of conditions and the 11 * following disclaimer. 12 * 13 * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials 16 * provided with the distribution. 17 * 18 * Neither the name of the copyright holder nor the names 19 * of any other contributors may be used to endorse or 20 * promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 35 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 36 * OF SUCH DAMAGE. 37 */ 38 39 #include "libssh2_priv.h" 40 41 static int 42 readline(char *line, int line_size, FILE * fp) 43 { 44 size_t len; 45 46 if(!line) { 47 return -1; 48 } 49 if(!fgets(line, line_size, fp)) { 50 return -1; 51 } 52 53 if(*line) { 54 len = strlen(line); 55 if(len > 0 && line[len - 1] == '\n') { 56 line[len - 1] = '\0'; 57 } 58 } 59 60 if(*line) { 61 len = strlen(line); 62 if(len > 0 && line[len - 1] == '\r') { 63 line[len - 1] = '\0'; 64 } 65 } 66 67 return 0; 68 } 69 70 static int 71 readline_memory(char *line, size_t line_size, 72 const char *filedata, size_t filedata_len, 73 size_t *filedata_offset) 74 { 75 size_t off, len; 76 77 off = *filedata_offset; 78 79 for(len = 0; off + len < filedata_len && len < line_size - 1; len++) { 80 if(filedata[off + len] == '\n' || 81 filedata[off + len] == '\r') { 82 break; 83 } 84 } 85 86 if(len) { 87 memcpy(line, filedata + off, len); 88 *filedata_offset += len; 89 } 90 91 line[len] = '\0'; 92 *filedata_offset += 1; 93 94 return 0; 95 } 96 97 #define LINE_SIZE 128 98 99 static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED"; 100 101 static unsigned char hex_decode(char digit) 102 { 103 return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0'); 104 } 105 106 int 107 _libssh2_pem_parse(LIBSSH2_SESSION * session, 108 const char *headerbegin, 109 const char *headerend, 110 const unsigned char *passphrase, 111 FILE * fp, unsigned char **data, unsigned int *datalen) 112 { 113 char line[LINE_SIZE]; 114 unsigned char iv[LINE_SIZE]; 115 char *b64data = NULL; 116 unsigned int b64datalen = 0; 117 int ret; 118 const LIBSSH2_CRYPT_METHOD *method = NULL; 119 120 do { 121 *line = '\0'; 122 123 if(readline(line, LINE_SIZE, fp)) { 124 return -1; 125 } 126 } 127 while(strcmp(line, headerbegin) != 0); 128 129 if(readline(line, LINE_SIZE, fp)) { 130 return -1; 131 } 132 133 if(passphrase && 134 memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) { 135 const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method; 136 int i; 137 138 if(readline(line, LINE_SIZE, fp)) { 139 ret = -1; 140 goto out; 141 } 142 143 all_methods = libssh2_crypt_methods(); 144 while((cur_method = *all_methods++)) { 145 if(*cur_method->pem_annotation && 146 memcmp(line, cur_method->pem_annotation, 147 strlen(cur_method->pem_annotation)) == 0) { 148 method = cur_method; 149 memcpy(iv, line + strlen(method->pem_annotation) + 1, 150 2*method->iv_len); 151 } 152 } 153 154 /* None of the available crypt methods were able to decrypt the key */ 155 if(method == NULL) 156 return -1; 157 158 /* Decode IV from hex */ 159 for(i = 0; i < method->iv_len; ++i) { 160 iv[i] = hex_decode(iv[2*i]) << 4; 161 iv[i] |= hex_decode(iv[2*i + 1]); 162 } 163 164 /* skip to the next line */ 165 if(readline(line, LINE_SIZE, fp)) { 166 ret = -1; 167 goto out; 168 } 169 } 170 171 do { 172 if(*line) { 173 char *tmp; 174 size_t linelen; 175 176 linelen = strlen(line); 177 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); 178 if(!tmp) { 179 _libssh2_error(session, LIBSSH2_ERROR_ALLOC, 180 "Unable to allocate memory for PEM parsing"); 181 ret = -1; 182 goto out; 183 } 184 memcpy(tmp + b64datalen, line, linelen); 185 b64data = tmp; 186 b64datalen += linelen; 187 } 188 189 *line = '\0'; 190 191 if(readline(line, LINE_SIZE, fp)) { 192 ret = -1; 193 goto out; 194 } 195 } while(strcmp(line, headerend) != 0); 196 197 if(!b64data) { 198 return -1; 199 } 200 201 if(libssh2_base64_decode(session, (char **) data, datalen, 202 b64data, b64datalen)) { 203 ret = -1; 204 goto out; 205 } 206 207 if(method) { 208 /* Set up decryption */ 209 int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0; 210 int blocksize = method->blocksize; 211 void *abstract; 212 unsigned char secret[2*MD5_DIGEST_LENGTH]; 213 libssh2_md5_ctx fingerprint_ctx; 214 215 /* Perform key derivation (PBKDF1/MD5) */ 216 if(!libssh2_md5_init(&fingerprint_ctx)) { 217 ret = -1; 218 goto out; 219 } 220 libssh2_md5_update(fingerprint_ctx, passphrase, 221 strlen((char *)passphrase)); 222 libssh2_md5_update(fingerprint_ctx, iv, 8); 223 libssh2_md5_final(fingerprint_ctx, secret); 224 if(method->secret_len > MD5_DIGEST_LENGTH) { 225 if(!libssh2_md5_init(&fingerprint_ctx)) { 226 ret = -1; 227 goto out; 228 } 229 libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH); 230 libssh2_md5_update(fingerprint_ctx, passphrase, 231 strlen((char *)passphrase)); 232 libssh2_md5_update(fingerprint_ctx, iv, 8); 233 libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH); 234 } 235 236 /* Initialize the decryption */ 237 if(method->init(session, method, iv, &free_iv, secret, 238 &free_secret, 0, &abstract)) { 239 _libssh2_explicit_zero((char *)secret, sizeof(secret)); 240 LIBSSH2_FREE(session, data); 241 ret = -1; 242 goto out; 243 } 244 245 if(free_secret) { 246 _libssh2_explicit_zero((char *)secret, sizeof(secret)); 247 } 248 249 /* Do the actual decryption */ 250 if((*datalen % blocksize) != 0) { 251 _libssh2_explicit_zero((char *)secret, sizeof(secret)); 252 method->dtor(session, &abstract); 253 _libssh2_explicit_zero(*data, *datalen); 254 LIBSSH2_FREE(session, *data); 255 ret = -1; 256 goto out; 257 } 258 259 while(len_decrypted <= (int)*datalen - blocksize) { 260 if(method->crypt(session, *data + len_decrypted, blocksize, 261 &abstract)) { 262 ret = LIBSSH2_ERROR_DECRYPT; 263 _libssh2_explicit_zero((char *)secret, sizeof(secret)); 264 method->dtor(session, &abstract); 265 _libssh2_explicit_zero(*data, *datalen); 266 LIBSSH2_FREE(session, *data); 267 goto out; 268 } 269 270 len_decrypted += blocksize; 271 } 272 273 /* Account for padding */ 274 padding = (*data)[*datalen - 1]; 275 memset(&(*data)[*datalen-padding], 0, padding); 276 *datalen -= padding; 277 278 /* Clean up */ 279 _libssh2_explicit_zero((char *)secret, sizeof(secret)); 280 method->dtor(session, &abstract); 281 } 282 283 ret = 0; 284 out: 285 if(b64data) { 286 _libssh2_explicit_zero(b64data, b64datalen); 287 LIBSSH2_FREE(session, b64data); 288 } 289 return ret; 290 } 291 292 int 293 _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, 294 const char *headerbegin, 295 const char *headerend, 296 const char *filedata, size_t filedata_len, 297 unsigned char **data, unsigned int *datalen) 298 { 299 char line[LINE_SIZE]; 300 char *b64data = NULL; 301 unsigned int b64datalen = 0; 302 size_t off = 0; 303 int ret; 304 305 do { 306 *line = '\0'; 307 308 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { 309 return -1; 310 } 311 } 312 while(strcmp(line, headerbegin) != 0); 313 314 *line = '\0'; 315 316 do { 317 if(*line) { 318 char *tmp; 319 size_t linelen; 320 321 linelen = strlen(line); 322 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); 323 if(!tmp) { 324 _libssh2_error(session, LIBSSH2_ERROR_ALLOC, 325 "Unable to allocate memory for PEM parsing"); 326 ret = -1; 327 goto out; 328 } 329 memcpy(tmp + b64datalen, line, linelen); 330 b64data = tmp; 331 b64datalen += linelen; 332 } 333 334 *line = '\0'; 335 336 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { 337 ret = -1; 338 goto out; 339 } 340 } while(strcmp(line, headerend) != 0); 341 342 if(!b64data) { 343 return -1; 344 } 345 346 if(libssh2_base64_decode(session, (char **) data, datalen, 347 b64data, b64datalen)) { 348 ret = -1; 349 goto out; 350 } 351 352 ret = 0; 353 out: 354 if(b64data) { 355 _libssh2_explicit_zero(b64data, b64datalen); 356 LIBSSH2_FREE(session, b64data); 357 } 358 return ret; 359 } 360 361 /* OpenSSH formatted keys */ 362 #define AUTH_MAGIC "openssh-key-v1" 363 #define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----" 364 #define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----" 365 366 static int 367 _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, 368 const unsigned char *passphrase, 369 const char *b64data, size_t b64datalen, 370 struct string_buf **decrypted_buf) 371 { 372 const LIBSSH2_CRYPT_METHOD *method = NULL; 373 struct string_buf decoded, decrypted, kdf_buf; 374 unsigned char *ciphername = NULL; 375 unsigned char *kdfname = NULL; 376 unsigned char *kdf = NULL; 377 unsigned char *buf = NULL; 378 unsigned char *salt = NULL; 379 uint32_t nkeys, check1, check2; 380 uint32_t rounds = 0; 381 unsigned char *key = NULL; 382 unsigned char *key_part = NULL; 383 unsigned char *iv_part = NULL; 384 unsigned char *f = NULL; 385 unsigned int f_len = 0; 386 int ret = 0, keylen = 0, ivlen = 0, total_len = 0; 387 size_t kdf_len = 0, tmp_len = 0, salt_len = 0; 388 389 if(decrypted_buf) 390 *decrypted_buf = NULL; 391 392 /* decode file */ 393 if(libssh2_base64_decode(session, (char **)&f, &f_len, 394 b64data, b64datalen)) { 395 ret = -1; 396 goto out; 397 } 398 399 /* Parse the file */ 400 decoded.data = (unsigned char *)f; 401 decoded.dataptr = (unsigned char *)f; 402 decoded.len = f_len; 403 404 if(decoded.len < strlen(AUTH_MAGIC)) { 405 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short"); 406 goto out; 407 } 408 409 if(strncmp((char *) decoded.dataptr, AUTH_MAGIC, 410 strlen(AUTH_MAGIC)) != 0) { 411 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 412 "key auth magic mismatch"); 413 goto out; 414 } 415 416 decoded.dataptr += strlen(AUTH_MAGIC) + 1; 417 418 if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) || 419 tmp_len == 0) { 420 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 421 "ciphername is missing"); 422 goto out; 423 } 424 425 if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) || 426 tmp_len == 0) { 427 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 428 "kdfname is missing"); 429 goto out; 430 } 431 432 if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) { 433 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 434 "kdf is missing"); 435 goto out; 436 } 437 else { 438 kdf_buf.data = kdf; 439 kdf_buf.dataptr = kdf; 440 kdf_buf.len = kdf_len; 441 } 442 443 if((passphrase == NULL || strlen((const char *)passphrase) == 0) && 444 strcmp((const char *)ciphername, "none") != 0) { 445 /* passphrase required */ 446 ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; 447 goto out; 448 } 449 450 if(strcmp((const char *)kdfname, "none") != 0 && 451 strcmp((const char *)kdfname, "bcrypt") != 0) { 452 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 453 "unknown cipher"); 454 goto out; 455 } 456 457 if(!strcmp((const char *)kdfname, "none") && 458 strcmp((const char *)ciphername, "none") != 0) { 459 ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO, 460 "invalid format"); 461 goto out; 462 } 463 464 if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) { 465 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 466 "Multiple keys are unsupported"); 467 goto out; 468 } 469 470 /* unencrypted public key */ 471 472 if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) { 473 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 474 "Invalid private key; " 475 "expect embedded public key"); 476 goto out; 477 } 478 479 if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) { 480 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 481 "Private key data not found"); 482 goto out; 483 } 484 485 /* decode encrypted private key */ 486 decrypted.data = decrypted.dataptr = buf; 487 decrypted.len = tmp_len; 488 489 if(ciphername && strcmp((const char *)ciphername, "none") != 0) { 490 const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method; 491 492 all_methods = libssh2_crypt_methods(); 493 while((cur_method = *all_methods++)) { 494 if(*cur_method->name && 495 memcmp(ciphername, cur_method->name, 496 strlen(cur_method->name)) == 0) { 497 method = cur_method; 498 } 499 } 500 501 /* None of the available crypt methods were able to decrypt the key */ 502 503 if(method == NULL) { 504 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 505 "No supported cipher found"); 506 goto out; 507 } 508 } 509 510 if(method) { 511 int free_iv = 0, free_secret = 0, len_decrypted = 0; 512 int blocksize; 513 void *abstract = NULL; 514 515 keylen = method->secret_len; 516 ivlen = method->iv_len; 517 total_len = keylen + ivlen; 518 519 key = LIBSSH2_CALLOC(session, total_len); 520 if(key == NULL) { 521 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 522 "Could not alloc key"); 523 goto out; 524 } 525 526 if(strcmp((const char *)kdfname, "bcrypt") == 0 && 527 passphrase != NULL) { 528 if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) || 529 (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) { 530 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 531 "kdf contains unexpected values"); 532 LIBSSH2_FREE(session, key); 533 goto out; 534 } 535 536 if(_libssh2_bcrypt_pbkdf((const char *)passphrase, 537 strlen((const char *)passphrase), 538 salt, salt_len, key, 539 keylen + ivlen, rounds) < 0) { 540 ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT, 541 "invalid format"); 542 LIBSSH2_FREE(session, key); 543 goto out; 544 } 545 } 546 else { 547 ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED, 548 "bcrypted without passphrase"); 549 LIBSSH2_FREE(session, key); 550 goto out; 551 } 552 553 /* Set up decryption */ 554 blocksize = method->blocksize; 555 556 key_part = LIBSSH2_CALLOC(session, keylen); 557 if(key_part == NULL) { 558 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 559 "Could not alloc key part"); 560 goto out; 561 } 562 563 iv_part = LIBSSH2_CALLOC(session, ivlen); 564 if(iv_part == NULL) { 565 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 566 "Could not alloc iv part"); 567 goto out; 568 } 569 570 memcpy(key_part, key, keylen); 571 memcpy(iv_part, key + keylen, ivlen); 572 573 /* Initialize the decryption */ 574 if(method->init(session, method, iv_part, &free_iv, key_part, 575 &free_secret, 0, &abstract)) { 576 ret = LIBSSH2_ERROR_DECRYPT; 577 goto out; 578 } 579 580 /* Do the actual decryption */ 581 if((decrypted.len % blocksize) != 0) { 582 method->dtor(session, &abstract); 583 ret = LIBSSH2_ERROR_DECRYPT; 584 goto out; 585 } 586 587 while((size_t)len_decrypted <= decrypted.len - blocksize) { 588 if(method->crypt(session, decrypted.data + len_decrypted, 589 blocksize, 590 &abstract)) { 591 ret = LIBSSH2_ERROR_DECRYPT; 592 method->dtor(session, &abstract); 593 goto out; 594 } 595 596 len_decrypted += blocksize; 597 } 598 599 /* No padding */ 600 601 method->dtor(session, &abstract); 602 } 603 604 /* Check random bytes match */ 605 606 if(_libssh2_get_u32(&decrypted, &check1) != 0 || 607 _libssh2_get_u32(&decrypted, &check2) != 0 || 608 check1 != check2) { 609 _libssh2_error(session, LIBSSH2_ERROR_PROTO, 610 "Private key unpack failed (correct password?)"); 611 ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; 612 goto out; 613 } 614 615 if(decrypted_buf != NULL) { 616 /* copy data to out-going buffer */ 617 struct string_buf *out_buf = _libssh2_string_buf_new(session); 618 if(!out_buf) { 619 ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, 620 "Unable to allocate memory for " 621 "decrypted struct"); 622 goto out; 623 } 624 625 out_buf->data = LIBSSH2_CALLOC(session, decrypted.len); 626 if(out_buf->data == NULL) { 627 ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, 628 "Unable to allocate memory for " 629 "decrypted struct"); 630 _libssh2_string_buf_free(session, out_buf); 631 goto out; 632 } 633 memcpy(out_buf->data, decrypted.data, decrypted.len); 634 out_buf->dataptr = out_buf->data + 635 (decrypted.dataptr - decrypted.data); 636 out_buf->len = decrypted.len; 637 638 *decrypted_buf = out_buf; 639 } 640 641 out: 642 643 /* Clean up */ 644 if(key) { 645 _libssh2_explicit_zero(key, total_len); 646 LIBSSH2_FREE(session, key); 647 } 648 if(key_part) { 649 _libssh2_explicit_zero(key_part, keylen); 650 LIBSSH2_FREE(session, key_part); 651 } 652 if(iv_part) { 653 _libssh2_explicit_zero(iv_part, ivlen); 654 LIBSSH2_FREE(session, iv_part); 655 } 656 if(f) { 657 _libssh2_explicit_zero(f, f_len); 658 LIBSSH2_FREE(session, f); 659 } 660 661 return ret; 662 } 663 664 int 665 _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, 666 const unsigned char *passphrase, 667 FILE * fp, struct string_buf **decrypted_buf) 668 { 669 char line[LINE_SIZE]; 670 char *b64data = NULL; 671 unsigned int b64datalen = 0; 672 int ret = 0; 673 674 /* read file */ 675 676 do { 677 *line = '\0'; 678 679 if(readline(line, LINE_SIZE, fp)) { 680 return -1; 681 } 682 } 683 while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); 684 685 if(readline(line, LINE_SIZE, fp)) { 686 return -1; 687 } 688 689 do { 690 if(*line) { 691 char *tmp; 692 size_t linelen; 693 694 linelen = strlen(line); 695 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); 696 if(!tmp) { 697 _libssh2_error(session, LIBSSH2_ERROR_ALLOC, 698 "Unable to allocate memory for PEM parsing"); 699 ret = -1; 700 goto out; 701 } 702 memcpy(tmp + b64datalen, line, linelen); 703 b64data = tmp; 704 b64datalen += linelen; 705 } 706 707 *line = '\0'; 708 709 if(readline(line, LINE_SIZE, fp)) { 710 ret = -1; 711 goto out; 712 } 713 } while(strcmp(line, OPENSSH_HEADER_END) != 0); 714 715 if(!b64data) { 716 return -1; 717 } 718 719 ret = _libssh2_openssh_pem_parse_data(session, 720 passphrase, 721 (const char *)b64data, 722 (size_t)b64datalen, 723 decrypted_buf); 724 725 if(b64data) { 726 _libssh2_explicit_zero(b64data, b64datalen); 727 LIBSSH2_FREE(session, b64data); 728 } 729 730 out: 731 732 return ret; 733 } 734 735 int 736 _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, 737 const unsigned char *passphrase, 738 const char *filedata, size_t filedata_len, 739 struct string_buf **decrypted_buf) 740 { 741 char line[LINE_SIZE]; 742 char *b64data = NULL; 743 unsigned int b64datalen = 0; 744 size_t off = 0; 745 int ret; 746 747 if(filedata == NULL || filedata_len <= 0) 748 return _libssh2_error(session, LIBSSH2_ERROR_PROTO, 749 "Error parsing PEM: filedata missing"); 750 751 do { 752 753 *line = '\0'; 754 755 if(off >= filedata_len) 756 return _libssh2_error(session, LIBSSH2_ERROR_PROTO, 757 "Error parsing PEM: offset out of bounds"); 758 759 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { 760 return -1; 761 } 762 } 763 while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); 764 765 *line = '\0'; 766 767 do { 768 if (*line) { 769 char *tmp; 770 size_t linelen; 771 772 linelen = strlen(line); 773 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); 774 if(!tmp) { 775 ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, 776 "Unable to allocate memory for " 777 "PEM parsing"); 778 goto out; 779 } 780 memcpy(tmp + b64datalen, line, linelen); 781 b64data = tmp; 782 b64datalen += linelen; 783 } 784 785 *line = '\0'; 786 787 if(off >= filedata_len) { 788 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, 789 "Error parsing PEM: offset out of bounds"); 790 goto out; 791 } 792 793 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { 794 ret = -1; 795 goto out; 796 } 797 } while(strcmp(line, OPENSSH_HEADER_END) != 0); 798 799 if(!b64data) 800 return _libssh2_error(session, LIBSSH2_ERROR_PROTO, 801 "Error parsing PEM: base 64 data missing"); 802 803 ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data, 804 b64datalen, decrypted_buf); 805 806 out: 807 if(b64data) { 808 _libssh2_explicit_zero(b64data, b64datalen); 809 LIBSSH2_FREE(session, b64data); 810 } 811 return ret; 812 813 } 814 815 static int 816 read_asn1_length(const unsigned char *data, 817 unsigned int datalen, unsigned int *len) 818 { 819 unsigned int lenlen; 820 int nextpos; 821 822 if(datalen < 1) { 823 return -1; 824 } 825 *len = data[0]; 826 827 if(*len >= 0x80) { 828 lenlen = *len & 0x7F; 829 *len = data[1]; 830 if(1 + lenlen > datalen) { 831 return -1; 832 } 833 if(lenlen > 1) { 834 *len <<= 8; 835 *len |= data[2]; 836 } 837 } 838 else { 839 lenlen = 0; 840 } 841 842 nextpos = 1 + lenlen; 843 if(lenlen > 2 || 1 + lenlen + *len > datalen) { 844 return -1; 845 } 846 847 return nextpos; 848 } 849 850 int 851 _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) 852 { 853 unsigned int len; 854 int lenlen; 855 856 if(*datalen < 1) { 857 return -1; 858 } 859 860 if((*data)[0] != '\x30') { 861 return -1; 862 } 863 864 (*data)++; 865 (*datalen)--; 866 867 lenlen = read_asn1_length(*data, *datalen, &len); 868 if(lenlen < 0 || lenlen + len != *datalen) { 869 return -1; 870 } 871 872 *data += lenlen; 873 *datalen -= lenlen; 874 875 return 0; 876 } 877 878 int 879 _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, 880 unsigned char **i, unsigned int *ilen) 881 { 882 unsigned int len; 883 int lenlen; 884 885 if(*datalen < 1) { 886 return -1; 887 } 888 889 if((*data)[0] != '\x02') { 890 return -1; 891 } 892 893 (*data)++; 894 (*datalen)--; 895 896 lenlen = read_asn1_length(*data, *datalen, &len); 897 if(lenlen < 0 || lenlen + len > *datalen) { 898 return -1; 899 } 900 901 *data += lenlen; 902 *datalen -= lenlen; 903 904 *i = *data; 905 *ilen = len; 906 907 *data += len; 908 *datalen -= len; 909 910 return 0; 911 } 912