diff options
| author | 2011-09-14 18:55:59 +0200 | |
|---|---|---|
| committer | 2012-03-19 01:43:29 +0100 | |
| commit | 8b1af4cf80eff619d3465925dce7fe572fc09224 (patch) | |
| tree | 1fc167114f574c2ff3470c97d6ce74938778f9db /src/idevice.c | |
| parent | 294cf69b256419e407b1eac04634752412ee7756 (diff) | |
| download | libimobiledevice-8b1af4cf80eff619d3465925dce7fe572fc09224.tar.gz libimobiledevice-8b1af4cf80eff619d3465925dce7fe572fc09224.tar.bz2 | |
Add OpenSSL support
Diffstat (limited to 'src/idevice.c')
| -rw-r--r-- | src/idevice.c | 155 |
1 files changed, 154 insertions, 1 deletions
diff --git a/src/idevice.c b/src/idevice.c index af87e61..d2769de 100644 --- a/src/idevice.c +++ b/src/idevice.c | |||
| @@ -20,16 +20,28 @@ | |||
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #ifdef HAVE_CONFIG_H | ||
| 24 | #include <config.h> | ||
| 25 | #endif | ||
| 26 | |||
| 23 | #include <stdlib.h> | 27 | #include <stdlib.h> |
| 24 | #include <string.h> | 28 | #include <string.h> |
| 25 | #include <errno.h> | 29 | #include <errno.h> |
| 26 | 30 | ||
| 27 | #include <usbmuxd.h> | 31 | #include <usbmuxd.h> |
| 32 | #ifdef HAVE_OPENSSL | ||
| 33 | #include <openssl/ssl.h> | ||
| 34 | #else | ||
| 28 | #include <gnutls/gnutls.h> | 35 | #include <gnutls/gnutls.h> |
| 36 | #endif | ||
| 29 | #include "idevice.h" | 37 | #include "idevice.h" |
| 30 | #include "userpref.h" | 38 | #include "userpref.h" |
| 31 | #include "debug.h" | 39 | #include "debug.h" |
| 32 | 40 | ||
| 41 | #ifdef HAVE_OPENSSL | ||
| 42 | static int openssl_init_done = 0; | ||
| 43 | #endif | ||
| 44 | |||
| 33 | static idevice_event_cb_t event_cb = NULL; | 45 | static idevice_event_cb_t event_cb = NULL; |
| 34 | 46 | ||
| 35 | static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data) | 47 | static void usbmux_event_cb(const usbmuxd_event_t *event, void *user_data) |
| @@ -303,7 +315,12 @@ idevice_error_t idevice_connection_send(idevice_connection_t connection, const c | |||
| 303 | } | 315 | } |
| 304 | 316 | ||
| 305 | if (connection->ssl_data) { | 317 | if (connection->ssl_data) { |
| 318 | #ifdef HAVE_OPENSSL | ||
| 319 | int sent = SSL_write(connection->ssl_data->session, (const void*)data, (int)len); | ||
| 320 | debug_info("SSL_write %d, sent %d", len, sent); | ||
| 321 | #else | ||
| 306 | ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len); | 322 | ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len); |
| 323 | #endif | ||
| 307 | if ((uint32_t)sent == (uint32_t)len) { | 324 | if ((uint32_t)sent == (uint32_t)len) { |
| 308 | *sent_bytes = sent; | 325 | *sent_bytes = sent; |
| 309 | return IDEVICE_E_SUCCESS; | 326 | return IDEVICE_E_SUCCESS; |
| @@ -359,7 +376,12 @@ idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connecti | |||
| 359 | } | 376 | } |
| 360 | 377 | ||
| 361 | if (connection->ssl_data) { | 378 | if (connection->ssl_data) { |
| 379 | #ifdef HAVE_OPENSSL | ||
| 380 | int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len); | ||
| 381 | debug_info("SSL_read %d, received %d", len, received); | ||
| 382 | #else | ||
| 362 | ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); | 383 | ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); |
| 384 | #endif | ||
| 363 | if (received > 0) { | 385 | if (received > 0) { |
| 364 | *recv_bytes = received; | 386 | *recv_bytes = received; |
| 365 | return IDEVICE_E_SUCCESS; | 387 | return IDEVICE_E_SUCCESS; |
| @@ -413,7 +435,12 @@ idevice_error_t idevice_connection_receive(idevice_connection_t connection, char | |||
| 413 | } | 435 | } |
| 414 | 436 | ||
| 415 | if (connection->ssl_data) { | 437 | if (connection->ssl_data) { |
| 438 | #ifdef HAVE_OPENSSL | ||
| 439 | int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len); | ||
| 440 | debug_info("SSL_read %d, received %d", len, received); | ||
| 441 | #else | ||
| 416 | ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); | 442 | ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); |
| 443 | #endif | ||
| 417 | if (received > 0) { | 444 | if (received > 0) { |
| 418 | *recv_bytes = received; | 445 | *recv_bytes = received; |
| 419 | return IDEVICE_E_SUCCESS; | 446 | return IDEVICE_E_SUCCESS; |
| @@ -453,6 +480,7 @@ idevice_error_t idevice_get_uuid(idevice_t device, char **uuid) | |||
| 453 | return IDEVICE_E_SUCCESS; | 480 | return IDEVICE_E_SUCCESS; |
| 454 | } | 481 | } |
| 455 | 482 | ||
| 483 | #ifndef HAVE_OPENSSL | ||
| 456 | /** | 484 | /** |
| 457 | * Internally used gnutls callback function for receiving encrypted data. | 485 | * Internally used gnutls callback function for receiving encrypted data. |
| 458 | */ | 486 | */ |
| @@ -514,6 +542,7 @@ static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer | |||
| 514 | debug_info("post-send sent %i bytes", bytes); | 542 | debug_info("post-send sent %i bytes", bytes); |
| 515 | return bytes; | 543 | return bytes; |
| 516 | } | 544 | } |
| 545 | #endif | ||
| 517 | 546 | ||
| 518 | /** | 547 | /** |
| 519 | * Internally used function for cleaning up SSL stuff. | 548 | * Internally used function for cleaning up SSL stuff. |
| @@ -523,6 +552,14 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data) | |||
| 523 | if (!ssl_data) | 552 | if (!ssl_data) |
| 524 | return; | 553 | return; |
| 525 | 554 | ||
| 555 | #ifdef HAVE_OPENSSL | ||
| 556 | if (ssl_data->session) { | ||
| 557 | SSL_free(ssl_data->session); | ||
| 558 | } | ||
| 559 | if (ssl_data->ctx) { | ||
| 560 | SSL_CTX_free(ssl_data->ctx); | ||
| 561 | } | ||
| 562 | #else | ||
| 526 | if (ssl_data->session) { | 563 | if (ssl_data->session) { |
| 527 | gnutls_deinit(ssl_data->session); | 564 | gnutls_deinit(ssl_data->session); |
| 528 | } | 565 | } |
| @@ -541,8 +578,45 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data) | |||
| 541 | if (ssl_data->host_privkey) { | 578 | if (ssl_data->host_privkey) { |
| 542 | gnutls_x509_privkey_deinit(ssl_data->host_privkey); | 579 | gnutls_x509_privkey_deinit(ssl_data->host_privkey); |
| 543 | } | 580 | } |
| 581 | #endif | ||
| 582 | } | ||
| 583 | |||
| 584 | #ifdef HAVE_OPENSSL | ||
| 585 | static int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) | ||
| 586 | { | ||
| 587 | return 1; | ||
| 588 | } | ||
| 589 | |||
| 590 | #ifndef STRIP_DEBUG_CODE | ||
| 591 | static const char *errorstring(int e) | ||
| 592 | { | ||
| 593 | switch(e) { | ||
| 594 | case SSL_ERROR_NONE: | ||
| 595 | return "SSL_ERROR_NONE"; | ||
| 596 | case SSL_ERROR_SSL: | ||
| 597 | return "SSL_ERROR_SSL"; | ||
| 598 | case SSL_ERROR_WANT_READ: | ||
| 599 | return "SSL_ERROR_WANT_READ"; | ||
| 600 | case SSL_ERROR_WANT_WRITE: | ||
| 601 | return "SSL_ERROR_WANT_WRITE"; | ||
| 602 | case SSL_ERROR_WANT_X509_LOOKUP: | ||
| 603 | return "SSL_ERROR_WANT_X509_LOOKUP"; | ||
| 604 | case SSL_ERROR_SYSCALL: | ||
| 605 | return "SSL_ERROR_SYSCALL"; | ||
| 606 | case SSL_ERROR_ZERO_RETURN: | ||
| 607 | return "SSL_ERROR_ZERO_RETURN"; | ||
| 608 | case SSL_ERROR_WANT_CONNECT: | ||
| 609 | return "SSL_ERROR_WANT_CONNECT"; | ||
| 610 | case SSL_ERROR_WANT_ACCEPT: | ||
| 611 | return "SSL_ERROR_WANT_ACCEPT"; | ||
| 612 | default: | ||
| 613 | return "UNKOWN_ERROR_VALUE"; | ||
| 614 | } | ||
| 544 | } | 615 | } |
| 616 | #endif | ||
| 617 | #endif | ||
| 545 | 618 | ||
| 619 | #ifndef HAVE_OPENSSL | ||
| 546 | /** | 620 | /** |
| 547 | * Internally used gnutls callback function that gets called during handshake. | 621 | * Internally used gnutls callback function that gets called during handshake. |
| 548 | */ | 622 | */ |
| @@ -564,6 +638,7 @@ static int internal_cert_callback (gnutls_session_t session, const gnutls_datum_ | |||
| 564 | } | 638 | } |
| 565 | return res; | 639 | return res; |
| 566 | } | 640 | } |
| 641 | #endif | ||
| 567 | 642 | ||
| 568 | /** | 643 | /** |
| 569 | * Enables SSL for the given connection. | 644 | * Enables SSL for the given connection. |
| @@ -582,6 +657,76 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) | |||
| 582 | idevice_error_t ret = IDEVICE_E_SSL_ERROR; | 657 | idevice_error_t ret = IDEVICE_E_SSL_ERROR; |
| 583 | uint32_t return_me = 0; | 658 | uint32_t return_me = 0; |
| 584 | 659 | ||
| 660 | #ifdef HAVE_OPENSSL | ||
| 661 | key_data_t root_cert = { NULL, 0 }; | ||
| 662 | key_data_t root_privkey = { NULL, 0 }; | ||
| 663 | |||
| 664 | userpref_error_t uerr = userpref_get_keys_and_certs(&root_privkey, &root_cert, NULL, NULL); | ||
| 665 | if (uerr != USERPREF_E_SUCCESS) { | ||
| 666 | debug_info("Error %d when loading keys and certificates! %d", uerr); | ||
| 667 | } | ||
| 668 | |||
| 669 | /* Set up OpenSSL */ | ||
| 670 | BIO *ssl_bio = BIO_new(BIO_s_socket()); | ||
| 671 | if (!ssl_bio) { | ||
| 672 | debug_info("ERROR: Could not create SSL bio."); | ||
| 673 | return ret; | ||
| 674 | } | ||
| 675 | BIO_set_fd(ssl_bio, (int)(long)connection->data, BIO_NOCLOSE); | ||
| 676 | |||
| 677 | if (openssl_init_done == 0) { | ||
| 678 | SSL_library_init(); | ||
| 679 | openssl_init_done = 1; | ||
| 680 | } | ||
| 681 | SSL_CTX *ssl_ctx = SSL_CTX_new(SSLv3_method()); | ||
| 682 | |||
| 683 | BIO* membp; | ||
| 684 | X509* rootCert = NULL; | ||
| 685 | membp = BIO_new_mem_buf(root_cert.data, root_cert.size); | ||
| 686 | PEM_read_bio_X509(membp, &rootCert, NULL, NULL); | ||
| 687 | BIO_free(membp); | ||
| 688 | if (SSL_CTX_use_certificate(ssl_ctx, rootCert) != 1) { | ||
| 689 | debug_info("WARNING: Could not load RootCertificate"); | ||
| 690 | } | ||
| 691 | X509_free(rootCert); | ||
| 692 | free(root_cert.data); | ||
| 693 | |||
| 694 | RSA* rootPrivKey = NULL; | ||
| 695 | membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size); | ||
| 696 | PEM_read_bio_RSAPrivateKey(membp, &rootPrivKey, NULL, NULL); | ||
| 697 | BIO_free(membp); | ||
| 698 | if (SSL_CTX_use_RSAPrivateKey(ssl_ctx, rootPrivKey) != 1) { | ||
| 699 | debug_info("WARNING: Could not load RootPrivateKey"); | ||
| 700 | } | ||
| 701 | RSA_free(rootPrivKey); | ||
| 702 | free(root_privkey.data); | ||
| 703 | |||
| 704 | SSL *ssl = SSL_new(ssl_ctx); | ||
| 705 | if (!ssl) { | ||
| 706 | debug_info("ERROR: Could not create SSL object"); | ||
| 707 | BIO_free(ssl_bio); | ||
| 708 | SSL_CTX_free(ssl_ctx); | ||
| 709 | return ret; | ||
| 710 | } | ||
| 711 | SSL_set_connect_state(ssl); | ||
| 712 | SSL_set_verify(ssl, 0, ssl_verify_callback); | ||
| 713 | SSL_set_bio(ssl, ssl_bio, ssl_bio); | ||
| 714 | |||
| 715 | return_me = SSL_do_handshake(ssl); | ||
| 716 | if (return_me != 1) { | ||
| 717 | debug_info("ERROR in SSL_do_handshake: %s", errorstring(SSL_get_error(ssl, return_me))); | ||
| 718 | BIO_free(ssl_bio); | ||
| 719 | SSL_CTX_free(ssl_ctx); | ||
| 720 | } else { | ||
| 721 | ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private)); | ||
| 722 | ssl_data_loc->session = ssl; | ||
| 723 | ssl_data_loc->ctx = ssl_ctx; | ||
| 724 | ssl_data_loc->bio = ssl_bio; | ||
| 725 | connection->ssl_data = ssl_data_loc; | ||
| 726 | ret = IDEVICE_E_SUCCESS; | ||
| 727 | debug_info("SSL mode enabled, cipher: %s", SSL_get_cipher(ssl)); | ||
| 728 | } | ||
| 729 | #else | ||
| 585 | ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private)); | 730 | ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private)); |
| 586 | 731 | ||
| 587 | /* Set up GnuTLS... */ | 732 | /* Set up GnuTLS... */ |
| @@ -612,8 +757,9 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) | |||
| 612 | debug_info("GnuTLS step 3..."); | 757 | debug_info("GnuTLS step 3..."); |
| 613 | gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read); | 758 | gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read); |
| 614 | debug_info("GnuTLS step 4 -- now handshaking..."); | 759 | debug_info("GnuTLS step 4 -- now handshaking..."); |
| 615 | if (errno) | 760 | if (errno) { |
| 616 | debug_info("WARN: errno says %s before handshake!", strerror(errno)); | 761 | debug_info("WARN: errno says %s before handshake!", strerror(errno)); |
| 762 | } | ||
| 617 | return_me = gnutls_handshake(ssl_data_loc->session); | 763 | return_me = gnutls_handshake(ssl_data_loc->session); |
| 618 | debug_info("GnuTLS handshake done..."); | 764 | debug_info("GnuTLS handshake done..."); |
| 619 | 765 | ||
| @@ -628,6 +774,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) | |||
| 628 | ret = IDEVICE_E_SUCCESS; | 774 | ret = IDEVICE_E_SUCCESS; |
| 629 | debug_info("SSL mode enabled"); | 775 | debug_info("SSL mode enabled"); |
| 630 | } | 776 | } |
| 777 | #endif | ||
| 631 | return ret; | 778 | return ret; |
| 632 | } | 779 | } |
| 633 | 780 | ||
| @@ -649,9 +796,15 @@ idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection) | |||
| 649 | return IDEVICE_E_SUCCESS; | 796 | return IDEVICE_E_SUCCESS; |
| 650 | } | 797 | } |
| 651 | 798 | ||
| 799 | #ifdef HAVE_OPENSSL | ||
| 800 | if (connection->ssl_data->session) { | ||
| 801 | SSL_shutdown(connection->ssl_data->session); | ||
| 802 | } | ||
| 803 | #else | ||
| 652 | if (connection->ssl_data->session) { | 804 | if (connection->ssl_data->session) { |
| 653 | gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR); | 805 | gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR); |
| 654 | } | 806 | } |
| 807 | #endif | ||
| 655 | internal_ssl_cleanup(connection->ssl_data); | 808 | internal_ssl_cleanup(connection->ssl_data); |
| 656 | free(connection->ssl_data); | 809 | free(connection->ssl_data); |
| 657 | connection->ssl_data = NULL; | 810 | connection->ssl_data = NULL; |
