diff options
Diffstat (limited to 'libsylph/ssl.c')
| -rw-r--r-- | libsylph/ssl.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/libsylph/ssl.c b/libsylph/ssl.c index 8413925..5a76b8b 100644 --- a/libsylph/ssl.c +++ b/libsylph/ssl.c | |||
| @@ -32,6 +32,11 @@ | |||
| 32 | #include "ssl.h" | 32 | #include "ssl.h" |
| 33 | #include "ssl_hostname_validation.h" | 33 | #include "ssl_hostname_validation.h" |
| 34 | 34 | ||
| 35 | #define SALT_SIZE 16 | ||
| 36 | #define CIPHER EVP_aes_256_cfb() | ||
| 37 | #define KEY_HASH EVP_sha256() | ||
| 38 | #define DIGEST_HASH EVP_sha256() | ||
| 39 | |||
| 35 | static SSL_CTX *ssl_ctx_SSLv23 = NULL; | 40 | static SSL_CTX *ssl_ctx_SSLv23 = NULL; |
| 36 | static SSL_CTX *ssl_ctx_TLSv1 = NULL; | 41 | static SSL_CTX *ssl_ctx_TLSv1 = NULL; |
| 37 | 42 | ||
| @@ -402,4 +407,376 @@ void ssl_set_verify_func(SSLVerifyFunc func) | |||
| 402 | verify_ui_func = func; | 407 | verify_ui_func = func; |
| 403 | } | 408 | } |
| 404 | 409 | ||
| 410 | /* master password related functions */ | ||
| 411 | static gint secure_derive_key(guchar *key, | ||
| 412 | gint length_key, | ||
| 413 | const gchar *passphrase, | ||
| 414 | const guchar *salt) { | ||
| 415 | |||
| 416 | guint length_buffer, length_hash; | ||
| 417 | guchar *buffer, *ptr_hash; | ||
| 418 | |||
| 419 | EVP_MD_CTX *mdctx; | ||
| 420 | |||
| 421 | OPENSSL_cleanse(key, length_key); | ||
| 422 | |||
| 423 | length_buffer = SALT_SIZE + strlen(passphrase); | ||
| 424 | buffer = OPENSSL_malloc(length_buffer); | ||
| 425 | OPENSSL_cleanse(buffer, length_buffer); | ||
| 426 | |||
| 427 | memcpy(buffer, salt, SALT_SIZE); | ||
| 428 | memcpy(buffer + SALT_SIZE, passphrase, strlen(passphrase)); | ||
| 429 | |||
| 430 | mdctx = EVP_MD_CTX_create(); | ||
| 431 | EVP_DigestInit_ex(mdctx, KEY_HASH, NULL); | ||
| 432 | EVP_DigestUpdate(mdctx, buffer, length_buffer); | ||
| 433 | OPENSSL_cleanse(buffer, length_buffer); | ||
| 434 | |||
| 435 | ptr_hash = OPENSSL_malloc(EVP_MD_size(KEY_HASH)); | ||
| 436 | EVP_DigestFinal_ex(mdctx, ptr_hash, &length_hash); | ||
| 437 | |||
| 438 | memcpy(key, | ||
| 439 | ptr_hash, | ||
| 440 | (length_hash > length_key) ? length_key : length_hash); | ||
| 441 | |||
| 442 | OPENSSL_cleanse(ptr_hash, length_hash); | ||
| 443 | OPENSSL_free(ptr_hash); | ||
| 444 | OPENSSL_free(buffer); | ||
| 445 | EVP_MD_CTX_destroy(mdctx); | ||
| 446 | |||
| 447 | return RC_OK; | ||
| 448 | |||
| 449 | } | ||
| 450 | |||
| 451 | |||
| 452 | gint encrypt_data(gchar **encrypted, | ||
| 453 | gint *length_encrypted, | ||
| 454 | const gchar *data, | ||
| 455 | const gchar *passphrase, | ||
| 456 | gint length_data, | ||
| 457 | guint min_data_length, | ||
| 458 | gboolean rnd_salt) { | ||
| 459 | |||
| 460 | gint crypt_buffer_cnt, rc; | ||
| 461 | guint key_size, length_hash; | ||
| 462 | guint length_cleartext, length_ciphertext, length_total; | ||
| 463 | guchar salt[SALT_SIZE]; | ||
| 464 | guchar *ciphertext_buffer, *total_buffer; | ||
| 465 | /* sensitive buffers and counters */ | ||
| 466 | guint length_data_payload, length_padding; | ||
| 467 | gchar str_data_size[3]; | ||
| 468 | guchar *data_payload_buffer, *hash_buffer, *padding_buffer, *key; | ||
| 469 | guchar *cleartext_buffer; | ||
| 470 | |||
| 471 | EVP_CIPHER_CTX *ctx; | ||
| 472 | EVP_MD_CTX *mdctx; | ||
| 473 | |||
| 474 | rc = RC_ERROR; | ||
| 475 | |||
| 476 | if (length_data < 1) { | ||
| 477 | return -1; | ||
| 478 | } | ||
| 479 | if (rnd_salt) { | ||
| 480 | if (RAND_bytes(salt, SALT_SIZE) != 1) { | ||
| 481 | debug_print("Random problems...\n"); | ||
| 482 | goto cleanup; | ||
| 483 | } | ||
| 484 | } else { | ||
| 485 | strncpy((gchar *)salt, "FOR TESTING ONLY", SALT_SIZE); | ||
| 486 | } | ||
| 487 | |||
| 488 | key_size = EVP_CIPHER_key_length(CIPHER); | ||
| 489 | key = OPENSSL_malloc(key_size); | ||
| 490 | OPENSSL_cleanse(key, key_size); | ||
| 491 | if (secure_derive_key(key, | ||
| 492 | key_size, | ||
| 493 | passphrase, | ||
| 494 | salt) != RC_OK) { | ||
| 495 | OPENSSL_cleanse(key, key_size); | ||
| 496 | debug_print("Could not generate secure key\n"); | ||
| 497 | goto cleanup; | ||
| 498 | } | ||
| 499 | |||
| 500 | /* prepare the data-buffer */ | ||
| 501 | length_padding = 0; | ||
| 502 | if (length_data < min_data_length) { | ||
| 503 | g_snprintf(str_data_size, 3, "%02d", length_data); | ||
| 504 | length_padding = min_data_length - length_data; | ||
| 505 | padding_buffer = OPENSSL_malloc(length_padding); | ||
| 506 | OPENSSL_cleanse(padding_buffer, length_padding); | ||
| 507 | if (RAND_bytes(padding_buffer, length_padding) != 1) { | ||
| 508 | debug_print("Random problems...\n"); | ||
| 509 | goto cleanup; | ||
| 510 | } | ||
| 511 | } else { | ||
| 512 | g_snprintf(str_data_size, 3, "-1"); | ||
| 513 | } | ||
| 514 | |||
| 515 | length_data_payload = 2 + length_data + length_padding; | ||
| 516 | data_payload_buffer = OPENSSL_malloc(length_data_payload); | ||
| 517 | OPENSSL_cleanse(data_payload_buffer, length_data_payload); | ||
| 518 | |||
| 519 | memcpy(data_payload_buffer, str_data_size, 2); | ||
| 520 | memcpy(data_payload_buffer + 2, data, length_data); | ||
| 521 | if (length_padding > 0) { | ||
| 522 | memcpy(data_payload_buffer + (2 + length_data), | ||
| 523 | padding_buffer, | ||
| 524 | length_padding); | ||
| 525 | } | ||
| 526 | |||
| 527 | mdctx = EVP_MD_CTX_create(); | ||
| 528 | EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); | ||
| 529 | EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); | ||
| 530 | |||
| 531 | length_hash = EVP_MD_size(DIGEST_HASH); | ||
| 532 | hash_buffer = OPENSSL_malloc(length_hash); | ||
| 533 | OPENSSL_cleanse(hash_buffer, length_hash); | ||
| 534 | EVP_DigestFinal_ex(mdctx, hash_buffer, NULL); | ||
| 535 | |||
| 536 | length_cleartext = length_hash + length_data_payload; | ||
| 537 | |||
| 538 | cleartext_buffer = OPENSSL_malloc(length_cleartext); | ||
| 539 | OPENSSL_cleanse(cleartext_buffer, length_cleartext); | ||
| 540 | |||
| 541 | /* assemble cleartext-buffer */ | ||
| 542 | memcpy(cleartext_buffer, hash_buffer, length_hash); | ||
| 543 | memcpy(cleartext_buffer + length_hash, | ||
| 544 | data_payload_buffer, | ||
| 545 | length_data_payload); | ||
| 546 | OPENSSL_cleanse(data_payload_buffer, length_data_payload); /* sensitive */ | ||
| 547 | |||
| 548 | /* encryption */ | ||
| 549 | if (!(ctx = EVP_CIPHER_CTX_new())) { | ||
| 550 | debug_print("New ctx failed\n"); | ||
| 551 | goto cleanup; | ||
| 552 | } | ||
| 553 | |||
| 554 | length_ciphertext = 0; | ||
| 555 | if (EVP_EncryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { | ||
| 556 | debug_print("EVP_EncryptInit_ex failed\n"); | ||
| 557 | goto cleanup; | ||
| 558 | } | ||
| 559 | |||
| 560 | ciphertext_buffer = OPENSSL_malloc(length_cleartext); | ||
| 561 | |||
| 562 | crypt_buffer_cnt = 0; | ||
| 563 | while(1) { | ||
| 564 | if (EVP_EncryptUpdate(ctx, | ||
| 565 | ciphertext_buffer + length_ciphertext, | ||
| 566 | &crypt_buffer_cnt, | ||
| 567 | cleartext_buffer + length_ciphertext, | ||
| 568 | 1) != 1) { /* one byte at a time */ | ||
| 569 | debug_print("EVP_EncryptUpdate failed\n"); | ||
| 570 | goto cleanup; | ||
| 571 | } | ||
| 572 | |||
| 573 | if (crypt_buffer_cnt != 1) { /* paranoia */ | ||
| 574 | debug_print("The sizes of enc and dec text do not correspond\n"); | ||
| 575 | goto cleanup; | ||
| 576 | } | ||
| 577 | |||
| 578 | ++length_ciphertext; | ||
| 579 | |||
| 580 | if (length_ciphertext >= length_cleartext) { | ||
| 581 | break; | ||
| 582 | } | ||
| 583 | } | ||
| 584 | /* No padding required for the CFB mode */ | ||
| 585 | |||
| 586 | OPENSSL_cleanse(cleartext_buffer, length_cleartext); /* sensitive */ | ||
| 587 | length_total = SALT_SIZE + length_ciphertext; | ||
| 588 | total_buffer = OPENSSL_malloc(length_total); | ||
| 589 | |||
| 590 | memcpy(total_buffer, salt, SALT_SIZE); | ||
| 591 | memcpy(total_buffer + SALT_SIZE, ciphertext_buffer, length_ciphertext); | ||
| 592 | |||
| 593 | *encrypted = g_base64_encode(total_buffer, length_total); | ||
| 594 | *length_encrypted = strlen(*encrypted); | ||
| 595 | |||
| 596 | rc = RC_OK; | ||
| 597 | |||
| 598 | cleanup: | ||
| 599 | /* key */ | ||
| 600 | OPENSSL_cleanse(key, key_size); | ||
| 601 | OPENSSL_free(key); | ||
| 602 | /* cleartext buffer */ | ||
| 603 | OPENSSL_cleanse(cleartext_buffer, length_cleartext); | ||
| 604 | OPENSSL_free(cleartext_buffer); | ||
| 605 | /* payload buffer */ | ||
| 606 | OPENSSL_cleanse(data_payload_buffer, length_data_payload); | ||
| 607 | OPENSSL_free(data_payload_buffer); | ||
| 608 | /* hash */ | ||
| 609 | OPENSSL_cleanse(hash_buffer, length_hash); | ||
| 610 | OPENSSL_free(hash_buffer); | ||
| 611 | /* padding */ | ||
| 612 | if (length_padding > 0) { | ||
| 613 | OPENSSL_cleanse(padding_buffer, length_padding); | ||
| 614 | OPENSSL_free(padding_buffer); | ||
| 615 | } | ||
| 616 | |||
| 617 | OPENSSL_cleanse(str_data_size, 3); /* paranoia */ | ||
| 618 | |||
| 619 | /* ciphertext buffer */ | ||
| 620 | OPENSSL_free(ciphertext_buffer); | ||
| 621 | |||
| 622 | /* total buffer */ | ||
| 623 | OPENSSL_free(total_buffer); | ||
| 624 | |||
| 625 | length_data_payload = 0; | ||
| 626 | length_padding = 0; | ||
| 627 | |||
| 628 | EVP_CIPHER_CTX_free(ctx); | ||
| 629 | EVP_MD_CTX_destroy(mdctx); | ||
| 630 | |||
| 631 | return rc; | ||
| 632 | |||
| 633 | } | ||
| 634 | |||
| 635 | |||
| 636 | gint decrypt_data(gchar **decrypted, | ||
| 637 | const gchar *data, | ||
| 638 | const gchar *passphrase, | ||
| 639 | gint length_data) { | ||
| 640 | |||
| 641 | gint rc; /* return code */ | ||
| 642 | gint decrypt_buffer_cnt, length_ciphertext, length_decrypted; | ||
| 643 | guint key_size, length_hash, length_cleartext; | ||
| 644 | gsize length_total; | ||
| 645 | guchar salt[SALT_SIZE]; | ||
| 646 | guchar *ciphertext_buffer, *total_buffer; | ||
| 647 | /* sensitive buffers and counters */ | ||
| 648 | gint data_size; | ||
| 649 | guint length_data_payload; | ||
| 650 | gchar str_data_size[3]; | ||
| 651 | guchar *data_payload_buffer, *hash_buffer, *key; | ||
| 652 | guchar *cleartext_buffer; | ||
| 653 | |||
| 654 | EVP_CIPHER_CTX *ctx; | ||
| 655 | EVP_MD_CTX *mdctx; | ||
| 656 | |||
| 657 | rc = -1; | ||
| 658 | |||
| 659 | if (length_data < 1) { | ||
| 660 | return -1; | ||
| 661 | } | ||
| 662 | |||
| 663 | total_buffer = g_base64_decode(data, &length_total); | ||
| 664 | length_ciphertext = length_total - SALT_SIZE; | ||
| 665 | ciphertext_buffer = OPENSSL_malloc(length_ciphertext); | ||
| 666 | OPENSSL_cleanse(ciphertext_buffer, length_ciphertext); | ||
| 667 | |||
| 668 | memcpy(salt, total_buffer, SALT_SIZE); | ||
| 669 | memcpy(ciphertext_buffer, total_buffer + SALT_SIZE, length_ciphertext); | ||
| 670 | |||
| 671 | key_size = EVP_CIPHER_key_length(CIPHER); | ||
| 672 | |||
| 673 | /* decryption */ | ||
| 674 | if(!(ctx = EVP_CIPHER_CTX_new())) { | ||
| 675 | debug_print("New ctx failed\n"); | ||
| 676 | goto cleanup; | ||
| 677 | } | ||
| 678 | |||
| 679 | key = OPENSSL_malloc(key_size); | ||
| 680 | OPENSSL_cleanse(key, key_size); | ||
| 681 | if (secure_derive_key(key, | ||
| 682 | key_size, | ||
| 683 | passphrase, | ||
| 684 | salt) != 0) { | ||
| 685 | OPENSSL_cleanse(key, key_size); | ||
| 686 | debug_print("Could not generate secure key\n"); | ||
| 687 | goto cleanup; | ||
| 688 | } | ||
| 689 | |||
| 690 | if (EVP_DecryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { | ||
| 691 | debug_print("EVP_DecryptInit_ex failed\n"); | ||
| 692 | goto cleanup; | ||
| 693 | } | ||
| 694 | OPENSSL_cleanse(key, key_size); /* highly sensitive */ | ||
| 695 | cleartext_buffer = OPENSSL_malloc(length_ciphertext); | ||
| 696 | OPENSSL_cleanse(cleartext_buffer, length_ciphertext); | ||
| 697 | |||
| 698 | length_cleartext = 0; | ||
| 699 | decrypt_buffer_cnt = 0; | ||
| 700 | |||
| 701 | while(1) { | ||
| 702 | if (EVP_DecryptUpdate(ctx, | ||
| 703 | cleartext_buffer + length_cleartext, | ||
| 704 | &decrypt_buffer_cnt, | ||
| 705 | ciphertext_buffer + length_cleartext, | ||
| 706 | 1) != 1) { /* one byte at a time */ | ||
| 707 | debug_print("EVP_EncryptUpdate failed\n"); | ||
| 708 | goto cleanup; | ||
| 709 | } | ||
| 710 | |||
| 711 | if (decrypt_buffer_cnt != 1) { /* paranoia */ | ||
| 712 | debug_print("The sizes of enc and dec text do not correspond"); | ||
| 713 | goto cleanup; | ||
| 714 | } | ||
| 715 | |||
| 716 | ++length_cleartext; | ||
| 717 | |||
| 718 | if (length_cleartext >= length_ciphertext) { | ||
| 719 | break; | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | |||
| 724 | length_hash = EVP_MD_size(DIGEST_HASH); | ||
| 725 | hash_buffer = OPENSSL_malloc(length_hash); | ||
| 726 | length_data_payload = length_cleartext - length_hash; | ||
| 727 | data_payload_buffer = OPENSSL_malloc(length_data_payload); | ||
| 728 | OPENSSL_cleanse(data_payload_buffer, length_data_payload); | ||
| 729 | |||
| 730 | memcpy(data_payload_buffer, | ||
| 731 | cleartext_buffer + length_hash, | ||
| 732 | length_data_payload); | ||
| 733 | |||
| 734 | mdctx = EVP_MD_CTX_create(); | ||
| 735 | EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); | ||
| 736 | EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); | ||
| 737 | EVP_DigestFinal_ex(mdctx, hash_buffer, &length_hash); | ||
| 738 | |||
| 739 | if (strncmp((const gchar*) hash_buffer, | ||
| 740 | (const gchar*) cleartext_buffer, | ||
| 741 | length_hash) != 0) { | ||
| 742 | debug_print("Invalid hash\n"); | ||
| 743 | rc = RC_WRONG_HASH_OR_KEY; | ||
| 744 | goto cleanup; | ||
| 745 | } | ||
| 746 | |||
| 747 | memcpy(str_data_size, cleartext_buffer + length_hash, 2); | ||
| 748 | data_size = atoi(str_data_size); | ||
| 749 | |||
| 750 | if (data_size < 0) { | ||
| 751 | length_decrypted = length_data_payload - 2; | ||
| 752 | } else { | ||
| 753 | length_decrypted = data_size; | ||
| 754 | } | ||
| 755 | *decrypted = OPENSSL_malloc(length_decrypted); | ||
| 756 | memcpy(*decrypted, data_payload_buffer + 2, length_decrypted); | ||
| 757 | |||
| 758 | rc = RC_OK; | ||
| 759 | |||
| 760 | cleanup: | ||
| 761 | |||
| 762 | /* key */ | ||
| 763 | OPENSSL_cleanse(key, key_size); | ||
| 764 | OPENSSL_free(key); | ||
| 765 | /* payload buffer */ | ||
| 766 | OPENSSL_cleanse(data_payload_buffer, length_data_payload); | ||
| 767 | OPENSSL_free(data_payload_buffer); | ||
| 768 | /* hash */ | ||
| 769 | OPENSSL_cleanse(hash_buffer, length_hash); | ||
| 770 | OPENSSL_free(hash_buffer); | ||
| 771 | /* ciphertext */ | ||
| 772 | OPENSSL_free(ciphertext_buffer); | ||
| 773 | OPENSSL_free(total_buffer); | ||
| 774 | |||
| 775 | EVP_CIPHER_CTX_free(ctx); | ||
| 776 | EVP_MD_CTX_destroy(mdctx); | ||
| 777 | |||
| 778 | return rc; | ||
| 779 | |||
| 780 | } | ||
| 781 | |||
| 405 | #endif /* USE_SSL */ | 782 | #endif /* USE_SSL */ |
