summaryrefslogtreecommitdiffstats
path: root/src/userpref.c
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/userpref.c
parent294cf69b256419e407b1eac04634752412ee7756 (diff)
downloadlibimobiledevice-8b1af4cf80eff619d3465925dce7fe572fc09224.tar.gz
libimobiledevice-8b1af4cf80eff619d3465925dce7fe572fc09224.tar.bz2
Add OpenSSL support
Diffstat (limited to 'src/userpref.c')
-rw-r--r--src/userpref.c233
1 files changed, 199 insertions, 34 deletions
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;