summaryrefslogtreecommitdiffstats
path: root/common/userpref.c
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2014-03-21 00:16:29 +0100
committerGravatar Martin Szulecki2014-03-21 00:16:29 +0100
commitd1ccd4eeebc94dac11140ae77b73392d0763d3a4 (patch)
treefb5fa6cab2bdaf55b28004921960d331db59bf7b /common/userpref.c
parent88ce6113593158944630435678e689bf155d9a03 (diff)
downloadlibimobiledevice-d1ccd4eeebc94dac11140ae77b73392d0763d3a4.tar.gz
libimobiledevice-d1ccd4eeebc94dac11140ae77b73392d0763d3a4.tar.bz2
Refactor pair record handling to use new usbmuxd pair record interface
This refactoring is mandatory as libimobiledevice should not interact with the pair record configuration directory which is owned by the usbmuxd user. This change also adds compatibility for the native usbmuxd and thus pair records saved by iTunes.
Diffstat (limited to 'common/userpref.c')
-rw-r--r--common/userpref.c989
1 files changed, 420 insertions, 569 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