summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/userpref.c989
-rw-r--r--common/userpref.h34
-rw-r--r--common/utils.c30
-rw-r--r--common/utils.h1
4 files changed, 469 insertions, 585 deletions
diff --git a/common/userpref.c b/common/userpref.c
index c192c1d..d9641cb 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -35,6 +35,7 @@
35#include <pwd.h> 35#include <pwd.h>
36#endif 36#endif
37#include <unistd.h> 37#include <unistd.h>
38#include <usbmuxd.h>
38#ifdef HAVE_OPENSSL 39#ifdef HAVE_OPENSSL
39#include <openssl/pem.h> 40#include <openssl/pem.h>
40#include <openssl/rsa.h> 41#include <openssl/rsa.h>
@@ -59,6 +60,17 @@
59#include "debug.h" 60#include "debug.h"
60#include "utils.h" 61#include "utils.h"
61 62
63#ifndef HAVE_OPENSSL
64const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
65 {"PKCS1", 536872976, 0},
66 {0, 1073741836, 0},
67 {"RSAPublicKey", 536870917, 0},
68 {"modulus", 1073741827, 0},
69 {"publicExponent", 3, 0},
70 {0, 0, 0}
71};
72#endif
73
62#ifdef WIN32 74#ifdef WIN32
63#define DIR_SEP '\\' 75#define DIR_SEP '\\'
64#define DIR_SEP_S "\\" 76#define DIR_SEP_S "\\"
@@ -158,274 +170,20 @@ const char *userpref_get_config_dir()
158 return __config_dir; 170 return __config_dir;
159} 171}
160 172
161static int __mkdir(const char *dir, int mode)
162{
163#ifdef WIN32
164 return mkdir(dir);
165#else
166 return mkdir(dir, mode);
167#endif
168}
169
170static int mkdir_with_parents(const char *dir, int mode)
171{
172 if (!dir) return -1;
173 if (__mkdir(dir, mode) == 0) {
174 return 0;
175 } else {
176 if (errno == EEXIST) return 0;
177 }
178 int res;
179 char *parent = strdup(dir);
180 char* parentdir = dirname(parent);
181 if (parentdir) {
182 res = mkdir_with_parents(parentdir, mode);
183 } else {
184 res = -1;
185 }
186 free(parent);
187 return res;
188}
189
190/**
191 * Creates a freedesktop compatible configuration directory.
192 */
193static void userpref_create_config_dir(void)
194{
195 const char *config_path = userpref_get_config_dir();
196 struct stat st;
197 if (stat(config_path, &st) != 0) {
198 mkdir_with_parents(config_path, 0755);
199 }
200}
201
202static int get_rand(int min, int max)
203{
204 int retval = (rand() % (max - min)) + min;
205 return retval;
206}
207
208/**
209 * Generates a valid HostID (which is actually a UUID).
210 *
211 * @return A null terminated string containing a valid HostID.
212 */
213static char *userpref_generate_host_id(int idx)
214{
215 /* HostID's are just UUID's, and UUID's are 36 characters long */
216 char *hostid = (char *) malloc(sizeof(char) * 37);
217 const char *chars = "ABCDEF0123456789";
218 srand(time(NULL) - idx);
219 int i = 0;
220
221 for (i = 0; i < 36; i++) {
222 if (i == 8 || i == 13 || i == 18 || i == 23) {
223 hostid[i] = '-';
224 continue;
225 } else {
226 hostid[i] = chars[get_rand(0, 16)];
227 }
228 }
229 /* make it a real string */
230 hostid[36] = '\0';
231 return hostid;
232}
233
234/**
235 * Generates a valid BUID for this system (which is actually a UUID).
236 *
237 * @return A null terminated string containing a valid BUID.
238 */
239static char *userpref_generate_system_buid()
240{
241 return userpref_generate_host_id(1);
242}
243
244static int internal_set_value(const char *config_file, const char *key, plist_t value)
245{
246 if (!config_file)
247 return 0;
248
249 /* read file into plist */
250 plist_t config = NULL;
251
252 plist_read_from_filename(&config, config_file);
253 if (!config) {
254 config = plist_new_dict();
255 plist_dict_set_item(config, key, value);
256 } else {
257 plist_t n = plist_dict_get_item(config, key);
258 if (n) {
259 plist_dict_remove_item(config, key);
260 }
261 plist_dict_set_item(config, key, value);
262 remove(config_file);
263 }
264
265 /* store in config file */
266 char *value_string = NULL;
267 if (plist_get_node_type(value) == PLIST_STRING) {
268 plist_get_string_val(value, &value_string);
269 debug_info("setting key %s to %s in config_file %s", key, value_string, config_file);
270 if (value_string)
271 free(value_string);
272 } else {
273 debug_info("setting key %s in config_file %s", key, config_file);
274 }
275
276 plist_write_to_filename(config, config_file, PLIST_FORMAT_XML);
277
278 plist_free(config);
279
280 return 1;
281}
282
283int userpref_set_value(const char *key, plist_t value)
284{
285 const char *config_path = NULL;
286 char *config_file = NULL;
287
288 /* Make sure config directory exists */
289 userpref_create_config_dir();
290
291 config_path = userpref_get_config_dir();
292 config_file = string_concat(config_path, DIR_SEP_S, USERPREF_CONFIG_FILE, NULL);
293
294 int result = internal_set_value(config_file, key, value);
295
296 free(config_file);
297
298 return result;
299}
300
301int userpref_device_record_set_value(const char *udid, const char *key, plist_t value)
302{
303 const char *config_path = NULL;
304 char *config_file = NULL;
305
306 /* Make sure config directory exists */
307 userpref_create_config_dir();
308
309 config_path = userpref_get_config_dir();
310 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
311
312 int result = internal_set_value(config_file, key, value);
313
314 free(config_file);
315
316 return result;
317}
318
319static int internal_get_value(const char* config_file, const char *key, plist_t *value)
320{
321 *value = NULL;
322
323 /* now parse file to get the SystemBUID */
324 plist_t config = NULL;
325 if (plist_read_from_filename(&config, config_file)) {
326 debug_info("reading key %s from config_file %s", key, config_file);
327 plist_t n = plist_dict_get_item(config, key);
328 if (n) {
329 *value = plist_copy(n);
330 n = NULL;
331 }
332 }
333 plist_free(config);
334
335 return 1;
336}
337
338int userpref_get_value(const char *key, plist_t *value)
339{
340 const char *config_path = NULL;
341 char *config_file = NULL;
342
343 config_path = userpref_get_config_dir();
344 config_file = string_concat(config_path, DIR_SEP_S, USERPREF_CONFIG_FILE, NULL);
345
346 int result = internal_get_value(config_file, key, value);
347
348 free(config_file);
349
350 return result;
351}
352
353int userpref_device_record_get_value(const char *udid, const char *key, plist_t *value)
354{
355 const char *config_path = NULL;
356 char *config_file = NULL;
357
358 config_path = userpref_get_config_dir();
359 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
360
361 int result = internal_get_value(config_file, key, value);
362
363 free(config_file);
364
365 return result;
366}
367
368/**
369 * Store SystemBUID in config file.
370 *
371 * @param host_id A null terminated string containing a valid SystemBUID.
372 */
373static int userpref_set_system_buid(const char *system_buid)
374{
375 return userpref_set_value(USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid));
376}
377
378/** 173/**
379 * Reads the BUID from a previously generated configuration file. 174 * Reads the BUID from a previously generated configuration file.
380 * 175 *
381 * @note It is the responsibility of the calling function to free the returned system_buid 176 * @note It is the responsibility of the calling function to free the returned system_buid
382 * 177 * @param system_buid A null terminated string containing a valid SystemBUID.
383 * @return The string containing the BUID or NULL 178 * @return 1 if the system buid could be retrieved or 0 otherwise.
384 */ 179 */
385void userpref_get_system_buid(char **system_buid) 180int userpref_read_system_buid(char **system_buid)
386{ 181{
387 plist_t value = NULL; 182 int res = usbmuxd_read_buid(system_buid);
388
389 userpref_get_value(USERPREF_SYSTEM_BUID_KEY, &value);
390
391 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
392 plist_get_string_val(value, system_buid);
393 debug_info("got %s %s", USERPREF_SYSTEM_BUID_KEY, *system_buid);
394 }
395
396 if (value)
397 plist_free(value);
398
399 if (!*system_buid) {
400 /* no config, generate system_buid */
401 debug_info("no previous %s found", USERPREF_SYSTEM_BUID_KEY);
402 *system_buid = userpref_generate_system_buid();
403 userpref_set_system_buid(*system_buid);
404 }
405 183
406 debug_info("using %s as %s", *system_buid, USERPREF_SYSTEM_BUID_KEY); 184 debug_info("using %s as %s", *system_buid, USERPREF_SYSTEM_BUID_KEY);
407}
408
409void userpref_device_record_get_host_id(const char *udid, char **host_id)
410{
411 plist_t value = NULL;
412
413 userpref_device_record_get_value(udid, USERPREF_HOST_ID_KEY, &value);
414
415 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
416 plist_get_string_val(value, host_id);
417 }
418
419 if (value)
420 plist_free(value);
421 185
422 if (!*host_id) { 186 return res;
423 /* no config, generate host_id */
424 *host_id = userpref_generate_host_id(0);
425 userpref_device_record_set_value(udid, USERPREF_HOST_ID_KEY, plist_new_string(*host_id));
426 }
427
428 debug_info("using %s as %s", *host_id, USERPREF_HOST_ID_KEY);
429} 187}
430 188
431/** 189/**
@@ -436,7 +194,7 @@ void userpref_device_record_get_host_id(const char *udid, char **host_id)
436 * @return 1 if the device has been connected previously to this configuration 194 * @return 1 if the device has been connected previously to this configuration
437 * or 0 otherwise. 195 * or 0 otherwise.
438 */ 196 */
439int userpref_has_device_record(const char *udid) 197int userpref_has_pair_record(const char *udid)
440{ 198{
441 int ret = 0; 199 int ret = 0;
442 const char *config_path = NULL; 200 const char *config_path = NULL;
@@ -536,50 +294,61 @@ userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count)
536} 294}
537 295
538/** 296/**
539 * Mark the device as having connected to this configuration. 297 * Save a pair record for a device.
540 * 298 *
541 * @param udid The device UDID as given by the device 299 * @param udid The device UDID as given by the device
542 * @param device_record The device record with full configuration 300 * @param pair_record The pair record to save
543 * 301 *
544 * @return 1 on success and 0 if no device record is given or if it has already 302 * @return 1 on success and 0 if no device record is given or if it has already
545 * been marked as connected previously. 303 * been saved previously.
546 */ 304 */
547userpref_error_t userpref_set_device_record(const char *udid, plist_t device_record) 305userpref_error_t userpref_save_pair_record(const char *udid, plist_t pair_record)
548{ 306{
549 /* ensure config directory exists */ 307 char* record_data = NULL;
550 userpref_create_config_dir(); 308 uint32_t record_size = 0;
551 309
552 /* build file path */ 310 plist_to_bin(pair_record, &record_data, &record_size);
553 const char *config_path = userpref_get_config_dir();
554 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
555 311
556 remove(device_record_file); 312 int res = usbmuxd_save_pair_record(udid, record_data, record_size);
557 313
558 /* store file */ 314 free(record_data);
559 if (!plist_write_to_filename(device_record, device_record_file, PLIST_FORMAT_XML)) {
560 debug_info("could not open '%s' for writing: %s", device_record_file, strerror(errno));
561 }
562 free(device_record_file);
563 315
564 return USERPREF_E_SUCCESS; 316 return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
565} 317}
566 318
567userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_record) 319/**
320 * Read a pair record for a device.
321 *
322 * @param udid The device UDID as given by the device
323 * @param pair_record The pair record to read
324 *
325 * @return 1 on success and 0 if no device record is given or if it has already
326 * been saved previously.
327 */
328userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_record)
568{ 329{
569 /* ensure config directory exists */ 330 char* record_data = NULL;
570 userpref_create_config_dir(); 331 uint32_t record_size = 0;
332
333 int res = usbmuxd_read_pair_record(udid, &record_data, &record_size);
571 334
572 /* build file path */ 335 if (res < 0) {
573 const char *config_path = userpref_get_config_dir(); 336 if (record_data)
574 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL); 337 free(record_data);
575 338
576 /* read file */ 339 return USERPREF_E_INVALID_CONF;
577 if (!plist_read_from_filename(device_record, device_record_file)) {
578 debug_info("could not open '%s' for reading: %s", device_record_file, strerror(errno));
579 } 340 }
580 free(device_record_file);
581 341
582 return USERPREF_E_SUCCESS; 342 *pair_record = NULL;
343 if (memcmp(record_data, "bplist00", 8) == 0) {
344 plist_from_bin(record_data, record_size, pair_record);
345 } else {
346 plist_from_xml(record_data, record_size, pair_record);
347 }
348
349 free(record_data);
350
351 return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
583} 352}
584 353
585/** 354/**
@@ -589,87 +358,33 @@ userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_re
589 * 358 *
590 * @return USERPREF_E_SUCCESS on success. 359 * @return USERPREF_E_SUCCESS on success.
591 */ 360 */
592userpref_error_t userpref_remove_device_record(const char *udid) 361userpref_error_t userpref_delete_pair_record(const char *udid)
593{ 362{
594 userpref_error_t res = USERPREF_E_SUCCESS; 363 int res = usbmuxd_delete_pair_record(udid);
595 if (!userpref_has_device_record(udid))
596 return res;
597
598 /* build file path */
599 const char *config_path = userpref_get_config_dir();
600 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
601
602 /* remove file */
603 if (remove(device_record_file) != 0) {
604 debug_info("could not remove %s: %s", device_record_file, strerror(errno));
605 res = USERPREF_E_UNKNOWN_ERROR;
606 }
607 364
608 free(device_record_file); 365 return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
609
610 return res;
611} 366}
612 367
613#if 0 368#ifdef HAVE_OPENSSL
614/** 369static int X509_add_ext_helper(X509 *cert, int nid, char *value)
615 * Private function which reads the given file into a key_data_t structure.
616 *
617 * @param file The filename of the file to read
618 * @param data The pointer at which to store the data.
619 *
620 * @return 1 if the file contents where read successfully and 0 otherwise.
621 */
622static int userpref_get_file_contents(const char *file, key_data_t * data)
623{ 370{
624 int success = 0; 371 X509_EXTENSION *ex;
625 unsigned long int size = 0; 372 X509V3_CTX ctx;
626 unsigned char *content = NULL;
627 const char *config_path = NULL;
628 char *filepath;
629 FILE *fd;
630
631 if (NULL == file || NULL == data)
632 return 0;
633
634 /* Read file */
635 config_path = userpref_get_config_dir();
636 filepath = string_concat(config_path, DIR_SEP_S, file, NULL);
637 373
638 fd = fopen(filepath, "rb"); 374 /* No configuration database */
639 if (fd) { 375 X509V3_set_ctx_nodb(&ctx);
640 fseek(fd, 0, SEEK_END);
641 size = ftell(fd);
642 fseek(fd, 0, SEEK_SET);
643 376
644 // prevent huge files 377 X509V3_set_ctx(&ctx, NULL, cert, NULL, NULL, 0);
645 if (size > 0xFFFFFF) { 378 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
646 fprintf(stderr, "%s: file is too big (> 16MB). Refusing to read the contents to memory!", __func__); 379 if (!ex) {
647 } else { 380 debug_info("ERROR: X509V3_EXT_conf_nid(%d, %s) failed", nid, value);
648 size_t p = 0; 381 return 0;
649 content = (unsigned char*)malloc(size);
650 while (!feof(fd)) {
651 p += fread(content+p, 1, size-p, fd);
652 if (ferror(fd) != 0) {
653 break;
654 }
655 if (p >= size) {
656 success = 1;
657 break;
658 }
659 }
660 }
661 fclose(fd);
662 } 382 }
663 383
664 free(filepath); 384 X509_add_ext(cert, ex, -1);
385 X509_EXTENSION_free(ex);
665 386
666 /* Add it to the key_data_t structure */ 387 return 1;
667 if (success) {
668 data->data = (uint8_t*) content;
669 data->size = size;
670 }
671
672 return success;
673} 388}
674#endif 389#endif
675 390
@@ -678,7 +393,7 @@ static int userpref_get_file_contents(const char *file, key_data_t * data)
678 * 393 *
679 * @return 1 if keys were successfully generated, 0 otherwise 394 * @return 1 if keys were successfully generated, 0 otherwise
680 */ 395 */
681static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udid) 396userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record)
682{ 397{
683 userpref_error_t ret = USERPREF_E_SSL_ERROR; 398 userpref_error_t ret = USERPREF_E_SSL_ERROR;
684 399
@@ -687,7 +402,8 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
687 key_data_t host_key_pem = { NULL, 0 }; 402 key_data_t host_key_pem = { NULL, 0 };
688 key_data_t host_cert_pem = { NULL, 0 }; 403 key_data_t host_cert_pem = { NULL, 0 };
689 404
690 debug_info("generating keys and certificates"); 405 debug_info("Generating keys and certificates...");
406
691#ifdef HAVE_OPENSSL 407#ifdef HAVE_OPENSSL
692 BIGNUM *e = BN_new(); 408 BIGNUM *e = BN_new();
693 RSA* root_keypair = RSA_new(); 409 RSA* root_keypair = RSA_new();
@@ -719,11 +435,7 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
719 X509_set_version(root_cert, 2); 435 X509_set_version(root_cert, 2);
720 436
721 /* set x509v3 basic constraints */ 437 /* set x509v3 basic constraints */
722 X509_EXTENSION* ext; 438 X509_add_ext_helper(root_cert, NID_basic_constraints, (char*)"critical,CA:TRUE");
723 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:TRUE"))) {
724 debug_info("ERROR: X509V3_EXT_conf_nid failed");
725 }
726 X509_add_ext(root_cert, ext, -1);
727 439
728 /* set key validity */ 440 /* set key validity */
729 ASN1_TIME* asn1time = ASN1_TIME_new(); 441 ASN1_TIME* asn1time = ASN1_TIME_new();
@@ -735,6 +447,7 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
735 447
736 /* use root public key for root cert */ 448 /* use root public key for root cert */
737 X509_set_pubkey(root_cert, root_pkey); 449 X509_set_pubkey(root_cert, root_pkey);
450
738 /* sign root cert with root private key */ 451 /* sign root cert with root private key */
739 X509_sign(root_cert, root_pkey, EVP_sha1()); 452 X509_sign(root_cert, root_pkey, EVP_sha1());
740 } 453 }
@@ -752,17 +465,10 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
752 X509_set_version(host_cert, 2); 465 X509_set_version(host_cert, 2);
753 466
754 /* set x509v3 basic constraints */ 467 /* set x509v3 basic constraints */
755 X509_EXTENSION* ext; 468 X509_add_ext_helper(host_cert, NID_basic_constraints, (char*)"critical,CA:FALSE");
756 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
757 debug_info("ERROR: X509V3_EXT_conf_nid failed");
758 }
759 X509_add_ext(host_cert, ext, -1);
760 469
761 /* set x509v3 key usage */ 470 /* set x509v3 key usage */
762 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"digitalSignature,keyEncipherment"))) { 471 X509_add_ext_helper(host_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");
763 debug_info("ERROR: X509V3_EXT_conf_nid failed");
764 }
765 X509_add_ext(host_cert, ext, -1);
766 472
767 /* set key validity */ 473 /* set key validity */
768 ASN1_TIME* asn1time = ASN1_TIME_new(); 474 ASN1_TIME* asn1time = ASN1_TIME_new();
@@ -907,8 +613,11 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
907 NULL != host_cert_pem.data && 0 != host_cert_pem.size) 613 NULL != host_cert_pem.data && 0 != host_cert_pem.size)
908 ret = USERPREF_E_SUCCESS; 614 ret = USERPREF_E_SUCCESS;
909 615
910 /* store values in config file */ 616 /* now set keys and certificates */
911 userpref_device_record_set_keys_and_certs(udid, &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem); 617 pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_key_pem);
618 pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &root_cert_pem);
619 pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_key_pem);
620 pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &host_cert_pem);
912 621
913 if (root_key_pem.data) 622 if (root_key_pem.data)
914 free(root_key_pem.data); 623 free(root_key_pem.data);
@@ -923,6 +632,284 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
923} 632}
924 633
925/** 634/**
635 * Generates the device certificate from the public key as well as the host
636 * and root certificates.
637 *
638 * @param pair_record The pair record to use for lookup of key pairs
639 * @param public_key The public key of the device to use for generation.
640 *
641 * @return USERPREF_E_SUCCESS on success, USERPREF_E_INVALID_ARG when a
642 * parameter is NULL, USERPREF_E_INVALID_CONF if the internal configuration
643 * system failed, USERPREF_E_SSL_ERROR if the certificates could not be
644 * generated
645 */
646userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record, key_data_t public_key)
647{
648 if (!pair_record || !public_key.data)
649 return USERPREF_E_INVALID_ARG;
650
651 userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR;
652
653#ifdef HAVE_OPENSSL
654 BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size);
655 RSA *pubkey = NULL;
656 if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) {
657 debug_info("Could not read public key");
658 }
659 BIO_free(membio);
660
661 /* now generate certificates */
662 key_data_t root_privkey, host_privkey;
663 key_data_t root_cert, host_cert;
664
665 X509* dev_cert = X509_new();
666
667 root_cert.data = NULL;
668 root_cert.size = 0;
669 host_cert.data = NULL;
670 host_cert.size = 0;
671
672 root_privkey.data = NULL;
673 root_privkey.size = 0;
674 host_privkey.data = NULL;
675 host_privkey.size = 0;
676
677 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert);
678 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &host_cert);
679 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey);
680 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_privkey);
681
682 if (USERPREF_E_SUCCESS == uret) {
683 /* generate device certificate */
684 ASN1_INTEGER* sn = ASN1_INTEGER_new();
685 ASN1_INTEGER_set(sn, 0);
686 X509_set_serialNumber(dev_cert, sn);
687 ASN1_INTEGER_free(sn);
688 X509_set_version(dev_cert, 2);
689
690 X509_add_ext_helper(dev_cert, NID_basic_constraints, (char*)"critical,CA:FALSE");
691
692 ASN1_TIME* asn1time = ASN1_TIME_new();
693 ASN1_TIME_set(asn1time, time(NULL));
694 X509_set_notBefore(dev_cert, asn1time);
695 ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
696 X509_set_notAfter(dev_cert, asn1time);
697 ASN1_TIME_free(asn1time);
698
699 /* read root certificate */
700 BIO* membp;
701 X509* rootCert = NULL;
702 membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
703 PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
704 BIO_free(membp);
705 if (!rootCert) {
706 debug_info("Could not read RootCertificate");
707 } else {
708 debug_info("RootCertificate loaded");
709 EVP_PKEY* pkey = EVP_PKEY_new();
710 EVP_PKEY_assign_RSA(pkey, pubkey);
711 X509_set_pubkey(dev_cert, pkey);
712 EVP_PKEY_free(pkey);
713 X509_free(rootCert);
714 }
715
716 X509_add_ext_helper(dev_cert, NID_subject_key_identifier, (char*)"hash");
717 X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");
718
719 /* read root private key */
720 EVP_PKEY* rootPriv = NULL;
721 membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
722 PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL);
723 BIO_free(membp);
724 if (!rootPriv) {
725 debug_info("Could not read RootPrivateKey");
726 } else {
727 debug_info("RootPrivateKey loaded");
728 if (X509_sign(dev_cert, rootPriv, EVP_sha1())) {
729 uret = USERPREF_E_SUCCESS;
730 } else {
731 debug_info("signing failed");
732 }
733 EVP_PKEY_free(rootPriv);
734 }
735
736 if (USERPREF_E_SUCCESS == uret) {
737 /* if everything went well, export in PEM format */
738 key_data_t pem_root_cert = { NULL, 0 };
739 key_data_t pem_host_cert = { NULL, 0 };
740
741 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &pem_root_cert);
742 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &pem_host_cert);
743
744 if (USERPREF_E_SUCCESS == uret) {
745 /* set new keys and certs in pair record */
746 membp = BIO_new(BIO_s_mem());
747 if (membp && PEM_write_bio_X509(membp, dev_cert) > 0) {
748 void *datap;
749 int size = BIO_get_mem_data(membp, &datap);
750 plist_dict_set_item(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data(datap, size));
751 }
752 if (membp)
753 BIO_free(membp);
754
755 plist_dict_set_item(pair_record, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data((char*)pem_host_cert.data, pem_host_cert.size));
756 plist_dict_set_item(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data((char*)pem_root_cert.data, pem_root_cert.size));
757 plist_dict_set_item(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data((char*)root_privkey.data, root_privkey.size));
758 plist_dict_set_item(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data((char*)host_privkey.data, host_privkey.size));
759
760 free(pem_root_cert.data);
761 free(pem_host_cert.data);
762 }
763 }
764 }
765 X509V3_EXT_cleanup();
766 X509_free(dev_cert);
767
768 if (root_cert.data)
769 free(root_cert.data);
770 if (host_cert.data)
771 free(host_cert.data);
772 if (root_privkey.data)
773 free(root_privkey.data);
774 if (host_privkey.data)
775 free(host_privkey.data);
776#else
777 gnutls_datum_t modulus = { NULL, 0 };
778 gnutls_datum_t exponent = { NULL, 0 };
779
780 /* now decode the PEM encoded key */
781 gnutls_datum_t der_pub_key;
782 if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) {
783
784 /* initalize asn.1 parser */
785 ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY;
786 if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) {
787
788 ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY;
789 asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key);
790
791 if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) {
792
793 /* get size to read */
794 int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, (int*)&modulus.size);
795 int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, (int*)&exponent.size);
796
797 modulus.data = gnutls_malloc(modulus.size);
798 exponent.data = gnutls_malloc(exponent.size);
799
800 ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size);
801 ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size);
802 if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2)
803 uret = USERPREF_E_SUCCESS;
804 }
805 if (asn1_pub_key)
806 asn1_delete_structure(&asn1_pub_key);
807 }
808 if (pkcs1)
809 asn1_delete_structure(&pkcs1);
810 }
811
812 /* now generate certificates */
813 if (USERPREF_E_SUCCESS == uret && 0 != modulus.size && 0 != exponent.size) {
814
815 gnutls_global_init();
816 gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") };
817
818 gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey;
819 gnutls_x509_crt_t dev_cert, root_cert, host_cert;
820
821 gnutls_x509_privkey_init(&fake_privkey);
822 gnutls_x509_privkey_init(&root_privkey);
823 gnutls_x509_privkey_init(&host_privkey);
824
825 gnutls_x509_crt_init(&dev_cert);
826 gnutls_x509_crt_init(&root_cert);
827 gnutls_x509_crt_init(&host_cert);
828
829 if (GNUTLS_E_SUCCESS ==
830 gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null,
831 &essentially_null, &essentially_null)) {
832
833 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, root_cert);
834 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, host_cert);
835 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
836 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
837
838 if (USERPREF_E_SUCCESS == uret) {
839 /* generate device certificate */
840 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
841 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
842 gnutls_x509_crt_set_version(dev_cert, 3);
843 gnutls_x509_crt_set_ca_status(dev_cert, 0);
844 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
845 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
846
847 /* use custom hash generation for compatibility with the "Apple ecosystem" */
848 const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1;
849 size_t hash_size = gnutls_hash_get_len(dig_sha1);
850 unsigned char hash[hash_size];
851 if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) {
852 debug_info("ERROR: Failed to generate SHA1 for public key");
853 } else {
854 gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size);
855 }
856
857 gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT);
858 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
859
860 if (LOCKDOWN_E_SUCCESS == ret) {
861 /* if everything went well, export in PEM format */
862 size_t export_size = 0;
863 gnutls_datum_t dev_pem = { NULL, 0 };
864 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size);
865 dev_pem.data = gnutls_malloc(export_size);
866 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size);
867 dev_pem.size = export_size;
868
869 gnutls_datum_t pem_root_cert = { NULL, 0 };
870 gnutls_datum_t pem_host_cert = { NULL, 0 };
871
872 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &pem_root_cert);
873 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &pem_host_cert);
874
875 if (USERPREF_E_SUCCESS == uret) {
876 /* set new keys and certs in pair record */
877 plist_dict_set_item(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data(dev_pem.data, dev_pem.size));
878 plist_dict_set_item(pair_record, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data(pem_host_cert.data, pem_host_cert.size));
879 plist_dict_set_item(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data(pem_root_cert.data, pem_root_cert.size));
880 plist_dict_set_item(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data(root_privkey.data, root_privkey.size));
881 plist_dict_set_item(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data(host_privkey.data, host_privkey.size));
882
883 gnutls_free(pem_root_cert.data);
884 gnutls_free(pem_host_cert.data);
885
886 if (dev_pem.data)
887 gnutls_free(dev_pem.data);
888 }
889 }
890 }
891 }
892
893 if (essentially_null.data)
894 free(essentially_null.data);
895
896 gnutls_x509_crt_deinit(dev_cert);
897 gnutls_x509_crt_deinit(root_cert);
898 gnutls_x509_crt_deinit(host_cert);
899 gnutls_x509_privkey_deinit(fake_privkey);
900 gnutls_x509_privkey_deinit(root_privkey);
901 gnutls_x509_privkey_deinit(host_privkey);
902 }
903
904 gnutls_free(modulus.data);
905 gnutls_free(exponent.data);
906
907 gnutls_free(der_pub_key.data);
908#endif
909 return uret;
910}
911
912/**
926 * Private function which import the given key into a gnutls structure. 913 * Private function which import the given key into a gnutls structure.
927 * 914 *
928 * @param name The name of the private key to import. 915 * @param name The name of the private key to import.
@@ -931,9 +918,9 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
931 * @return 1 if the key was successfully imported. 918 * @return 1 if the key was successfully imported.
932 */ 919 */
933#ifdef HAVE_OPENSSL 920#ifdef HAVE_OPENSSL
934static userpref_error_t userpref_device_record_import_key(const char* udid, const char* name, key_data_t* key) 921userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key)
935#else 922#else
936static userpref_error_t userpref_device_record_import_key(const char* udid, const char* name, gnutls_x509_privkey_t key) 923userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key)
937#endif 924#endif
938{ 925{
939#ifdef HAVE_OPENSSL 926#ifdef HAVE_OPENSSL
@@ -941,33 +928,20 @@ static userpref_error_t userpref_device_record_import_key(const char* udid, cons
941 return USERPREF_E_SUCCESS; 928 return USERPREF_E_SUCCESS;
942#endif 929#endif
943 userpref_error_t ret = USERPREF_E_INVALID_CONF; 930 userpref_error_t ret = USERPREF_E_INVALID_CONF;
944 char* buffer = NULL;
945 uint64_t length = 0;
946 931
947 plist_t crt = NULL;
948 if (userpref_device_record_get_value(udid, name, &crt)) {
949 if (crt && plist_get_node_type(crt) == PLIST_DATA) {
950 plist_get_data_val(crt, &buffer, &length);
951#ifdef HAVE_OPENSSL 932#ifdef HAVE_OPENSSL
952 key->data = (unsigned char*)malloc(length); 933 ret = pair_record_get_item_as_key_data(pair_record, name, key);
953 memcpy(key->data, buffer, length);
954 key->size = length;
955 ret = USERPREF_E_SUCCESS;
956#else 934#else
957 key_data_t pem = { (unsigned char*)buffer, length }; 935 key_data_t pem = { NULL, 0 };
958 if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) 936 ret = pair_record_get_item_as_key_data(pair_record, name, pem);
959 ret = USERPREF_E_SUCCESS; 937 if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(cert, &pem, GNUTLS_X509_FMT_PEM))
960 else 938 ret = USERPREF_E_SUCCESS;
961 ret = USERPREF_E_SSL_ERROR; 939 else
962#endif 940 ret = USERPREF_E_SSL_ERROR;
963 }
964 }
965
966 if (crt)
967 plist_free(crt);
968 941
969 if (buffer) 942 if (pem.data)
970 free(buffer); 943 free(pem.data);
944#endif
971 945
972 return ret; 946 return ret;
973} 947}
@@ -981,9 +955,9 @@ static userpref_error_t userpref_device_record_import_key(const char* udid, cons
981 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported. 955 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
982 */ 956 */
983#ifdef HAVE_OPENSSL 957#ifdef HAVE_OPENSSL
984static userpref_error_t userpref_device_record_import_crt(const char* udid, const char* name, key_data_t* cert) 958userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert)
985#else 959#else
986static userpref_error_t userpref_device_record_import_crt(const char* udid, const char* name, gnutls_x509_crt_t cert) 960userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert)
987#endif 961#endif
988{ 962{
989#ifdef HAVE_OPENSSL 963#ifdef HAVE_OPENSSL
@@ -991,206 +965,83 @@ static userpref_error_t userpref_device_record_import_crt(const char* udid, cons
991 return USERPREF_E_SUCCESS; 965 return USERPREF_E_SUCCESS;
992#endif 966#endif
993 userpref_error_t ret = USERPREF_E_INVALID_CONF; 967 userpref_error_t ret = USERPREF_E_INVALID_CONF;
994 char* buffer = NULL;
995 uint64_t length = 0;
996 968
997 plist_t crt = NULL;
998 if (userpref_device_record_get_value(udid, name, &crt)) {
999 if (crt && plist_get_node_type(crt) == PLIST_DATA) {
1000 plist_get_data_val(crt, &buffer, &length);
1001#ifdef HAVE_OPENSSL 969#ifdef HAVE_OPENSSL
1002 cert->data = (unsigned char*)malloc(length); 970 ret = pair_record_get_item_as_key_data(pair_record, name, cert);
1003 memcpy(cert->data, buffer, length);
1004 cert->size = length;
1005 ret = USERPREF_E_SUCCESS;
1006#else 971#else
1007 key_data_t pem = { (unsigned char*)buffer, length }; 972 key_data_t pem = { NULL, 0 };
1008 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) 973 ret = pair_record_get_item_as_key_data(pair_record, name, pem);
1009 ret = USERPREF_E_SUCCESS; 974 if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
1010 else 975 ret = USERPREF_E_SUCCESS;
1011 ret = USERPREF_E_SSL_ERROR; 976 else
1012#endif 977 ret = USERPREF_E_SSL_ERROR;
1013 }
1014 }
1015
1016 if (crt)
1017 plist_free(crt);
1018 978
1019 if (buffer) 979 if (pem.data)
1020 free(buffer); 980 free(pem.data);
981#endif
1021 982
1022 return ret; 983 return ret;
1023} 984}
1024 985
1025/** 986userpref_error_t pair_record_get_host_id(plist_t pair_record, char** host_id)
1026 * Function to retrieve host keys and certificates.
1027 * This function trigger key generation if they do not exists yet or are invalid.
1028 *
1029 * @note This function can take few seconds to complete (typically 5 seconds)
1030 *
1031 * @param root_privkey The root private key.
1032 * @param root_crt The root certificate.
1033 * @param host_privkey The host private key.
1034 * @param host_crt The host certificate.
1035 *
1036 * @return 1 if the keys and certificates were successfully retrieved, 0 otherwise
1037 */
1038#ifdef HAVE_OPENSSL
1039userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt)
1040#else
1041userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt)
1042#endif
1043{ 987{
1044 userpref_error_t ret = USERPREF_E_SUCCESS; 988 plist_t node = plist_dict_get_item(pair_record, USERPREF_HOST_ID_KEY);
1045
1046 if (ret == USERPREF_E_SUCCESS)
1047 ret = userpref_device_record_import_key(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
1048
1049 if (ret == USERPREF_E_SUCCESS)
1050 ret = userpref_device_record_import_key(udid, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
1051
1052 if (ret == USERPREF_E_SUCCESS)
1053 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, root_crt);
1054 989
1055 if (ret == USERPREF_E_SUCCESS) 990 if (node && plist_get_node_type(node) == PLIST_STRING) {
1056 ret = userpref_device_record_import_crt(udid, USERPREF_HOST_CERTIFICATE_KEY, host_crt); 991 plist_get_string_val(node, host_id);
1057 992 }
1058 if (USERPREF_E_SUCCESS != ret) {
1059 /* we had problem reading or importing root cert, try with new ones */
1060 ret = userpref_device_record_gen_keys_and_cert(udid);
1061
1062 if (ret == USERPREF_E_SUCCESS)
1063 ret = userpref_device_record_import_key(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
1064
1065 if (ret == USERPREF_E_SUCCESS)
1066 ret = userpref_device_record_import_key(udid, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
1067 993
1068 if (ret == USERPREF_E_SUCCESS) 994 return USERPREF_E_SUCCESS;
1069 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, root_crt); 995}
1070 996
1071 if (ret == USERPREF_E_SUCCESS) 997userpref_error_t pair_record_set_host_id(plist_t pair_record, const char* host_id)
1072 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, host_crt); 998{
1073 } 999 plist_dict_set_item(pair_record, USERPREF_HOST_ID_KEY, plist_new_string(host_id));
1074 1000
1075 return ret; 1001 return USERPREF_E_SUCCESS;
1076} 1002}
1077 1003
1078/** 1004userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const char* name, key_data_t *value)
1079 * Function to retrieve certificates encoded in PEM format.
1080 *
1081 * @param pem_root_cert The root certificate.
1082 * @param pem_host_cert The host certificate.
1083 * @param pem_device_cert The device certificate (optional).
1084 *
1085 * @return 1 if the certificates were successfully retrieved, 0 otherwise
1086 */
1087userpref_error_t userpref_device_record_get_certs_as_pem(const char *udid, key_data_t *pem_root_cert, key_data_t *pem_host_cert, key_data_t *pem_device_cert)
1088{ 1005{
1089 if (!udid || !pem_root_cert || !pem_host_cert) 1006 if (!pair_record || !value)
1090 return USERPREF_E_INVALID_ARG; 1007 return USERPREF_E_INVALID_ARG;
1091 1008
1092 char* buffer = NULL; 1009 char* buffer = NULL;
1093 uint64_t length = 0; 1010 uint64_t length = 0;
1094 1011
1095 plist_t root_cert = NULL; 1012 plist_t node = plist_dict_get_item(pair_record, name);
1096 plist_t host_cert = NULL;
1097 plist_t dev_cert = NULL;
1098
1099 if (userpref_device_record_get_value(udid, USERPREF_HOST_CERTIFICATE_KEY, &host_cert) &&
1100 userpref_device_record_get_value(udid, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert)) {
1101 if (host_cert && plist_get_node_type(host_cert) == PLIST_DATA) {
1102 plist_get_data_val(host_cert, &buffer, &length);
1103 pem_host_cert->data = (unsigned char*)malloc(length);
1104 memcpy(pem_host_cert->data, buffer, length);
1105 pem_host_cert->size = length;
1106 free(buffer);
1107 buffer = NULL;
1108 }
1109 if (root_cert && plist_get_node_type(root_cert) == PLIST_DATA) {
1110 plist_get_data_val(root_cert, &buffer, &length);
1111 pem_root_cert->data = (unsigned char*)malloc(length);
1112 memcpy(pem_root_cert->data, buffer, length);
1113 pem_root_cert->size = length;
1114 free(buffer);
1115 buffer = NULL;
1116 }
1117
1118 if (pem_device_cert) {
1119 userpref_device_record_get_value(udid, USERPREF_DEVICE_CERTIFICATE_KEY, &dev_cert);
1120 if (dev_cert && plist_get_node_type(dev_cert) == PLIST_DATA) {
1121 plist_get_data_val(dev_cert, &buffer, &length);
1122 pem_device_cert->data = (unsigned char*)malloc(length);
1123 memcpy(pem_device_cert->data, buffer, length);
1124 pem_device_cert->size = length;
1125 free(buffer);
1126 buffer = NULL;
1127 }
1128 }
1129
1130 if (root_cert)
1131 plist_free(root_cert);
1132 if (host_cert)
1133 plist_free(host_cert);
1134 if (dev_cert)
1135 plist_free(dev_cert);
1136 1013
1137 return USERPREF_E_SUCCESS; 1014 if (node && plist_get_node_type(node) == PLIST_DATA) {
1138 } else { 1015 plist_get_data_val(node, &buffer, &length);
1139 if (pem_root_cert->data) { 1016 value->data = (unsigned char*)malloc(length);
1140 free(pem_root_cert->data); 1017 memcpy(value->data, buffer, length);
1141 pem_root_cert->size = 0; 1018 value->size = length;
1142 } 1019 free(buffer);
1143 if (pem_host_cert->data) { 1020 buffer = NULL;
1144 free(pem_host_cert->data);
1145 pem_host_cert->size = 0;
1146 }
1147 } 1021 }
1148 1022
1149 if (root_cert) 1023 if (node)
1150 plist_free(root_cert); 1024 plist_free(node);
1151 if (host_cert)
1152 plist_free(host_cert);
1153 if (dev_cert)
1154 plist_free(dev_cert);
1155 1025
1156 debug_info("configuration invalid"); 1026 return USERPREF_E_SUCCESS;
1157
1158 return USERPREF_E_INVALID_CONF;
1159} 1027}
1160 1028
1161/** 1029userpref_error_t pair_record_set_item_from_key_data(plist_t pair_record, const char* name, key_data_t *value)
1162 * Create and save a configuration file containing the given data.
1163 *
1164 * @note: All fields must specified and be non-null
1165 *
1166 * @param root_key The root key
1167 * @param root_cert The root certificate
1168 * @param host_key The host key
1169 * @param host_cert The host certificate
1170 *
1171 * @return 1 on success and 0 otherwise.
1172 */
1173userpref_error_t userpref_device_record_set_keys_and_certs(const char* udid, key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert)
1174{ 1030{
1175 userpref_error_t ret = USERPREF_E_SUCCESS; 1031 userpref_error_t ret = USERPREF_E_SUCCESS;
1176 1032
1177 debug_info("saving keys and certs for udid %s", udid); 1033 if (!pair_record || !value) {
1178
1179 if (!root_key || !host_key || !root_cert || !host_cert) {
1180 debug_info("missing key or cert (root_key=%p, host_key=%p, root=cert=%p, host_cert=%p", root_key, host_key, root_cert, host_cert);
1181 return USERPREF_E_INVALID_ARG; 1034 return USERPREF_E_INVALID_ARG;
1182 } 1035 }
1183 1036
1184 /* now write keys and certificates to disk */ 1037 /* remove any existing item */
1185 if (userpref_device_record_set_value(udid, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data((char*)host_key->data, host_key->size)) && 1038 if (plist_dict_get_item(pair_record, name)) {
1186 userpref_device_record_set_value(udid, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data((char*)host_cert->data, host_cert->size)) && 1039 plist_dict_remove_item(pair_record, name);
1187 userpref_device_record_set_value(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data((char*)root_key->data, root_key->size)) &&
1188 userpref_device_record_set_value(udid, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data((char*)root_cert->data, root_cert->size)))
1189 {
1190 ret = USERPREF_E_SUCCESS;
1191 } else {
1192 ret = 1;
1193 } 1040 }
1194 1041
1042 /* set new item */
1043 plist_dict_set_item(pair_record, name, plist_new_data((char*)value->data, value->size));
1044
1195 return ret; 1045 return ret;
1196} 1046}
1047
diff --git a/common/userpref.h b/common/userpref.h
index 07fed8d..a39417a 100644
--- a/common/userpref.h
+++ b/common/userpref.h
@@ -69,27 +69,29 @@ typedef gnutls_datum_t key_data_t;
69 69
70typedef int16_t userpref_error_t; 70typedef int16_t userpref_error_t;
71 71
72const char *userpref_get_config_dir();
73int userpref_read_system_buid(char **system_buid);
74userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_record);
75userpref_error_t userpref_save_pair_record(const char *udid, plist_t pair_record);
76userpref_error_t userpref_delete_pair_record(const char *udid);
77
78LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record);
79LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record, key_data_t public_key);
72#ifdef HAVE_OPENSSL 80#ifdef HAVE_OPENSSL
73LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt); 81LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key);
82LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert);
74#else 83#else
75LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt); 84LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key);
85LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert);
76#endif 86#endif
77LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_set_keys_and_certs(const char *udid, key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert);
78LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_certs_as_pem(const char *udid, key_data_t *pem_root_cert, key_data_t *pem_host_cert, key_data_t *pem_device_cert);
79 87
80LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_record(const char *udid, plist_t device_record); 88userpref_error_t pair_record_get_host_id(plist_t pair_record, char** host_id);
81userpref_error_t userpref_remove_device_record(const char *udid); 89userpref_error_t pair_record_set_host_id(plist_t pair_record, const char* host_id);
82LIBIMOBILEDEVICE_INTERNAL int userpref_has_device_record(const char *udid); 90userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const char* name, key_data_t *value);
91userpref_error_t pair_record_set_item_from_key_data(plist_t pair_record, const char* name, key_data_t *value);
83 92
93/* deprecated */
84userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count); 94userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count);
85void userpref_device_record_get_host_id(const char *udid, char **host_id); 95LIBIMOBILEDEVICE_INTERNAL int userpref_has_pair_record(const char *udid);
86void userpref_get_system_buid(char **system_buid);
87const char *userpref_get_config_dir();
88
89userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_record);
90int userpref_get_value(const char *key, plist_t *value);
91int userpref_set_value(const char *key, plist_t value);
92int userpref_device_record_get_value(const char *udid, const char *key, plist_t *value);
93int userpref_device_record_set_value(const char *udid, const char *key, plist_t value);
94 96
95#endif 97#endif
diff --git a/common/utils.c b/common/utils.c
index 1b207ea..68b23b9 100644
--- a/common/utils.c
+++ b/common/utils.c
@@ -26,6 +26,7 @@
26#include <stdarg.h> 26#include <stdarg.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#include <string.h> 28#include <string.h>
29#include <time.h>
29 30
30#include "utils.h" 31#include "utils.h"
31 32
@@ -107,6 +108,35 @@ char *string_concat(const char *str, ...)
107 return result; 108 return result;
108} 109}
109 110
111static int get_rand(int min, int max)
112{
113 int retval = (rand() % (max - min)) + min;
114 return retval;
115}
116
117char *generate_uuid()
118{
119 const char *chars = "ABCDEF0123456789";
120 int i = 0;
121 char *uuid = (char *) malloc(sizeof(char) * 37);
122
123 srand(time(NULL));
124
125 for (i = 0; i < 36; i++) {
126 if (i == 8 || i == 13 || i == 18 || i == 23) {
127 uuid[i] = '-';
128 continue;
129 } else {
130 uuid[i] = chars[get_rand(0, 16)];
131 }
132 }
133
134 /* make it a real string */
135 uuid[36] = '\0';
136
137 return uuid;
138}
139
110void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) 140void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
111{ 141{
112 FILE *f; 142 FILE *f;
diff --git a/common/utils.h b/common/utils.h
index 0e78b3c..c1b6c32 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -37,6 +37,7 @@
37char *stpcpy(char * s1, const char * s2); 37char *stpcpy(char * s1, const char * s2);
38#endif 38#endif
39char *string_concat(const char *str, ...); 39char *string_concat(const char *str, ...);
40char *generate_uuid();
40 41
41void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length); 42void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
42void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length); 43void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);