summaryrefslogtreecommitdiffstats
path: root/src/iphone.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2010-01-13 00:10:03 +0100
committerGravatar Martin Szulecki2010-01-13 01:02:55 +0100
commit65346c9ddd92e6ea3650040d791a411b9ac308af (patch)
tree9076bb41718b464a1842ef5ab17d5b0de4a91d0c /src/iphone.c
parent4709c7301decf0fb275e6e0a9ad08c0afa4d774f (diff)
downloadlibimobiledevice-65346c9ddd92e6ea3650040d791a411b9ac308af.tar.gz
libimobiledevice-65346c9ddd92e6ea3650040d791a411b9ac308af.tar.bz2
Move SSL code into iphone.c/iphone.h
Diffstat (limited to 'src/iphone.c')
-rw-r--r--src/iphone.c274
1 files changed, 257 insertions, 17 deletions
diff --git a/src/iphone.c b/src/iphone.c
index ce90299..8bc9e8d 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -26,6 +26,7 @@
26#include <arpa/inet.h> 26#include <arpa/inet.h>
27 27
28#include <usbmuxd.h> 28#include <usbmuxd.h>
29#include <gnutls/gnutls.h>
29#include "iphone.h" 30#include "iphone.h"
30#include "debug.h" 31#include "debug.h"
31 32
@@ -222,6 +223,7 @@ iphone_error_t iphone_device_connect(iphone_device_t device, uint16_t dst_port,
222 iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int)); 223 iphone_connection_t new_connection = (iphone_connection_t)malloc(sizeof(struct iphone_connection_int));
223 new_connection->type = CONNECTION_USBMUXD; 224 new_connection->type = CONNECTION_USBMUXD;
224 new_connection->data = (void*)sfd; 225 new_connection->data = (void*)sfd;
226 new_connection->ssl_data = NULL;
225 *connection = new_connection; 227 *connection = new_connection;
226 return IPHONE_E_SUCCESS; 228 return IPHONE_E_SUCCESS;
227 } else { 229 } else {
@@ -243,6 +245,10 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
243 if (!connection) { 245 if (!connection) {
244 return IPHONE_E_INVALID_ARG; 246 return IPHONE_E_INVALID_ARG;
245 } 247 }
248 /* shut down ssl if enabled */
249 if (connection->ssl_data) {
250 iphone_connection_disable_ssl(connection);
251 }
246 iphone_error_t result = IPHONE_E_UNKNOWN_ERROR; 252 iphone_error_t result = IPHONE_E_UNKNOWN_ERROR;
247 if (connection->type == CONNECTION_USBMUXD) { 253 if (connection->type == CONNECTION_USBMUXD) {
248 usbmuxd_disconnect((int)(connection->data)); 254 usbmuxd_disconnect((int)(connection->data));
@@ -255,6 +261,29 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
255} 261}
256 262
257/** 263/**
264 * Internally used function to send raw data over the given connection.
265 */
266static iphone_error_t internal_connection_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
267{
268 if (!connection || !data) {
269 return IPHONE_E_INVALID_ARG;
270 }
271
272 if (connection->type == CONNECTION_USBMUXD) {
273 int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes);
274 if (res < 0) {
275 debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res));
276 return IPHONE_E_UNKNOWN_ERROR;
277 }
278 return IPHONE_E_SUCCESS;
279 } else {
280 debug_info("Unknown connection type %d", connection->type);
281 }
282 return IPHONE_E_UNKNOWN_ERROR;
283
284}
285
286/**
258 * Send data to a device via the given connection. 287 * Send data to a device via the given connection.
259 * 288 *
260 * @param connection The connection to send data over. 289 * @param connection The connection to send data over.
@@ -267,14 +296,36 @@ iphone_error_t iphone_device_disconnect(iphone_connection_t connection)
267 */ 296 */
268iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) 297iphone_error_t iphone_device_send(iphone_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes)
269{ 298{
270 if (!connection || !data) { 299 if (!connection || !data || (connection->ssl_data && !connection->ssl_data->session)) {
300 return IPHONE_E_INVALID_ARG;
301 }
302
303 if (connection->ssl_data) {
304 ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len);
305 if ((uint32_t)sent == (uint32_t)len) {
306 *sent_bytes = sent;
307 return IPHONE_E_SUCCESS;
308 }
309 *sent_bytes = 0;
310 return IPHONE_E_SSL_ERROR;
311 }
312 return internal_connection_send(connection, data, len, sent_bytes);
313}
314
315/**
316 * Internally used function for receiving raw data over the given connection
317 * using a timeout.
318 */
319static iphone_error_t internal_connection_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
320{
321 if (!connection) {
271 return IPHONE_E_INVALID_ARG; 322 return IPHONE_E_INVALID_ARG;
272 } 323 }
273 324
274 if (connection->type == CONNECTION_USBMUXD) { 325 if (connection->type == CONNECTION_USBMUXD) {
275 int res = usbmuxd_send((int)(connection->data), data, len, sent_bytes); 326 int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout);
276 if (res < 0) { 327 if (res < 0) {
277 debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res)); 328 debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(-res));
278 return IPHONE_E_UNKNOWN_ERROR; 329 return IPHONE_E_UNKNOWN_ERROR;
279 } 330 }
280 return IPHONE_E_SUCCESS; 331 return IPHONE_E_SUCCESS;
@@ -301,16 +352,38 @@ iphone_error_t iphone_device_send(iphone_connection_t connection, const char *da
301 */ 352 */
302iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) 353iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
303{ 354{
355 if (!connection || (connection->ssl_data && !connection->ssl_data->session)) {
356 return IPHONE_E_INVALID_ARG;
357 }
358
359 if (connection->ssl_data) {
360 ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
361 if (received > 0) {
362 *recv_bytes = received;
363 return IPHONE_E_SUCCESS;
364 }
365 *recv_bytes = 0;
366 return IPHONE_E_SSL_ERROR;
367 }
368 return internal_connection_recv_timeout(connection, data, len, recv_bytes, timeout);
369}
370
371/**
372 * Internally used function for receiving raw data over the given connection.
373 */
374static iphone_error_t internal_connection_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
375{
304 if (!connection) { 376 if (!connection) {
305 return IPHONE_E_INVALID_ARG; 377 return IPHONE_E_INVALID_ARG;
306 } 378 }
307 379
308 if (connection->type == CONNECTION_USBMUXD) { 380 if (connection->type == CONNECTION_USBMUXD) {
309 int res = usbmuxd_recv_timeout((int)(connection->data), data, len, recv_bytes, timeout); 381 int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes);
310 if (res < 0) { 382 if (res < 0) {
311 debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", res, strerror(-res)); 383 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));
312 return IPHONE_E_UNKNOWN_ERROR; 384 return IPHONE_E_UNKNOWN_ERROR;
313 } 385 }
386
314 return IPHONE_E_SUCCESS; 387 return IPHONE_E_SUCCESS;
315 } else { 388 } else {
316 debug_info("Unknown connection type %d", connection->type); 389 debug_info("Unknown connection type %d", connection->type);
@@ -333,22 +406,20 @@ iphone_error_t iphone_device_recv_timeout(iphone_connection_t connection, char *
333 */ 406 */
334iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) 407iphone_error_t iphone_device_recv(iphone_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes)
335{ 408{
336 if (!connection) { 409 if (!connection || (connection->ssl_data && !connection->ssl_data->session)) {
337 return -EINVAL; 410 return IPHONE_E_INVALID_ARG;
338 } 411 }
339 412
340 if (connection->type == CONNECTION_USBMUXD) { 413 if (connection->ssl_data) {
341 int res = usbmuxd_recv((int)(connection->data), data, len, recv_bytes); 414 ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
342 if (res < 0) { 415 if (received > 0) {
343 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res)); 416 *recv_bytes = received;
344 return IPHONE_E_UNKNOWN_ERROR; 417 return IPHONE_E_SUCCESS;
345 } 418 }
346 419 *recv_bytes = 0;
347 return IPHONE_E_SUCCESS; 420 return IPHONE_E_SSL_ERROR;
348 } else {
349 debug_info("Unknown connection type %d", connection->type);
350 } 421 }
351 return IPHONE_E_UNKNOWN_ERROR; 422 return internal_connection_recv(connection, data, len, recv_bytes);
352} 423}
353 424
354iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle) 425iphone_error_t iphone_device_get_handle(iphone_device_t device, uint32_t *handle)
@@ -374,3 +445,172 @@ iphone_error_t iphone_device_get_uuid(iphone_device_t device, char **uuid)
374 return IPHONE_E_SUCCESS; 445 return IPHONE_E_SUCCESS;
375} 446}
376 447
448/**
449 * Internally used gnutls callback function for receiving encrypted data.
450 */
451static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length)
452{
453 int bytes = 0, pos_start_fill = 0;
454 size_t tbytes = 0;
455 int this_len = length;
456 iphone_error_t res;
457 iphone_connection_t connection = (iphone_connection_t)transport;
458 char *recv_buffer;
459
460 debug_info("pre-read client wants %zi bytes", length);
461
462 recv_buffer = (char *) malloc(sizeof(char) * this_len);
463
464 /* repeat until we have the full data or an error occurs */
465 do {
466 if ((res = internal_connection_recv(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IPHONE_E_SUCCESS) {
467 debug_info("ERROR: iphone_device_recv returned %d", res);
468 return res;
469 }
470 debug_info("post-read we got %i bytes", bytes);
471
472 // increase read count
473 tbytes += bytes;
474
475 // fill the buffer with what we got right now
476 memcpy(buffer + pos_start_fill, recv_buffer, bytes);
477 pos_start_fill += bytes;
478
479 if (tbytes >= length) {
480 break;
481 }
482
483 this_len = length - tbytes;
484 debug_info("re-read trying to read missing %i bytes", this_len);
485 } while (tbytes < length);
486
487 if (recv_buffer) {
488 free(recv_buffer);
489 }
490 return tbytes;
491}
492
493/**
494 * Internally used gnutls callback function for sending encrypted data.
495 */
496static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length)
497{
498 uint32_t bytes = 0;
499 iphone_connection_t connection = (iphone_connection_t)transport;
500 debug_info("pre-send length = %zi", length);
501 internal_connection_send(connection, buffer, length, &bytes);
502 debug_info("post-send sent %i bytes", bytes);
503 return bytes;
504}
505
506/**
507 * Internally used function for cleaning up SSL stuff.
508 */
509static void internal_ssl_cleanup(ssl_data_t ssl_data)
510{
511 if (!ssl_data)
512 return;
513
514 if (ssl_data->session) {
515 gnutls_deinit(ssl_data->session);
516 }
517 if (ssl_data->certificate) {
518 gnutls_certificate_free_credentials(ssl_data->certificate);
519 }
520}
521
522/**
523 * Enables SSL for the given connection.
524 *
525 * @param connection The connection to enable SSL for.
526 *
527 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
528 * is NULL or connection->ssl_data is non-NULL, or IPHONE_E_SSL_ERROR when
529 * SSL initialization, setup, or handshake fails.
530 */
531iphone_error_t iphone_connection_enable_ssl(iphone_connection_t connection)
532{
533 if (!connection || connection->ssl_data)
534 return IPHONE_E_INVALID_ARG;
535
536 iphone_error_t ret = IPHONE_E_SSL_ERROR;
537 uint32_t return_me = 0;
538
539 ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_int));
540
541 // Set up GnuTLS...
542 debug_info("enabling SSL mode");
543 errno = 0;
544 gnutls_global_init();
545 gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate);
546 gnutls_certificate_set_x509_trust_file(ssl_data_loc->certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM);
547 gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT);
548 {
549 int protocol_priority[16] = { GNUTLS_SSL3, 0 };
550 int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 };
551 int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 };
552 int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 };
553 int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
554
555 gnutls_cipher_set_priority(ssl_data_loc->session, cipher_priority);
556 gnutls_compression_set_priority(ssl_data_loc->session, comp_priority);
557 gnutls_kx_set_priority(ssl_data_loc->session, kx_priority);
558 gnutls_protocol_set_priority(ssl_data_loc->session, protocol_priority);
559 gnutls_mac_set_priority(ssl_data_loc->session, mac_priority);
560 }
561 gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); // this part is killing me.
562
563 debug_info("GnuTLS step 1...");
564 gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection);
565 debug_info("GnuTLS step 2...");
566 gnutls_transport_set_push_function(ssl_data_loc->session, (gnutls_push_func) & internal_ssl_write);
567 debug_info("GnuTLS step 3...");
568 gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read);
569 debug_info("GnuTLS step 4 -- now handshaking...");
570 if (errno)
571 debug_info("WARN: errno says %s before handshake!", strerror(errno));
572 return_me = gnutls_handshake(ssl_data_loc->session);
573 debug_info("GnuTLS handshake done...");
574
575 if (return_me != GNUTLS_E_SUCCESS) {
576 internal_ssl_cleanup(ssl_data_loc);
577 free(ssl_data_loc);
578 debug_info("GnuTLS reported something wrong.");
579 gnutls_perror(return_me);
580 debug_info("oh.. errno says %s", strerror(errno));
581 } else {
582 connection->ssl_data = ssl_data_loc;
583 ret = IPHONE_E_SUCCESS;
584 debug_info("SSL mode enabled");
585 }
586 return ret;
587}
588
589/**
590 * Disable SSL for the given connection.
591 *
592 * @param connection The connection to disable SSL for.
593 *
594 * @return IPHONE_E_SUCCESS on success, IPHONE_E_INVALID_ARG when connection
595 * is NULL. This function also returns IPHONE_E_SUCCESS when SSL is not
596 * enabled and does no further error checking on cleanup.
597 */
598iphone_error_t iphone_connection_disable_ssl(iphone_connection_t connection)
599{
600 if (!connection)
601 return IPHONE_E_INVALID_ARG;
602 if (!connection->ssl_data) {
603 /* ignore if ssl is not enabled */
604 return IPHONE_E_SUCCESS;
605 }
606
607 if (connection->ssl_data->session) {
608 gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR);
609 }
610 internal_ssl_cleanup(connection->ssl_data);
611 free(connection->ssl_data);
612 connection->ssl_data = NULL;
613
614 return IPHONE_E_SUCCESS;
615}
616