From ab1c815340afc2883c9ef08795eebd9bed1858c5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 27 Jul 2021 03:36:45 +0200 Subject: Add support for MbedTLS --- common/userpref.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++------- common/userpref.h | 4 +- 2 files changed, 279 insertions(+), 41 deletions(-) (limited to 'common') 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 #include -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) #include #include #include @@ -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 #include #include #include #include +#elif defined(HAVE_MBEDTLS) +#include +#include +#include +#include +#include +#else +#error No supported TLS/SSL library enabled #endif #include @@ -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 { diff --git a/common/userpref.h b/common/userpref.h index 4ea630f..072721a 100644 --- a/common/userpref.h +++ b/common/userpref.h @@ -27,7 +27,7 @@ #include #endif -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) typedef struct { unsigned char *data; unsigned int size; @@ -68,7 +68,7 @@ userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, userpref_error_t userpref_delete_pair_record(const char *udid); userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key); -#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); userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert); #else -- cgit v1.1-32-gdbae