summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2011-09-14 18:55:59 +0200
committerGravatar Martin Szulecki2012-03-19 01:43:29 +0100
commit8b1af4cf80eff619d3465925dce7fe572fc09224 (patch)
tree1fc167114f574c2ff3470c97d6ce74938778f9db /src
parent294cf69b256419e407b1eac04634752412ee7756 (diff)
downloadlibimobiledevice-8b1af4cf80eff619d3465925dce7fe572fc09224.tar.gz
libimobiledevice-8b1af4cf80eff619d3465925dce7fe572fc09224.tar.bz2
Add OpenSSL support
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/idevice.c155
-rw-r--r--src/idevice.h16
-rw-r--r--src/lockdown.c164
-rw-r--r--src/lockdown.h7
-rw-r--r--src/userpref.c233
-rw-r--r--src/userpref.h22
7 files changed, 547 insertions, 54 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5531f8d..c7ab0cf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
-AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusbmuxd_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS)
-AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(libplist_LIBS) $(libusbmuxd_LIBS) $(libgcrypt_LIBS) ${libpthread_LIBS}
+AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusbmuxd_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) $(openssl_CFLAGS)
+AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(libplist_LIBS) $(libusbmuxd_LIBS) $(libgcrypt_LIBS) ${libpthread_LIBS} $(openssl_LIBS)
lib_LTLIBRARIES = libimobiledevice.la
libimobiledevice_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBIMOBILEDEVICE_SO_VERSION) -no-undefined
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 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <usbmuxd.h>
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#else
#include <gnutls/gnutls.h>
+#endif
#include "idevice.h"
#include "userpref.h"
#include "debug.h"
+#ifdef HAVE_OPENSSL
+static int openssl_init_done = 0;
+#endif
+
static idevice_event_cb_t event_cb = NULL;
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
}
if (connection->ssl_data) {
+#ifdef HAVE_OPENSSL
+ int sent = SSL_write(connection->ssl_data->session, (const void*)data, (int)len);
+ debug_info("SSL_write %d, sent %d", len, sent);
+#else
ssize_t sent = gnutls_record_send(connection->ssl_data->session, (void*)data, (size_t)len);
+#endif
if ((uint32_t)sent == (uint32_t)len) {
*sent_bytes = sent;
return IDEVICE_E_SUCCESS;
@@ -359,7 +376,12 @@ idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connecti
}
if (connection->ssl_data) {
+#ifdef HAVE_OPENSSL
+ int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len);
+ debug_info("SSL_read %d, received %d", len, received);
+#else
ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
+#endif
if (received > 0) {
*recv_bytes = received;
return IDEVICE_E_SUCCESS;
@@ -413,7 +435,12 @@ idevice_error_t idevice_connection_receive(idevice_connection_t connection, char
}
if (connection->ssl_data) {
+#ifdef HAVE_OPENSSL
+ int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len);
+ debug_info("SSL_read %d, received %d", len, received);
+#else
ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len);
+#endif
if (received > 0) {
*recv_bytes = received;
return IDEVICE_E_SUCCESS;
@@ -453,6 +480,7 @@ idevice_error_t idevice_get_uuid(idevice_t device, char **uuid)
return IDEVICE_E_SUCCESS;
}
+#ifndef HAVE_OPENSSL
/**
* Internally used gnutls callback function for receiving encrypted data.
*/
@@ -514,6 +542,7 @@ static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer
debug_info("post-send sent %i bytes", bytes);
return bytes;
}
+#endif
/**
* Internally used function for cleaning up SSL stuff.
@@ -523,6 +552,14 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data)
if (!ssl_data)
return;
+#ifdef HAVE_OPENSSL
+ if (ssl_data->session) {
+ SSL_free(ssl_data->session);
+ }
+ if (ssl_data->ctx) {
+ SSL_CTX_free(ssl_data->ctx);
+ }
+#else
if (ssl_data->session) {
gnutls_deinit(ssl_data->session);
}
@@ -541,8 +578,45 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data)
if (ssl_data->host_privkey) {
gnutls_x509_privkey_deinit(ssl_data->host_privkey);
}
+#endif
+}
+
+#ifdef HAVE_OPENSSL
+static int ssl_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+ return 1;
+}
+
+#ifndef STRIP_DEBUG_CODE
+static const char *errorstring(int e)
+{
+ switch(e) {
+ case SSL_ERROR_NONE:
+ return "SSL_ERROR_NONE";
+ case SSL_ERROR_SSL:
+ return "SSL_ERROR_SSL";
+ case SSL_ERROR_WANT_READ:
+ return "SSL_ERROR_WANT_READ";
+ case SSL_ERROR_WANT_WRITE:
+ return "SSL_ERROR_WANT_WRITE";
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "SSL_ERROR_WANT_X509_LOOKUP";
+ case SSL_ERROR_SYSCALL:
+ return "SSL_ERROR_SYSCALL";
+ case SSL_ERROR_ZERO_RETURN:
+ return "SSL_ERROR_ZERO_RETURN";
+ case SSL_ERROR_WANT_CONNECT:
+ return "SSL_ERROR_WANT_CONNECT";
+ case SSL_ERROR_WANT_ACCEPT:
+ return "SSL_ERROR_WANT_ACCEPT";
+ default:
+ return "UNKOWN_ERROR_VALUE";
+ }
}
+#endif
+#endif
+#ifndef HAVE_OPENSSL
/**
* Internally used gnutls callback function that gets called during handshake.
*/
@@ -564,6 +638,7 @@ static int internal_cert_callback (gnutls_session_t session, const gnutls_datum_
}
return res;
}
+#endif
/**
* Enables SSL for the given connection.
@@ -582,6 +657,76 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
idevice_error_t ret = IDEVICE_E_SSL_ERROR;
uint32_t return_me = 0;
+#ifdef HAVE_OPENSSL
+ key_data_t root_cert = { NULL, 0 };
+ key_data_t root_privkey = { NULL, 0 };
+
+ userpref_error_t uerr = userpref_get_keys_and_certs(&root_privkey, &root_cert, NULL, NULL);
+ if (uerr != USERPREF_E_SUCCESS) {
+ debug_info("Error %d when loading keys and certificates! %d", uerr);
+ }
+
+ /* Set up OpenSSL */
+ BIO *ssl_bio = BIO_new(BIO_s_socket());
+ if (!ssl_bio) {
+ debug_info("ERROR: Could not create SSL bio.");
+ return ret;
+ }
+ BIO_set_fd(ssl_bio, (int)(long)connection->data, BIO_NOCLOSE);
+
+ if (openssl_init_done == 0) {
+ SSL_library_init();
+ openssl_init_done = 1;
+ }
+ SSL_CTX *ssl_ctx = SSL_CTX_new(SSLv3_method());
+
+ BIO* membp;
+ X509* rootCert = NULL;
+ membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
+ PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
+ BIO_free(membp);
+ if (SSL_CTX_use_certificate(ssl_ctx, rootCert) != 1) {
+ debug_info("WARNING: Could not load RootCertificate");
+ }
+ X509_free(rootCert);
+ free(root_cert.data);
+
+ RSA* rootPrivKey = NULL;
+ membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
+ PEM_read_bio_RSAPrivateKey(membp, &rootPrivKey, NULL, NULL);
+ BIO_free(membp);
+ if (SSL_CTX_use_RSAPrivateKey(ssl_ctx, rootPrivKey) != 1) {
+ debug_info("WARNING: Could not load RootPrivateKey");
+ }
+ RSA_free(rootPrivKey);
+ free(root_privkey.data);
+
+ SSL *ssl = SSL_new(ssl_ctx);
+ if (!ssl) {
+ debug_info("ERROR: Could not create SSL object");
+ BIO_free(ssl_bio);
+ SSL_CTX_free(ssl_ctx);
+ return ret;
+ }
+ SSL_set_connect_state(ssl);
+ SSL_set_verify(ssl, 0, ssl_verify_callback);
+ SSL_set_bio(ssl, ssl_bio, ssl_bio);
+
+ return_me = SSL_do_handshake(ssl);
+ if (return_me != 1) {
+ debug_info("ERROR in SSL_do_handshake: %s", errorstring(SSL_get_error(ssl, return_me)));
+ BIO_free(ssl_bio);
+ SSL_CTX_free(ssl_ctx);
+ } else {
+ ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private));
+ ssl_data_loc->session = ssl;
+ ssl_data_loc->ctx = ssl_ctx;
+ ssl_data_loc->bio = ssl_bio;
+ connection->ssl_data = ssl_data_loc;
+ ret = IDEVICE_E_SUCCESS;
+ debug_info("SSL mode enabled, cipher: %s", SSL_get_cipher(ssl));
+ }
+#else
ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private));
/* Set up GnuTLS... */
@@ -612,8 +757,9 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
debug_info("GnuTLS step 3...");
gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read);
debug_info("GnuTLS step 4 -- now handshaking...");
- if (errno)
+ if (errno) {
debug_info("WARN: errno says %s before handshake!", strerror(errno));
+ }
return_me = gnutls_handshake(ssl_data_loc->session);
debug_info("GnuTLS handshake done...");
@@ -628,6 +774,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
ret = IDEVICE_E_SUCCESS;
debug_info("SSL mode enabled");
}
+#endif
return ret;
}
@@ -649,9 +796,15 @@ idevice_error_t idevice_connection_disable_ssl(idevice_connection_t connection)
return IDEVICE_E_SUCCESS;
}
+#ifdef HAVE_OPENSSL
+ if (connection->ssl_data->session) {
+ SSL_shutdown(connection->ssl_data->session);
+ }
+#else
if (connection->ssl_data->session) {
gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR);
}
+#endif
internal_ssl_cleanup(connection->ssl_data);
free(connection->ssl_data);
connection->ssl_data = NULL;
diff --git a/src/idevice.h b/src/idevice.h
index 231b3ab..65fdae0 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -21,8 +21,18 @@
#ifndef IDEVICE_H
#define IDEVICE_H
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#else
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
+#endif
+
+#include "userpref.h"
#include "libimobiledevice/libimobiledevice.h"
@@ -31,12 +41,18 @@ enum connection_type {
};
struct ssl_data_private {
+#ifdef HAVE_OPENSSL
+ SSL *session;
+ SSL_CTX *ctx;
+ BIO *bio;
+#else
gnutls_certificate_credentials_t certificate;
gnutls_session_t session;
gnutls_x509_privkey_t root_privkey;
gnutls_x509_crt_t root_cert;
gnutls_x509_privkey_t host_privkey;
gnutls_x509_crt_t host_cert;
+#endif
};
typedef struct ssl_data_private *ssl_data_t;
diff --git a/src/lockdown.c b/src/lockdown.c
index 0f1e1b2..f22fb08 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -20,14 +20,24 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <string.h>
#include <stdlib.h>
#define _GNU_SOURCE 1
#define __USE_GNU 1
#include <stdio.h>
#include <ctype.h>
+#ifdef HAVE_OPENSSL
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#else
#include <libtasn1.h>
#include <gnutls/x509.h>
+#endif
#include <plist/plist.h>
#include "property_list_service.h"
@@ -40,6 +50,7 @@
#define RESULT_SUCCESS 0
#define RESULT_FAILURE 1
+#ifndef HAVE_OPENSSL
const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
{"PKCS1", 536872976, 0},
{0, 1073741836, 0},
@@ -48,6 +59,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
{"publicExponent", 3, 0},
{0, 0, 0}
};
+#endif
/**
* Internally used function for checking the result from lockdown's answer
@@ -567,7 +579,7 @@ lockdownd_error_t lockdownd_get_device_uuid(lockdownd_client_t client, char **uu
*
* @return LOCKDOWN_E_SUCCESS on success
*/
-lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnutls_datum_t * public_key)
+lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key)
{
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t value = NULL;
@@ -783,13 +795,13 @@ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_recor
*
* @return LOCKDOWN_E_SUCCESS on success
*/
-static lockdownd_error_t generate_pair_record_plist(gnutls_datum_t public_key, char *host_id, plist_t *pair_record_plist)
+static lockdownd_error_t generate_pair_record_plist(key_data_t public_key, char *host_id, plist_t *pair_record_plist)
{
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
- gnutls_datum_t device_cert = { NULL, 0 };
- gnutls_datum_t host_cert = { NULL, 0 };
- gnutls_datum_t root_cert = { NULL, 0 };
+ key_data_t device_cert = { NULL, 0 };
+ key_data_t host_cert = { NULL, 0 };
+ key_data_t root_cert = { NULL, 0 };
ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert);
if (ret != LOCKDOWN_E_SUCCESS) {
@@ -844,7 +856,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t dict = NULL;
plist_t dict_record = NULL;
- gnutls_datum_t public_key = { NULL, 0 };
+ key_data_t public_key = { NULL, 0 };
int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */
if (pair_record && pair_record->host_id) {
@@ -1096,14 +1108,145 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
* LOCKDOWN_E_INVALID_CONF if the internal configuration system failed,
* LOCKDOWN_E_SSL_ERROR if the certificates could not be generated
*/
-lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * odevice_cert,
- gnutls_datum_t * ohost_cert, gnutls_datum_t * oroot_cert)
+lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * odevice_cert,
+ key_data_t * ohost_cert, key_data_t * oroot_cert)
{
if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert)
return LOCKDOWN_E_INVALID_ARG;
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR;
+#ifdef HAVE_OPENSSL
+ BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size);
+ RSA *pubkey = NULL;
+ if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) {
+ debug_info("%s: Could not read public key", __func__);
+ }
+ BIO_free(membio);
+
+ /* now generate certificates */
+ key_data_t root_privkey, host_privkey;
+ key_data_t root_cert, host_cert;
+ X509* dev_cert;
+
+ root_cert.data = NULL;
+ root_cert.size = 0;
+ host_cert.data = NULL;
+ host_cert.size = 0;
+
+ dev_cert = X509_new();
+
+ root_privkey.data = NULL;
+ root_privkey.size = 0;
+ host_privkey.data = NULL;
+ host_privkey.size = 0;
+
+ uret = userpref_get_keys_and_certs(&root_privkey, &root_cert, &host_privkey, &host_cert);
+ if (USERPREF_E_SUCCESS == uret) {
+ /* generate device certificate */
+ ASN1_INTEGER* sn = ASN1_INTEGER_new();
+ ASN1_INTEGER_set(sn, 0);
+ X509_set_serialNumber(dev_cert, sn);
+ ASN1_INTEGER_free(sn);
+ X509_set_version(dev_cert, 2);
+
+ X509_EXTENSION* ext;
+ if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
+ debug_info("ERROR: X509V3_EXT_conf_nid failed");
+ }
+ X509_add_ext(dev_cert, ext, -1);
+
+ ASN1_TIME* asn1time = ASN1_TIME_new();
+ ASN1_TIME_set(asn1time, time(NULL));
+ X509_set_notBefore(dev_cert, asn1time);
+ ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
+ X509_set_notAfter(dev_cert, asn1time);
+ ASN1_TIME_free(asn1time);
+
+ BIO* membp;
+
+ X509* rootCert = NULL;
+ membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
+ PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
+ BIO_free(membp);
+ if (!rootCert) {
+ debug_info("Could not read RootCertificate%*s");
+ } else {
+ debug_info("RootCertificate loaded");
+ EVP_PKEY* pkey = EVP_PKEY_new();
+ EVP_PKEY_assign_RSA(pkey, pubkey);
+ X509_set_pubkey(dev_cert, pkey);
+ EVP_PKEY_free(pkey);
+ X509_free(rootCert);
+ }
+
+ EVP_PKEY* rootPriv = NULL;
+ membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
+ PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL);
+ BIO_free(membp);
+ if (!rootPriv) {
+ debug_info("Could not read RootPrivateKey");
+ } else {
+ debug_info("RootPrivateKey loaded");
+ if (X509_sign(dev_cert, rootPriv, EVP_sha1())) {
+ ret = LOCKDOWN_E_SUCCESS;
+ } else {
+ debug_info("signing failed");
+ }
+ EVP_PKEY_free(rootPriv);
+ }
+
+ if (LOCKDOWN_E_SUCCESS == ret) {
+ /* if everything went well, export in PEM format */
+ key_data_t pem_root_cert = { NULL, 0 };
+ key_data_t pem_host_cert = { NULL, 0 };
+
+ uret = userpref_get_certs_as_pem(&pem_root_cert, &pem_host_cert);
+ if (USERPREF_E_SUCCESS == uret) {
+ /* copy buffer for output */
+ membp = BIO_new(BIO_s_mem());
+ if (PEM_write_bio_X509(membp, dev_cert) > 0) {
+ odevice_cert->size = BIO_get_mem_data(membp, &odevice_cert->data);
+ }
+
+ ohost_cert->data = malloc(pem_host_cert.size);
+ memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
+ ohost_cert->size = pem_host_cert.size;
+
+ oroot_cert->data = malloc(pem_root_cert.size);
+ memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
+ oroot_cert->size = pem_root_cert.size;
+
+ free(pem_root_cert.data);
+ free(pem_host_cert.data);
+ }
+ }
+ }
+ X509V3_EXT_cleanup();
+ X509_free(dev_cert);
+
+ switch(uret) {
+ case USERPREF_E_INVALID_ARG:
+ ret = LOCKDOWN_E_INVALID_ARG;
+ break;
+ case USERPREF_E_INVALID_CONF:
+ ret = LOCKDOWN_E_INVALID_CONF;
+ break;
+ case USERPREF_E_SSL_ERROR:
+ ret = LOCKDOWN_E_SSL_ERROR;
+ default:
+ break;
+ }
+
+ if (root_cert.data)
+ free(root_cert.data);
+ if (host_cert.data)
+ free(host_cert.data);
+ if (root_privkey.data)
+ free(root_privkey.data);
+ if (host_privkey.data)
+ free(host_privkey.data);
+#else
gnutls_datum_t modulus = { NULL, 0 };
gnutls_datum_t exponent = { NULL, 0 };
@@ -1200,8 +1343,8 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
oroot_cert->size = pem_root_cert.size;
- free(pem_root_cert.data);
- free(pem_host_cert.data);
+ gnutls_free(pem_root_cert.data);
+ gnutls_free(pem_host_cert.data);
if (dev_pem.data)
gnutls_free(dev_pem.data);
@@ -1238,6 +1381,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
gnutls_free(exponent.data);
gnutls_free(der_pub_key.data);
+#endif
return ret;
}
diff --git a/src/lockdown.h b/src/lockdown.h
index a25e59d..a08b040 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -22,7 +22,7 @@
#ifndef LOCKDOWND_H
#define LOCKDOWND_H
-#include <gnutls/gnutls.h>
+#include "userpref.h"
#include "libimobiledevice/lockdown.h"
#include "property_list_service.h"
@@ -35,8 +35,7 @@ struct lockdownd_client_private {
char *label;
};
-lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnutls_datum_t * public_key);
-lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert,
- gnutls_datum_t * host_cert, gnutls_datum_t * root_cert);
+lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key);
+lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * device_cert, key_data_t * host_cert, key_data_t * root_cert);
#endif
diff --git a/src/userpref.c b/src/userpref.c
index f4e9fe6..409eb27 100644
--- a/src/userpref.c
+++ b/src/userpref.c
@@ -19,13 +19,23 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_OPENSSL
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#else
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gcrypt.h>
+#endif
#include <dirent.h>
#include <libgen.h>
@@ -526,7 +536,7 @@ userpref_error_t userpref_get_paired_uuids(char ***list, unsigned int *count)
* @return 1 on success and 0 if no public key is given or if it has already
* been marked as connected previously.
*/
-userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key)
+userpref_error_t userpref_set_device_public_key(const char *uuid, key_data_t public_key)
{
if (NULL == public_key.data)
return USERPREF_E_INVALID_ARG;
@@ -583,14 +593,14 @@ userpref_error_t userpref_remove_device_public_key(const char *uuid)
}
/**
- * Private function which reads the given file into a gnutls structure.
+ * Private function which reads the given file into a key_data_t structure.
*
* @param file The filename of the file to read
* @param data The pointer at which to store the data.
*
* @return 1 if the file contents where read successfully and 0 otherwise.
*/
-static int userpref_get_file_contents(const char *file, gnutls_datum_t * data)
+static int userpref_get_file_contents(const char *file, key_data_t * data)
{
int success;
unsigned long int size = 0;
@@ -637,7 +647,7 @@ static int userpref_get_file_contents(const char *file, gnutls_datum_t * data)
free(filepath);
- /* Add it to the gnutls_datnum_t structure */
+ /* Add it to the key_data_t structure */
if (success) {
data->data = (uint8_t*) content;
data->size = size;
@@ -655,6 +665,121 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
{
userpref_error_t ret = USERPREF_E_SSL_ERROR;
+ key_data_t root_key_pem = { NULL, 0 };
+ key_data_t root_cert_pem = { NULL, 0 };
+ key_data_t host_key_pem = { NULL, 0 };
+ key_data_t host_cert_pem = { NULL, 0 };
+
+#ifdef HAVE_OPENSSL
+ RSA* root_keypair = RSA_generate_key(2048, 65537, NULL, NULL);
+ RSA* host_keypair = RSA_generate_key(2048, 65537, NULL, NULL);
+
+ EVP_PKEY* root_pkey = EVP_PKEY_new();
+ EVP_PKEY_assign_RSA(root_pkey, root_keypair);
+
+ EVP_PKEY* host_pkey = EVP_PKEY_new();
+ EVP_PKEY_assign_RSA(host_pkey, host_keypair);
+
+ /* generate root certificate */
+ X509* root_cert = X509_new();
+ {
+ /* set serial number */
+ ASN1_INTEGER* sn = ASN1_INTEGER_new();
+ ASN1_INTEGER_set(sn, 0);
+ X509_set_serialNumber(root_cert, sn);
+ ASN1_INTEGER_free(sn);
+
+ /* set version */
+ X509_set_version(root_cert, 2);
+
+ /* set x509v3 basic constraints */
+ X509_EXTENSION* ext;
+ if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:TRUE"))) {
+ debug_info("ERROR: X509V3_EXT_conf_nid failed");
+ }
+ X509_add_ext(root_cert, ext, -1);
+
+ /* set key validity */
+ ASN1_TIME* asn1time = ASN1_TIME_new();
+ ASN1_TIME_set(asn1time, time(NULL));
+ X509_set_notBefore(root_cert, asn1time);
+ ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
+ X509_set_notAfter(root_cert, asn1time);
+ ASN1_TIME_free(asn1time);
+
+ /* use root public key for root cert */
+ X509_set_pubkey(root_cert, root_pkey);
+ /* sign root cert with root private key */
+ X509_sign(root_cert, root_pkey, EVP_sha1());
+ }
+
+ /* create host certificate */
+ X509* host_cert = X509_new();
+ {
+ /* set serial number */
+ ASN1_INTEGER* sn = ASN1_INTEGER_new();
+ ASN1_INTEGER_set(sn, 0);
+ X509_set_serialNumber(host_cert, sn);
+ ASN1_INTEGER_free(sn);
+
+ /* set version */
+ X509_set_version(host_cert, 2);
+
+ /* set x509v3 basic constraints */
+ X509_EXTENSION* ext;
+ if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
+ debug_info("ERROR: X509V3_EXT_conf_nid failed");
+ }
+ X509_add_ext(host_cert, ext, -1);
+
+ /* set x509v3 key usage */
+ if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"digitalSignature,keyEncipherment"))) {
+ debug_info("ERROR: X509V3_EXT_conf_nid failed");
+ }
+ X509_add_ext(host_cert, ext, -1);
+
+ /* set key validity */
+ ASN1_TIME* asn1time = ASN1_TIME_new();
+ ASN1_TIME_set(asn1time, time(NULL));
+ X509_set_notBefore(host_cert, asn1time);
+ ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
+ X509_set_notAfter(host_cert, asn1time);
+ ASN1_TIME_free(asn1time);
+
+ /* use host public key for host cert */
+ X509_set_pubkey(host_cert, host_pkey);
+
+ /* sign host cert with root private key */
+ X509_sign(host_cert, root_pkey, EVP_sha1());
+ }
+
+ if (root_cert && root_pkey && host_cert && host_pkey) {
+ BIO* membp;
+
+ membp = BIO_new(BIO_s_mem());
+ if (PEM_write_bio_X509(membp, root_cert) > 0) {
+ root_cert_pem.size = BIO_get_mem_data(membp, &root_cert_pem.data);
+ }
+ membp = BIO_new(BIO_s_mem());
+ if (PEM_write_bio_PrivateKey(membp, root_pkey, NULL, NULL, 0, 0, NULL) > 0) {
+ root_key_pem.size = BIO_get_mem_data(membp, &root_key_pem.data);
+ }
+ membp = BIO_new(BIO_s_mem());
+ if (PEM_write_bio_X509(membp, host_cert) > 0) {
+ host_cert_pem.size = BIO_get_mem_data(membp, &host_cert_pem.data);
+ }
+ membp = BIO_new(BIO_s_mem());
+ if (PEM_write_bio_PrivateKey(membp, host_pkey, NULL, NULL, 0, 0, NULL) > 0) {
+ host_key_pem.size = BIO_get_mem_data(membp, &host_key_pem.data);
+ }
+ }
+
+ EVP_PKEY_free(root_pkey);
+ EVP_PKEY_free(host_pkey);
+
+ X509_free(host_cert);
+ X509_free(root_cert);
+#else
gnutls_x509_privkey_t root_privkey;
gnutls_x509_crt_t root_cert;
gnutls_x509_privkey_t host_privkey;
@@ -697,8 +822,6 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
/* export to PEM format */
size_t root_key_export_size = 0;
size_t host_key_export_size = 0;
- gnutls_datum_t root_key_pem = { NULL, 0 };
- gnutls_datum_t host_key_pem = { NULL, 0 };
gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, NULL, &root_key_export_size);
gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, NULL, &host_key_export_size);
@@ -713,8 +836,6 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
size_t root_cert_export_size = 0;
size_t host_cert_export_size = 0;
- gnutls_datum_t root_cert_pem = { NULL, 0 };
- gnutls_datum_t host_cert_pem = { NULL, 0 };
gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, NULL, &root_cert_export_size);
gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, NULL, &host_cert_export_size);
@@ -727,6 +848,10 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size);
host_cert_pem.size = host_cert_export_size;
+ //restore gnutls env
+ gnutls_global_deinit();
+ gnutls_global_init();
+#endif
if (NULL != root_cert_pem.data && 0 != root_cert_pem.size &&
NULL != host_cert_pem.data && 0 != host_cert_pem.size)
ret = USERPREF_E_SUCCESS;
@@ -734,14 +859,14 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
/* store values in config file */
userpref_set_keys_and_certs( &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem);
- gnutls_free(root_key_pem.data);
- gnutls_free(root_cert_pem.data);
- gnutls_free(host_key_pem.data);
- gnutls_free(host_cert_pem.data);
-
- //restore gnutls env
- gnutls_global_deinit();
- gnutls_global_init();
+ if (root_key_pem.data)
+ free(root_key_pem.data);
+ if (root_cert_pem.data)
+ free(root_cert_pem.data);
+ if (host_key_pem.data)
+ free(host_key_pem.data);
+ if (host_cert_pem.data)
+ free(host_cert_pem.data);
return ret;
}
@@ -754,18 +879,33 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
*
* @return 1 if the key was successfully imported.
*/
+#ifdef HAVE_OPENSSL
+static userpref_error_t userpref_import_key(const char* key_name, key_data_t* key)
+#else
static userpref_error_t userpref_import_key(const char* key_name, gnutls_x509_privkey_t key)
+#endif
{
+#ifdef HAVE_OPENSSL
+ if (!key)
+ return USERPREF_E_SUCCESS;
+#endif
userpref_error_t ret = USERPREF_E_INVALID_CONF;
- gnutls_datum_t pem_key = { NULL, 0 };
-
+ key_data_t pem_key = { NULL, 0 };
if (userpref_get_file_contents(key_name, &pem_key)) {
- if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem_key, GNUTLS_X509_FMT_PEM))
- ret = USERPREF_E_SUCCESS;
- else
- ret = USERPREF_E_SSL_ERROR;
+#ifdef HAVE_OPENSSL
+ key->data = (unsigned char*)malloc(pem_key.size);
+ memcpy(key->data, pem_key.data, pem_key.size);
+ key->size = pem_key.size;
+ ret = USERPREF_E_SUCCESS;
+#else
+ if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem_key, GNUTLS_X509_FMT_PEM))
+ ret = USERPREF_E_SUCCESS;
+ else
+ ret = USERPREF_E_SSL_ERROR;
+#endif
}
- gnutls_free(pem_key.data);
+ if (pem_key.data)
+ free(pem_key.data);
return ret;
}
@@ -777,18 +917,34 @@ static userpref_error_t userpref_import_key(const char* key_name, gnutls_x509_pr
*
* @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
*/
+#ifdef HAVE_OPENSSL
+static userpref_error_t userpref_import_crt(const char* crt_name, key_data_t* cert)
+#else
static userpref_error_t userpref_import_crt(const char* crt_name, gnutls_x509_crt_t cert)
+#endif
{
+#ifdef HAVE_OPENSSL
+ if (!cert)
+ return USERPREF_E_SUCCESS;
+#endif
userpref_error_t ret = USERPREF_E_INVALID_CONF;
- gnutls_datum_t pem_cert = { NULL, 0 };
+ key_data_t pem_cert = { NULL, 0 };
if (userpref_get_file_contents(crt_name, &pem_cert)) {
- if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem_cert, GNUTLS_X509_FMT_PEM))
- ret = USERPREF_E_SUCCESS;
- else
- ret = USERPREF_E_SSL_ERROR;
+#ifdef HAVE_OPENSSL
+ cert->data = (unsigned char*)malloc(pem_cert.size);
+ memcpy(cert->data, pem_cert.data, pem_cert.size);
+ cert->size = pem_cert.size;
+ ret = USERPREF_E_SUCCESS;
+#else
+ if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem_cert, GNUTLS_X509_FMT_PEM))
+ ret = USERPREF_E_SUCCESS;
+ else
+ ret = USERPREF_E_SSL_ERROR;
+#endif
}
- gnutls_free(pem_cert.data);
+ if (pem_cert.data)
+ free(pem_cert.data);
return ret;
}
@@ -805,7 +961,11 @@ static userpref_error_t userpref_import_crt(const char* crt_name, gnutls_x509_cr
*
* @return 1 if the keys and certificates were successfully retrieved, 0 otherwise
*/
+#ifdef HAVE_OPENSSL
+userpref_error_t userpref_get_keys_and_certs(key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt)
+#else
userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt)
+#endif
{
userpref_error_t ret = USERPREF_E_SUCCESS;
@@ -821,7 +981,6 @@ userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey,
if (ret == USERPREF_E_SUCCESS)
ret = userpref_import_crt(LIBIMOBILEDEVICE_HOST_CERTIF, host_crt);
-
if (USERPREF_E_SUCCESS != ret) {
//we had problem reading or importing root cert
//try with a new ones.
@@ -851,7 +1010,7 @@ userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey,
*
* @return 1 if the certificates were successfully retrieved, 0 otherwise
*/
-userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert)
+userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t *pem_host_cert)
{
if (!pem_root_cert || !pem_host_cert)
return USERPREF_E_INVALID_ARG;
@@ -859,8 +1018,14 @@ userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls
if (userpref_get_file_contents(LIBIMOBILEDEVICE_ROOT_CERTIF, pem_root_cert) && userpref_get_file_contents(LIBIMOBILEDEVICE_HOST_CERTIF, pem_host_cert))
return USERPREF_E_SUCCESS;
else {
- gnutls_free(pem_root_cert->data);
- gnutls_free(pem_host_cert->data);
+ if (pem_root_cert->data) {
+ free(pem_root_cert->data);
+ pem_root_cert->size = 0;
+ }
+ if (pem_host_cert->data) {
+ free(pem_host_cert->data);
+ pem_host_cert->size = 0;
+ }
}
return USERPREF_E_INVALID_CONF;
}
@@ -877,7 +1042,7 @@ userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls
*
* @return 1 on success and 0 otherwise.
*/
-userpref_error_t userpref_set_keys_and_certs(gnutls_datum_t * root_key, gnutls_datum_t * root_cert, gnutls_datum_t * host_key, gnutls_datum_t * host_cert)
+userpref_error_t userpref_set_keys_and_certs(key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert)
{
FILE *pFile;
char *pem;
diff --git a/src/userpref.h b/src/userpref.h
index e16fd65..0e959ba 100644
--- a/src/userpref.h
+++ b/src/userpref.h
@@ -22,7 +22,19 @@
#ifndef USERPREF_H
#define USERPREF_H
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_OPENSSL
+typedef struct {
+ unsigned char *data;
+ unsigned int size;
+} key_data_t;
+#else
#include <gnutls/gnutls.h>
+typedef gnutls_datum_t key_data_t;
+#endif
#ifndef LIBIMOBILEDEVICE_INTERNAL
#ifdef WIN32
@@ -41,10 +53,14 @@
typedef int16_t userpref_error_t;
+#ifdef HAVE_OPENSSL
+LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_keys_and_certs(key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt);
+#else
LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt);
-LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_keys_and_certs(gnutls_datum_t * root_key, gnutls_datum_t * root_cert, gnutls_datum_t * host_key, gnutls_datum_t * host_cert);
-LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert);
-LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_public_key(const char *uuid, gnutls_datum_t public_key);
+#endif
+LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_keys_and_certs(key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert);
+LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t *pem_host_cert);
+LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_public_key(const char *uuid, key_data_t public_key);
userpref_error_t userpref_remove_device_public_key(const char *uuid);
LIBIMOBILEDEVICE_INTERNAL int userpref_has_device_public_key(const char *uuid);
userpref_error_t userpref_get_paired_uuids(char ***list, unsigned int *count);