summaryrefslogtreecommitdiffstats
path: root/common/userpref.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/userpref.c')
-rw-r--r--common/userpref.c316
1 files changed, 277 insertions, 39 deletions
diff --git a/common/userpref.c b/common/userpref.c
index a5aa7cb..0c6050f 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -2,6 +2,7 @@
* userpref.c
* contains methods to access user specific certificates IDs and more.
*
+ * Copyright (c) 2013-2021 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2013-2014 Martin Szulecki All Rights Reserved.
* Copyright (c) 2008 Jonathan Beck All Rights Reserved.
*
@@ -36,7 +37,7 @@
#endif
#include <unistd.h>
#include <usbmuxd.h>
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
@@ -47,12 +48,20 @@
#define X509_set1_notBefore X509_set_notBefore
#define X509_set1_notAfter X509_set_notAfter
#endif
-#else
+#elif defined(HAVE_GNUTLS)
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <gnutls/x509.h>
#include <gcrypt.h>
#include <libtasn1.h>
+#elif defined(HAVE_MBEDTLS)
+#include <mbedtls/ssl.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/asn1write.h>
+#include <mbedtls/oid.h>
+#else
+#error No supported TLS/SSL library enabled
#endif
#include <dirent.h>
@@ -68,7 +77,7 @@
#include "debug.h"
#include "utils.h"
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_GNUTLS)
const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
{"PKCS1", 536872976, 0},
{0, 1073741836, 0},
@@ -343,7 +352,7 @@ userpref_error_t userpref_delete_pair_record(const char *udid)
return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
}
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
static int X509_add_ext_helper(X509 *cert, int nid, char *value)
{
X509_EXTENSION *ex;
@@ -364,6 +373,31 @@ static int X509_add_ext_helper(X509 *cert, int nid, char *value)
return 1;
}
+#elif defined(HAVE_MBEDTLS)
+static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509write_cert *ctx, int is_ca, int max_pathlen)
+{
+ int ret;
+ unsigned char buf[9];
+ unsigned char *c = buf + sizeof(buf);
+ size_t len = 0;
+
+ memset( buf, 0, sizeof(buf) );
+
+ if (is_ca && max_pathlen > 127)
+ return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
+
+ if (is_ca) {
+ if (max_pathlen >= 0) {
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) );
+ }
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
+ }
+
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
+ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
+
+ return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), 1, buf + sizeof(buf) - len, len );
+}
#endif
/**
@@ -390,7 +424,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
debug_info("Generating keys and certificates...");
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL)
BIGNUM *e = BN_new();
RSA* root_keypair = RSA_new();
RSA* host_keypair = RSA_new();
@@ -579,7 +613,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
X509_free(host_cert);
X509_free(root_cert);
-#else
+#elif defined(HAVE_GNUTLS)
gnutls_x509_privkey_t root_privkey;
gnutls_x509_crt_t root_cert;
gnutls_x509_privkey_t host_privkey;
@@ -749,6 +783,211 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
gnutls_free(exponent.data);
gnutls_free(der_pub_key.data);
+#elif defined(HAVE_MBEDTLS)
+ time_t now = time(NULL);
+ struct tm* timestamp = gmtime(&now);
+ char notbefore[16];
+ strftime(notbefore, sizeof(notbefore), "%Y%m%d%H%M%S", timestamp);
+ time_t then = now + 60 * 60 * 24 * 365 * 10;
+ char notafter[16];
+ timestamp = gmtime(&then);
+ strftime(notafter, sizeof(notafter), "%Y%m%d%H%M%S", timestamp);
+
+ mbedtls_mpi sn;
+ mbedtls_mpi_init(&sn);
+ mbedtls_mpi_lset(&sn, 1); /* 0 doesn't work, so we have to use 1 (like GnuTLS) */
+
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+ mbedtls_pk_context root_pkey;
+ mbedtls_pk_init(&root_pkey);
+
+ mbedtls_pk_context host_pkey;
+ mbedtls_pk_init(&host_pkey);
+
+ mbedtls_pk_context dev_public_key;
+ mbedtls_pk_init(&dev_public_key);
+
+ mbedtls_entropy_context entropy;
+ mbedtls_entropy_init(&entropy);
+
+ mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"limd", 4);
+
+ /* ----- root key & cert ----- */
+ ret = mbedtls_pk_setup(&root_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
+ if (ret != 0) {
+ debug_info("mbedtls_pk_setup returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(root_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);
+ if (ret != 0) {
+ debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ mbedtls_x509write_cert cert;
+ mbedtls_x509write_crt_init(&cert);
+
+ /* set serial number */
+ mbedtls_x509write_crt_set_serial(&cert, &sn);
+
+ /* set version */
+ mbedtls_x509write_crt_set_version(&cert, 2);
+
+ /* set x509v3 basic constraints */
+ _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 1, -1);
+
+ /* use root public key for root cert */
+ mbedtls_x509write_crt_set_subject_key(&cert, &root_pkey);
+
+ /* set x509v3 subject key identifier */
+ mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+
+ /* set key validity */
+ mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter);
+
+ /* sign root cert with root private key */
+ mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey);
+ mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1);
+
+ unsigned char outbuf[16384];
+
+ /* write root private key */
+ mbedtls_pk_write_key_pem(&root_pkey, outbuf, sizeof(outbuf));
+ root_key_pem.size = strlen((const char*)outbuf);
+ root_key_pem.data = malloc(root_key_pem.size+1);
+ memcpy(root_key_pem.data, outbuf, root_key_pem.size);
+ root_key_pem.data[root_key_pem.size] = '\0';
+
+ /* write root certificate */
+ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ root_cert_pem.size = strlen((const char*)outbuf);
+ root_cert_pem.data = malloc(root_cert_pem.size+1);
+ memcpy(root_cert_pem.data, outbuf, root_cert_pem.size);
+ root_cert_pem.data[root_cert_pem.size] = '\0';
+
+ mbedtls_x509write_crt_free(&cert);
+
+
+ /* ----- host key & cert ----- */
+ ret = mbedtls_pk_setup(&host_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
+ if (ret != 0) {
+ debug_info("mbedtls_pk_setup returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(host_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);
+ if (ret != 0) {
+ debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret);
+ goto cleanup;
+ }
+
+ mbedtls_x509write_crt_init(&cert);
+
+ /* set serial number */
+ mbedtls_x509write_crt_set_serial(&cert, &sn);
+
+ /* set version */
+ mbedtls_x509write_crt_set_version(&cert, 2);
+
+ /* set x509v3 basic constraints */
+ _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1);
+
+ /* use host public key for host cert */
+ mbedtls_x509write_crt_set_subject_key(&cert, &host_pkey);
+
+ /* set x509v3 subject key identifier */
+ mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+
+ /* set x509v3 key usage */
+ mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
+
+ /* set key validity */
+ mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter);
+
+ /* sign host cert with root private key */
+ mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey);
+ mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1);
+
+ /* write host private key */
+ mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf));
+ host_key_pem.size = strlen((const char*)outbuf);
+ host_key_pem.data = malloc(host_key_pem.size+1);
+ memcpy(host_key_pem.data, outbuf, host_key_pem.size);
+ host_key_pem.data[host_key_pem.size] = '\0';
+
+ /* write host certificate */
+ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ host_cert_pem.size = strlen((const char*)outbuf);
+ host_cert_pem.data = malloc(host_cert_pem.size+1);
+ memcpy(host_cert_pem.data, outbuf, host_cert_pem.size);
+ host_cert_pem.data[host_cert_pem.size] = '\0';
+
+ mbedtls_x509write_crt_free(&cert);
+
+
+ /* ----- device certificate ----- */
+ unsigned char* pubkey_data = malloc(public_key.size+1);
+ if (!pubkey_data) {
+ debug_info("malloc() failed\n");
+ goto cleanup;
+ }
+ memcpy(pubkey_data, public_key.data, public_key.size);
+ pubkey_data[public_key.size] = '\0';
+
+ int pr = mbedtls_pk_parse_public_key(&dev_public_key, pubkey_data, public_key.size+1);
+ free(pubkey_data);
+ if (pr != 0) {
+ debug_info("Failed to read device public key: -0x%x\n", -pr);
+ goto cleanup;
+ }
+
+ mbedtls_x509write_crt_init(&cert);
+
+ /* set serial number */
+ mbedtls_x509write_crt_set_serial(&cert, &sn);
+
+ /* set version */
+ mbedtls_x509write_crt_set_version(&cert, 2);
+
+ /* set x509v3 basic constraints */
+ _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1);
+
+ /* use root public key for dev cert subject key */
+ mbedtls_x509write_crt_set_subject_key(&cert, &dev_public_key);
+
+ /* set x509v3 subject key identifier */
+ mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+
+ /* set x509v3 key usage */
+ mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
+
+ /* set key validity */
+ mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter);
+
+ /* sign device certificate with root private key */
+ mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey);
+ mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1);
+
+ /* write device certificate */
+ mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
+ dev_cert_pem.size = strlen((const char*)outbuf);
+ dev_cert_pem.data = malloc(dev_cert_pem.size+1);
+ memcpy(dev_cert_pem.data, outbuf, dev_cert_pem.size);
+ dev_cert_pem.data[dev_cert_pem.size] = '\0';
+
+ mbedtls_x509write_crt_free(&cert);
+
+ /* cleanup */
+cleanup:
+ mbedtls_mpi_free(&sn);
+ mbedtls_pk_free(&dev_public_key);
+ mbedtls_entropy_free(&entropy);
+ mbedtls_pk_free(&host_pkey);
+ mbedtls_pk_free(&root_pkey);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
#endif
/* make sure that we have all we need */
@@ -783,32 +1022,31 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
*
* @return 1 if the key was successfully imported.
*/
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key)
-#else
+#elif defined(HAVE_GNUTLS)
userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key)
#endif
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
if (!key)
return USERPREF_E_SUCCESS;
#endif
userpref_error_t ret = USERPREF_E_INVALID_CONF;
-#ifdef HAVE_OPENSSL
- ret = pair_record_get_item_as_key_data(pair_record, name, key);
-#else
- key_data_t pem = { NULL, 0 };
- ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
- if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM))
- ret = USERPREF_E_SUCCESS;
- else
- ret = USERPREF_E_SSL_ERROR;
-
- if (pem.data)
- free(pem.data);
-#endif
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
+ ret = pair_record_get_item_as_key_data(pair_record, name, key);
+#elif defined(HAVE_GNUTLS)
+ key_data_t pem = { NULL, 0 };
+ ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
+ if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM))
+ ret = USERPREF_E_SUCCESS;
+ else
+ ret = USERPREF_E_SSL_ERROR;
+ if (pem.data)
+ free(pem.data);
+#endif
return ret;
}
@@ -820,32 +1058,31 @@ userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const cha
*
* @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
*/
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert)
#else
userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert)
#endif
{
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
if (!cert)
return USERPREF_E_SUCCESS;
#endif
userpref_error_t ret = USERPREF_E_INVALID_CONF;
-#ifdef HAVE_OPENSSL
- ret = pair_record_get_item_as_key_data(pair_record, name, cert);
-#else
- key_data_t pem = { NULL, 0 };
- ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
- if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
- ret = USERPREF_E_SUCCESS;
- else
- ret = USERPREF_E_SSL_ERROR;
-
- if (pem.data)
- free(pem.data);
-#endif
+#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
+ ret = pair_record_get_item_as_key_data(pair_record, name, cert);
+#elif defined(HAVE_GNUTLS)
+ key_data_t pem = { NULL, 0 };
+ ret = pair_record_get_item_as_key_data(pair_record, name, &pem);
+ if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
+ ret = USERPREF_E_SUCCESS;
+ else
+ ret = USERPREF_E_SSL_ERROR;
+ if (pem.data)
+ free(pem.data);
+#endif
return ret;
}
@@ -880,9 +1117,10 @@ userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const cha
if (node && plist_get_node_type(node) == PLIST_DATA) {
plist_get_data_val(node, &buffer, &length);
- value->data = (unsigned char*)malloc(length);
+ value->data = (unsigned char*)malloc(length+1);
memcpy(value->data, buffer, length);
- value->size = length;
+ value->data[length] = '\0';
+ value->size = length+1;
free(buffer);
buffer = NULL;
} else {