summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/userpref.c989
-rw-r--r--common/userpref.h34
-rw-r--r--common/utils.c30
-rw-r--r--common/utils.h1
-rw-r--r--src/idevice.c31
-rw-r--r--src/lockdown.c530
-rw-r--r--src/lockdown.h5
-rw-r--r--tools/idevicepair.c12
8 files changed, 608 insertions, 1024 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);
diff --git a/src/idevice.c b/src/idevice.c
index d01aa8f..c656517 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -511,7 +511,7 @@ static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer,
511 511
512 debug_info("pre-read client wants %zi bytes", length); 512 debug_info("pre-read client wants %zi bytes", length);
513 513
514 recv_buffer = (char *) malloc(sizeof(char) * this_len); 514 recv_buffer = (char *)malloc(sizeof(char) * this_len);
515 515
516 /* repeat until we have the full data or an error occurs */ 516 /* repeat until we have the full data or an error occurs */
517 do { 517 do {
@@ -637,12 +637,12 @@ static const char *errorstring(int e)
637/** 637/**
638 * Internally used gnutls callback function that gets called during handshake. 638 * Internally used gnutls callback function that gets called during handshake.
639 */ 639 */
640static int internal_cert_callback (gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st) 640static int internal_cert_callback(gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st)
641{ 641{
642 int res = -1; 642 int res = -1;
643 gnutls_certificate_type_t type = gnutls_certificate_type_get (session); 643 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
644 if (type == GNUTLS_CRT_X509) { 644 if (type == GNUTLS_CRT_X509) {
645 ssl_data_t ssl_data = (ssl_data_t)gnutls_session_get_ptr (session); 645 ssl_data_t ssl_data = (ssl_data_t)gnutls_session_get_ptr(session);
646 if (ssl_data && ssl_data->host_privkey && ssl_data->host_cert) { 646 if (ssl_data && ssl_data->host_privkey && ssl_data->host_cert) {
647 debug_info("Passing certificate"); 647 debug_info("Passing certificate");
648 st->type = type; 648 st->type = type;
@@ -673,15 +673,20 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
673 673
674 idevice_error_t ret = IDEVICE_E_SSL_ERROR; 674 idevice_error_t ret = IDEVICE_E_SSL_ERROR;
675 uint32_t return_me = 0; 675 uint32_t return_me = 0;
676 plist_t pair_record = NULL;
677
678 userpref_read_pair_record(connection->udid, &pair_record);
679 if (!pair_record) {
680 debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s.", connection->udid);
681 return ret;
682 }
676 683
677#ifdef HAVE_OPENSSL 684#ifdef HAVE_OPENSSL
678 key_data_t root_cert = { NULL, 0 }; 685 key_data_t root_cert = { NULL, 0 };
679 key_data_t root_privkey = { NULL, 0 }; 686 key_data_t root_privkey = { NULL, 0 };
680 687
681 userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, &root_privkey, &root_cert, NULL, NULL); 688 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert);
682 if (uerr != USERPREF_E_SUCCESS) { 689 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey);
683 debug_info("Error %d when loading keys and certificates! %d", uerr);
684 }
685 690
686 /* Set up OpenSSL */ 691 /* Set up OpenSSL */
687 if (openssl_init_done == 0) { 692 if (openssl_init_done == 0) {
@@ -756,7 +761,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
756 errno = 0; 761 errno = 0;
757 gnutls_global_init(); 762 gnutls_global_init();
758 gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate); 763 gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate);
759 gnutls_certificate_client_set_retrieve_function (ssl_data_loc->certificate, internal_cert_callback); 764 gnutls_certificate_client_set_retrieve_function(ssl_data_loc->certificate, internal_cert_callback);
760 gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT); 765 gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT);
761 gnutls_priority_set_direct(ssl_data_loc->session, "NONE:+VERS-SSL3.0:+ANON-DH:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA1:+MD5:+COMP-NULL", NULL); 766 gnutls_priority_set_direct(ssl_data_loc->session, "NONE:+VERS-SSL3.0:+ANON-DH:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA1:+MD5:+COMP-NULL", NULL);
762 gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); 767 gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate);
@@ -767,10 +772,10 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
767 gnutls_x509_privkey_init(&ssl_data_loc->root_privkey); 772 gnutls_x509_privkey_init(&ssl_data_loc->root_privkey);
768 gnutls_x509_privkey_init(&ssl_data_loc->host_privkey); 773 gnutls_x509_privkey_init(&ssl_data_loc->host_privkey);
769 774
770 userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, ssl_data_loc->root_privkey, ssl_data_loc->root_cert, ssl_data_loc->host_privkey, ssl_data_loc->host_cert); 775 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, ssl_data_loc->root_cert);
771 if (uerr != USERPREF_E_SUCCESS) { 776 pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, ssl_data_loc->host_cert);
772 debug_info("Error %d when loading keys and certificates! %d", uerr); 777 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, ssl_data_loc->root_privkey);
773 } 778 pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, ssl_data_loc->host_privkey);
774 779
775 debug_info("GnuTLS step 1..."); 780 debug_info("GnuTLS step 1...");
776 gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection); 781 gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection);
diff --git a/src/lockdown.c b/src/lockdown.c
index e21db30..6ea747f 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -47,6 +47,7 @@
47#include "idevice.h" 47#include "idevice.h"
48#include "common/debug.h" 48#include "common/debug.h"
49#include "common/userpref.h" 49#include "common/userpref.h"
50#include "common/utils.h"
50#include "asprintf.h" 51#include "asprintf.h"
51 52
52#ifdef WIN32 53#ifdef WIN32
@@ -57,17 +58,6 @@
57#define RESULT_SUCCESS 0 58#define RESULT_SUCCESS 0
58#define RESULT_FAILURE 1 59#define RESULT_FAILURE 1
59 60
60#ifndef HAVE_OPENSSL
61const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
62 {"PKCS1", 536872976, 0},
63 {0, 1073741836, 0},
64 {"RSAPublicKey", 536870917, 0},
65 {"modulus", 1073741827, 0},
66 {"publicExponent", 3, 0},
67 {0, 0, 0}
68};
69#endif
70
71/** 61/**
72 * Internally used function for checking the result from lockdown's answer 62 * Internally used function for checking the result from lockdown's answer
73 * plist to a previously sent request. 63 * plist to a previously sent request.
@@ -618,7 +608,7 @@ lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **ud
618 * 608 *
619 * @return LOCKDOWN_E_SUCCESS on success 609 * @return LOCKDOWN_E_SUCCESS on success
620 */ 610 */
621lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key) 611static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_client_t client, key_data_t *public_key)
622{ 612{
623 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 613 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
624 plist_t value = NULL; 614 plist_t value = NULL;
@@ -758,16 +748,27 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
758 if (type) 748 if (type)
759 free(type); 749 free(type);
760 750
761 userpref_device_record_get_host_id(client_loc->udid, &host_id); 751 debug_info("reading pair record");
752
753 plist_t pair_record = NULL;
754 userpref_read_pair_record(client_loc->udid, &pair_record);
755
756 debug_info("reading HostID");
757
758 pair_record_get_host_id(pair_record, &host_id);
762 if (LOCKDOWN_E_SUCCESS == ret && !host_id) { 759 if (LOCKDOWN_E_SUCCESS == ret && !host_id) {
763 ret = LOCKDOWN_E_INVALID_CONF; 760 ret = LOCKDOWN_E_INVALID_CONF;
764 } 761 }
765 762
766 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_record(client_loc->udid)) { 763 debug_info("HostID: %s", host_id);
764
765 if (LOCKDOWN_E_SUCCESS == ret && !pair_record) {
767 /* attempt pairing */ 766 /* attempt pairing */
768 ret = lockdownd_pair(client_loc, NULL); 767 ret = lockdownd_pair(client_loc, NULL);
769 } 768 }
770 769
770 plist_free(pair_record);
771
771 /* in any case, we need to validate pairing to receive trusted host status */ 772 /* in any case, we need to validate pairing to receive trusted host status */
772 ret = lockdownd_validate_pair(client_loc, NULL); 773 ret = lockdownd_validate_pair(client_loc, NULL);
773 774
@@ -836,67 +837,69 @@ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_recor
836 * 837 *
837 * @return LOCKDOWN_E_SUCCESS on success 838 * @return LOCKDOWN_E_SUCCESS on success
838 */ 839 */
839static lockdownd_error_t generate_pair_record_plist(lockdownd_client_t client, plist_t *pair_record_plist) 840static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t *pair_record)
840{ 841{
841 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 842 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
842 843
844 key_data_t public_key = { NULL, 0 };
843 char* host_id = NULL; 845 char* host_id = NULL;
844 char* system_buid = NULL; 846 char* system_buid = NULL;
845 847
846 key_data_t public_key = { NULL, 0 };
847 key_data_t device_cert = { NULL, 0 };
848 key_data_t host_cert = { NULL, 0 };
849 key_data_t root_cert = { NULL, 0 };
850
851 /* load certificates if a pairing exists */
852 userpref_error_t uret = userpref_device_record_get_certs_as_pem(client->udid, &root_cert, &host_cert, &device_cert);
853 if ((uret == USERPREF_E_SUCCESS) && (root_cert.size > 0) && (host_cert.size > 0) && (device_cert.size > 0)) {
854 ret = LOCKDOWN_E_SUCCESS;
855 }
856
857 /* get systembuid and host id */
858 userpref_get_system_buid(&system_buid);
859 userpref_device_record_get_host_id(client->udid, &host_id);
860
861 /* generate new certificates if needed */ 848 /* generate new certificates if needed */
849 ret = lockdownd_get_device_public_key_as_key_data(client, &public_key);
862 if (ret != LOCKDOWN_E_SUCCESS) { 850 if (ret != LOCKDOWN_E_SUCCESS) {
863 ret = lockdownd_get_device_public_key(client, &public_key); 851 debug_info("device refused to send public key.");
864 if (ret != LOCKDOWN_E_SUCCESS) { 852 goto leave;
865 debug_info("device refused to send public key."); 853 }
866 goto leave; 854 debug_info("device public key follows:\n%.*s", public_key.size, public_key.data);
867 }
868 debug_info("device public key follows:\n%.*s", public_key.size, public_key.data);
869 855
870 userpref_device_record_set_value(client->udid, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid)); 856 host_id = generate_uuid();
871 857
872 ret = lockdownd_gen_pair_cert_for_udid(client->udid, public_key, &device_cert, &host_cert, &root_cert); 858 *pair_record = plist_new_dict();
859
860 userpref_error_t uret = USERPREF_E_SUCCESS;
861 uret = pair_record_generate_keys_and_certs(pair_record);
862 switch(uret) {
863 case USERPREF_E_INVALID_ARG:
864 ret = LOCKDOWN_E_INVALID_ARG;
865 break;
866 case USERPREF_E_INVALID_CONF:
867 ret = LOCKDOWN_E_INVALID_CONF;
868 break;
869 case USERPREF_E_SSL_ERROR:
870 ret = LOCKDOWN_E_SSL_ERROR;
871 default:
872 break;
873 }
874
875 uret = pair_record_generate_from_device_public_key(pair_record, public_key);
876 switch(uret) {
877 case USERPREF_E_INVALID_ARG:
878 ret = LOCKDOWN_E_INVALID_ARG;
879 break;
880 case USERPREF_E_INVALID_CONF:
881 ret = LOCKDOWN_E_INVALID_CONF;
882 break;
883 case USERPREF_E_SSL_ERROR:
884 ret = LOCKDOWN_E_SSL_ERROR;
885 default:
886 break;
873 } 887 }
874 888
889 /* get systembuid and host id */
890 userpref_read_system_buid(&system_buid);
891
892 pair_record_set_host_id(pair_record, host_id);
893
875 if (ret != LOCKDOWN_E_SUCCESS) { 894 if (ret != LOCKDOWN_E_SUCCESS) {
876 goto leave; 895 goto leave;
877 } 896 }
878 897
879 /* setup request plist */
880 *pair_record_plist = plist_new_dict();
881 plist_dict_set_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
882 plist_dict_set_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
883 plist_dict_set_item(*pair_record_plist, "HostID", plist_new_string(host_id));
884 plist_dict_set_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
885 plist_dict_set_item(*pair_record_plist, "SystemBUID", plist_new_string(system_buid));
886
887leave: 898leave:
888 if (host_id) 899 if (host_id)
889 free(host_id); 900 free(host_id);
890 if (system_buid) 901 if (system_buid)
891 free(system_buid); 902 free(system_buid);
892 if (public_key.data)
893 free(public_key.data);
894 if (device_cert.data)
895 free(device_cert.data);
896 if (host_cert.data)
897 free(host_cert.data);
898 if (root_cert.data)
899 free(root_cert.data);
900 903
901 return ret; 904 return ret;
902} 905}
@@ -923,7 +926,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
923 926
924 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 927 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
925 plist_t dict = NULL; 928 plist_t dict = NULL;
926 plist_t dict_record = NULL; 929 plist_t pair_record_plist = NULL;
927 int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */ 930 int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */
928 931
929 if (pair_record && pair_record->system_buid && pair_record->host_id) { 932 if (pair_record && pair_record->system_buid && pair_record->host_id) {
@@ -933,36 +936,39 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
933 } 936 }
934 937
935 /* use passed pair_record */ 938 /* use passed pair_record */
936 dict_record = lockdownd_pair_record_to_plist(pair_record); 939 pair_record_plist = lockdownd_pair_record_to_plist(pair_record);
937 940
938 pairing_mode = 1; 941 pairing_mode = 1;
939 } else { 942 } else {
940 ret = generate_pair_record_plist(client, &dict_record); 943 /* generate a new pair record if pairing */
941 944 if (!strcmp("Pair", verb)) {
942 if (ret != LOCKDOWN_E_SUCCESS) { 945 ret = pair_record_generate(client, &pair_record_plist);
943 if (dict_record) 946
944 plist_free(dict_record); 947 if (ret != LOCKDOWN_E_SUCCESS) {
945 return ret; 948 if (pair_record_plist)
949 plist_free(pair_record_plist);
950 return ret;
951 }
952 } else {
953 /* use existing pair record */
954 if (userpref_has_pair_record(client->udid)) {
955 userpref_read_pair_record(client->udid, &pair_record_plist);
956 } else {
957 return LOCKDOWN_E_PAIRING_FAILED;
958 }
946 } 959 }
947 } 960 }
948 961
949 if (!strcmp("Pair", verb)) { 962 plist_t request_pair_record = plist_copy(pair_record_plist);
950 /* get wifi mac */
951 plist_t wifi_mac_node = NULL;
952 lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_mac_node);
953 963
954 /* save wifi mac address in config */ 964 /* remove stuff that is private */
955 if (wifi_mac_node) { 965 plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY);
956 userpref_device_record_set_value(client->udid, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(wifi_mac_node)); 966 plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY);
957 plist_free(wifi_mac_node);
958 wifi_mac_node = NULL;
959 }
960 }
961 967
962 /* setup pair request plist */ 968 /* setup pair request plist */
963 dict = plist_new_dict(); 969 dict = plist_new_dict();
964 plist_dict_add_label(dict, client->label); 970 plist_dict_add_label(dict, client->label);
965 plist_dict_set_item(dict, "PairRecord", plist_copy(dict_record)); 971 plist_dict_set_item(dict, "PairRecord", request_pair_record);
966 plist_dict_set_item(dict, "Request", plist_new_string(verb)); 972 plist_dict_set_item(dict, "Request", plist_new_string(verb));
967 plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION)); 973 plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION));
968 974
@@ -976,7 +982,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
976 dict = NULL; 982 dict = NULL;
977 983
978 if (ret != LOCKDOWN_E_SUCCESS) { 984 if (ret != LOCKDOWN_E_SUCCESS) {
979 plist_free(dict_record); 985 plist_free(pair_record_plist);
980 return ret; 986 return ret;
981 } 987 }
982 988
@@ -984,7 +990,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
984 ret = lockdownd_receive(client, &dict); 990 ret = lockdownd_receive(client, &dict);
985 991
986 if (ret != LOCKDOWN_E_SUCCESS) { 992 if (ret != LOCKDOWN_E_SUCCESS) {
987 plist_free(dict_record); 993 plist_free(pair_record_plist);
988 return ret; 994 return ret;
989 } 995 }
990 996
@@ -1007,24 +1013,32 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
1007 debug_info("internal pairing mode"); 1013 debug_info("internal pairing mode");
1008 if (!strcmp("Unpair", verb)) { 1014 if (!strcmp("Unpair", verb)) {
1009 /* remove public key from config */ 1015 /* remove public key from config */
1010 userpref_remove_device_record(client->udid); 1016 userpref_delete_pair_record(client->udid);
1011 } else { 1017 } else {
1012 if (!strcmp("Pair", verb)) { 1018 if (!strcmp("Pair", verb)) {
1013 debug_info("getting EscrowBag from response"); 1019 debug_info("Saving EscrowBag from response in pair record");
1014 1020
1015 /* add returned escrow bag if available */ 1021 /* add returned escrow bag if available */
1016 plist_t escrow_bag = plist_dict_get_item(dict, "EscrowBag"); 1022 plist_t extra_node = plist_dict_get_item(dict, USERPREF_ESCROW_BAG_KEY);
1017 if (escrow_bag && plist_get_node_type(escrow_bag) == PLIST_DATA) { 1023 if (extra_node && plist_get_node_type(extra_node) == PLIST_DATA) {
1018 userpref_device_record_set_value(client->udid, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag)); 1024 plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(extra_node));
1019 plist_free(escrow_bag); 1025 plist_free(extra_node);
1020 escrow_bag = NULL; 1026 extra_node = NULL;
1021 } 1027 }
1022 1028
1023 /* store DeviceCertificate upon successful pairing */ 1029 debug_info("Saving WiFiAddress from device in pair record");
1024 plist_t devcrt = plist_dict_get_item(dict_record, USERPREF_DEVICE_CERTIFICATE_KEY); 1030
1025 if (devcrt && plist_get_node_type(devcrt) == PLIST_DATA) { 1031 /* get wifi mac */
1026 userpref_device_record_set_value(client->udid, USERPREF_DEVICE_CERTIFICATE_KEY, plist_copy(devcrt)); 1032 lockdownd_get_value(client, NULL, "WiFiAddress", &extra_node);
1033
1034 /* save wifi mac address in config */
1035 if (extra_node) {
1036 plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(extra_node));
1037 plist_free(extra_node);
1038 extra_node = NULL;
1027 } 1039 }
1040
1041 userpref_save_pair_record(client->udid, pair_record_plist);
1028 } 1042 }
1029 } 1043 }
1030 } else { 1044 } else {
@@ -1057,9 +1071,9 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
1057 } 1071 }
1058 } 1072 }
1059 1073
1060 if (dict_record) { 1074 if (pair_record_plist) {
1061 plist_free(dict_record); 1075 plist_free(pair_record_plist);
1062 dict_record = NULL; 1076 pair_record_plist = NULL;
1063 } 1077 }
1064 1078
1065 plist_free(dict); 1079 plist_free(dict);
@@ -1206,332 +1220,6 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
1206} 1220}
1207 1221
1208/** 1222/**
1209 * Generates the device certificate from the public key as well as the host
1210 * and root certificates.
1211 *
1212 * @param public_key The public key of the device to use for generation.
1213 * @param odevice_cert Holds the generated device certificate.
1214 * @param ohost_cert Holds the generated host certificate.
1215 * @param oroot_cert Holds the generated root certificate.
1216 *
1217 * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when a
1218 * parameter is NULL, LOCKDOWN_E_INVALID_CONF if the internal configuration
1219 * system failed, LOCKDOWN_E_SSL_ERROR if the certificates could not be
1220 * generated
1221 */
1222lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * odevice_cert,
1223 key_data_t * ohost_cert, key_data_t * oroot_cert)
1224{
1225 if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert)
1226 return LOCKDOWN_E_INVALID_ARG;
1227
1228 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1229 userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR;
1230
1231#ifdef HAVE_OPENSSL
1232 BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size);
1233 RSA *pubkey = NULL;
1234 if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) {
1235 debug_info("Could not read public key");
1236 }
1237 BIO_free(membio);
1238
1239 /* now generate certificates */
1240 key_data_t root_privkey, host_privkey;
1241 key_data_t root_cert, host_cert;
1242 X509* dev_cert;
1243
1244 root_cert.data = NULL;
1245 root_cert.size = 0;
1246 host_cert.data = NULL;
1247 host_cert.size = 0;
1248
1249 dev_cert = X509_new();
1250
1251 root_privkey.data = NULL;
1252 root_privkey.size = 0;
1253 host_privkey.data = NULL;
1254 host_privkey.size = 0;
1255
1256 uret = userpref_device_record_get_keys_and_certs(udid, &root_privkey, &root_cert, &host_privkey, &host_cert);
1257 if (USERPREF_E_SUCCESS == uret) {
1258 /* generate device certificate */
1259 ASN1_INTEGER* sn = ASN1_INTEGER_new();
1260 ASN1_INTEGER_set(sn, 0);
1261 X509_set_serialNumber(dev_cert, sn);
1262 ASN1_INTEGER_free(sn);
1263 X509_set_version(dev_cert, 2);
1264
1265 X509_EXTENSION* ext;
1266 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
1267 debug_info("ERROR: X509V3_EXT_conf_nid failed for Basic Constraints");
1268 }
1269 X509_add_ext(dev_cert, ext, -1);
1270 X509_EXTENSION_free(ext);
1271
1272 ASN1_TIME* asn1time = ASN1_TIME_new();
1273 ASN1_TIME_set(asn1time, time(NULL));
1274 X509_set_notBefore(dev_cert, asn1time);
1275 ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
1276 X509_set_notAfter(dev_cert, asn1time);
1277 ASN1_TIME_free(asn1time);
1278
1279 BIO* membp;
1280
1281 X509* rootCert = NULL;
1282 membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
1283 PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
1284 BIO_free(membp);
1285 if (!rootCert) {
1286 debug_info("Could not read RootCertificate");
1287 } else {
1288 debug_info("RootCertificate loaded");
1289 EVP_PKEY* pkey = EVP_PKEY_new();
1290 EVP_PKEY_assign_RSA(pkey, pubkey);
1291 X509_set_pubkey(dev_cert, pkey);
1292 EVP_PKEY_free(pkey);
1293 X509_free(rootCert);
1294 }
1295
1296 X509V3_CTX ctx;
1297 X509V3_set_ctx_nodb(&ctx);
1298 X509V3_set_ctx(&ctx, NULL, dev_cert, NULL, NULL, 0);
1299
1300 if (!(ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, (char*)"hash"))) {
1301 debug_info("ERROR: X509V3_EXT_conf_nid failed for Subject Key identifier");
1302 }
1303 X509_add_ext(dev_cert, ext, -1);
1304 X509_EXTENSION_free(ext);
1305
1306 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"))) {
1307 debug_info("ERROR: X509V3_EXT_conf_nid failed for Key Usage");
1308 }
1309 X509_add_ext(dev_cert, ext, -1);
1310 X509_EXTENSION_free(ext);
1311
1312 EVP_PKEY* rootPriv = NULL;
1313 membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
1314 PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL);
1315 BIO_free(membp);
1316 if (!rootPriv) {
1317 debug_info("Could not read RootPrivateKey");
1318 } else {
1319 debug_info("RootPrivateKey loaded");
1320 if (X509_sign(dev_cert, rootPriv, EVP_sha1())) {
1321 ret = LOCKDOWN_E_SUCCESS;
1322 } else {
1323 debug_info("signing failed");
1324 }
1325 EVP_PKEY_free(rootPriv);
1326 }
1327
1328 if (LOCKDOWN_E_SUCCESS == ret) {
1329 /* if everything went well, export in PEM format */
1330 key_data_t pem_root_cert = { NULL, 0 };
1331 key_data_t pem_host_cert = { NULL, 0 };
1332
1333 uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert, NULL);
1334 if (USERPREF_E_SUCCESS == uret) {
1335 /* copy buffer for output */
1336 membp = BIO_new(BIO_s_mem());
1337 if (membp && PEM_write_bio_X509(membp, dev_cert) > 0) {
1338 void *datap;
1339 odevice_cert->size = BIO_get_mem_data(membp, &datap);
1340 odevice_cert->data = malloc(odevice_cert->size);
1341 memcpy(odevice_cert->data, datap, odevice_cert->size);
1342 }
1343 if (membp)
1344 BIO_free(membp);
1345
1346 ohost_cert->data = malloc(pem_host_cert.size);
1347 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
1348 ohost_cert->size = pem_host_cert.size;
1349
1350 oroot_cert->data = malloc(pem_root_cert.size);
1351 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
1352 oroot_cert->size = pem_root_cert.size;
1353
1354 free(pem_root_cert.data);
1355 free(pem_host_cert.data);
1356 }
1357 }
1358 }
1359 X509V3_EXT_cleanup();
1360 X509_free(dev_cert);
1361
1362 switch(uret) {
1363 case USERPREF_E_INVALID_ARG:
1364 ret = LOCKDOWN_E_INVALID_ARG;
1365 break;
1366 case USERPREF_E_INVALID_CONF:
1367 ret = LOCKDOWN_E_INVALID_CONF;
1368 break;
1369 case USERPREF_E_SSL_ERROR:
1370 ret = LOCKDOWN_E_SSL_ERROR;
1371 default:
1372 break;
1373 }
1374
1375 if (root_cert.data)
1376 free(root_cert.data);
1377 if (host_cert.data)
1378 free(host_cert.data);
1379 if (root_privkey.data)
1380 free(root_privkey.data);
1381 if (host_privkey.data)
1382 free(host_privkey.data);
1383#else
1384 gnutls_datum_t modulus = { NULL, 0 };
1385 gnutls_datum_t exponent = { NULL, 0 };
1386
1387 /* now decode the PEM encoded key */
1388 gnutls_datum_t der_pub_key;
1389 if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) {
1390
1391 /* initalize asn.1 parser */
1392 ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY;
1393 if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) {
1394
1395 ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY;
1396 asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key);
1397
1398 if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) {
1399
1400 /* get size to read */
1401 int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, (int*)&modulus.size);
1402 int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, (int*)&exponent.size);
1403
1404 modulus.data = gnutls_malloc(modulus.size);
1405 exponent.data = gnutls_malloc(exponent.size);
1406
1407 ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size);
1408 ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size);
1409 if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2)
1410 ret = LOCKDOWN_E_SUCCESS;
1411 }
1412 if (asn1_pub_key)
1413 asn1_delete_structure(&asn1_pub_key);
1414 }
1415 if (pkcs1)
1416 asn1_delete_structure(&pkcs1);
1417 }
1418
1419 /* now generate certificates */
1420 if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) {
1421
1422 gnutls_global_init();
1423 gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") };
1424
1425 gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey;
1426 gnutls_x509_crt_t dev_cert, root_cert, host_cert;
1427
1428 gnutls_x509_privkey_init(&fake_privkey);
1429 gnutls_x509_privkey_init(&root_privkey);
1430 gnutls_x509_privkey_init(&host_privkey);
1431
1432 gnutls_x509_crt_init(&dev_cert);
1433 gnutls_x509_crt_init(&root_cert);
1434 gnutls_x509_crt_init(&host_cert);
1435
1436 if (GNUTLS_E_SUCCESS ==
1437 gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null,
1438 &essentially_null, &essentially_null)) {
1439
1440 uret = userpref_device_record_get_keys_and_certs(udid, root_privkey, root_cert, host_privkey, host_cert);
1441
1442 if (USERPREF_E_SUCCESS == uret) {
1443 /* generate device certificate */
1444 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
1445 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
1446 gnutls_x509_crt_set_version(dev_cert, 3);
1447 gnutls_x509_crt_set_ca_status(dev_cert, 0);
1448 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
1449 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
1450
1451 /* use custom hash generation for compatibility with the "Apple ecosystem" */
1452 const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1;
1453 size_t hash_size = gnutls_hash_get_len(dig_sha1);
1454 unsigned char hash[hash_size];
1455 if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) {
1456 debug_info("ERROR: Failed to generate SHA1 for public key");
1457 } else {
1458 gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size);
1459 }
1460
1461 gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT);
1462 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
1463
1464 if (LOCKDOWN_E_SUCCESS == ret) {
1465 /* if everything went well, export in PEM format */
1466 size_t export_size = 0;
1467 gnutls_datum_t dev_pem = { NULL, 0 };
1468 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size);
1469 dev_pem.data = gnutls_malloc(export_size);
1470 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size);
1471 dev_pem.size = export_size;
1472
1473 gnutls_datum_t pem_root_cert = { NULL, 0 };
1474 gnutls_datum_t pem_host_cert = { NULL, 0 };
1475
1476 uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert, NULL);
1477
1478 if (USERPREF_E_SUCCESS == uret) {
1479 /* copy buffer for output */
1480 odevice_cert->data = malloc(dev_pem.size);
1481 memcpy(odevice_cert->data, dev_pem.data, dev_pem.size);
1482 odevice_cert->size = dev_pem.size;
1483
1484 ohost_cert->data = malloc(pem_host_cert.size);
1485 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
1486 ohost_cert->size = pem_host_cert.size;
1487
1488 oroot_cert->data = malloc(pem_root_cert.size);
1489 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
1490 oroot_cert->size = pem_root_cert.size;
1491
1492 gnutls_free(pem_root_cert.data);
1493 gnutls_free(pem_host_cert.data);
1494
1495 if (dev_pem.data)
1496 gnutls_free(dev_pem.data);
1497 }
1498 }
1499 }
1500
1501 switch(uret) {
1502 case USERPREF_E_INVALID_ARG:
1503 ret = LOCKDOWN_E_INVALID_ARG;
1504 break;
1505 case USERPREF_E_INVALID_CONF:
1506 ret = LOCKDOWN_E_INVALID_CONF;
1507 break;
1508 case USERPREF_E_SSL_ERROR:
1509 ret = LOCKDOWN_E_SSL_ERROR;
1510 default:
1511 break;
1512 }
1513 }
1514
1515 if (essentially_null.data)
1516 free(essentially_null.data);
1517 gnutls_x509_crt_deinit(dev_cert);
1518 gnutls_x509_crt_deinit(root_cert);
1519 gnutls_x509_crt_deinit(host_cert);
1520 gnutls_x509_privkey_deinit(fake_privkey);
1521 gnutls_x509_privkey_deinit(root_privkey);
1522 gnutls_x509_privkey_deinit(host_privkey);
1523
1524 }
1525
1526 gnutls_free(modulus.data);
1527 gnutls_free(exponent.data);
1528
1529 gnutls_free(der_pub_key.data);
1530#endif
1531 return ret;
1532}
1533
1534/**
1535 * Opens a session with lockdownd and switches to SSL mode if device wants it. 1223 * Opens a session with lockdownd and switches to SSL mode if device wants it.
1536 * 1224 *
1537 * @param client The lockdownd client 1225 * @param client The lockdownd client
@@ -1569,7 +1257,7 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char
1569 1257
1570 /* add system buid */ 1258 /* add system buid */
1571 char *system_buid = NULL; 1259 char *system_buid = NULL;
1572 userpref_get_system_buid(&system_buid); 1260 userpref_read_system_buid(&system_buid);
1573 if (system_buid) { 1261 if (system_buid) {
1574 plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid)); 1262 plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid));
1575 if (system_buid) { 1263 if (system_buid) {
@@ -1671,8 +1359,14 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1671 (*service)->ssl_enabled = 0; 1359 (*service)->ssl_enabled = 0;
1672 } 1360 }
1673 1361
1362 plist_t pair_record = NULL;
1363 userpref_read_pair_record(client->udid, &pair_record);
1364
1674 char *host_id = NULL; 1365 char *host_id = NULL;
1675 userpref_device_record_get_host_id(client->udid, &host_id); 1366 pair_record_get_host_id(pair_record, &host_id);
1367
1368 plist_free(pair_record);
1369
1676 if (!host_id) 1370 if (!host_id)
1677 return LOCKDOWN_E_INVALID_CONF; 1371 return LOCKDOWN_E_INVALID_CONF;
1678 1372
diff --git a/src/lockdown.h b/src/lockdown.h
index 9c2be44..a09e89b 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -22,8 +22,6 @@
22#ifndef __LOCKDOWND_H 22#ifndef __LOCKDOWND_H
23#define __LOCKDOWND_H 23#define __LOCKDOWND_H
24 24
25#include "common/userpref.h"
26
27#include "libimobiledevice/lockdown.h" 25#include "libimobiledevice/lockdown.h"
28#include "property_list_service.h" 26#include "property_list_service.h"
29 27
@@ -37,7 +35,4 @@ struct lockdownd_client_private {
37 char *label; 35 char *label;
38}; 36};
39 37
40lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key);
41lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * device_cert, key_data_t * host_cert, key_data_t * root_cert);
42
43#endif 38#endif
diff --git a/tools/idevicepair.c b/tools/idevicepair.c
index 91ed49b..5af95f0 100644
--- a/tools/idevicepair.c
+++ b/tools/idevicepair.c
@@ -134,7 +134,7 @@ int main(int argc, char **argv)
134 134
135 if (op == OP_SYSTEMBUID) { 135 if (op == OP_SYSTEMBUID) {
136 char *systembuid = NULL; 136 char *systembuid = NULL;
137 userpref_get_system_buid(&systembuid); 137 userpref_read_system_buid(&systembuid);
138 138
139 printf("%s\n", systembuid); 139 printf("%s\n", systembuid);
140 140
@@ -184,14 +184,20 @@ int main(int argc, char **argv)
184 } 184 }
185 185
186 if (op == OP_HOSTID) { 186 if (op == OP_HOSTID) {
187 plist_t pair_record = NULL;
187 char *hostid = NULL; 188 char *hostid = NULL;
188 userpref_device_record_get_host_id(udid, &hostid); 189
190 userpref_read_pair_record(udid, &pair_record);
191 pair_record_get_host_id(pair_record, &hostid);
189 192
190 printf("%s\n", hostid); 193 printf("%s\n", hostid);
191 194
192 if (hostid) 195 if (hostid)
193 free(hostid); 196 free(hostid);
194 197
198 if (pair_record)
199 plist_free(pair_record);
200
195 return EXIT_SUCCESS; 201 return EXIT_SUCCESS;
196 } 202 }
197 203
@@ -254,7 +260,7 @@ int main(int argc, char **argv)
254 lerr = lockdownd_unpair(client, NULL); 260 lerr = lockdownd_unpair(client, NULL);
255 if (lerr == LOCKDOWN_E_SUCCESS) { 261 if (lerr == LOCKDOWN_E_SUCCESS) {
256 /* also remove local device record */ 262 /* also remove local device record */
257 userpref_remove_device_record(udid); 263 userpref_delete_pair_record(udid);
258 printf("SUCCESS: Unpaired with device %s\n", udid); 264 printf("SUCCESS: Unpaired with device %s\n", udid);
259 } else { 265 } else {
260 result = EXIT_FAILURE; 266 result = EXIT_FAILURE;