summaryrefslogtreecommitdiffstats
path: root/src/lockdown.c
diff options
context:
space:
mode:
authorGravatar Jonathan Beck2008-08-03 20:47:47 +0200
committerGravatar Matt Colyer2008-08-05 23:28:10 -0700
commitb9f9675e1e3978693bb2e7f66a7125473b3cb30e (patch)
treeca582a51bce704bfb764e31b8ef65403b4e6fc86 /src/lockdown.c
parentb25fea997fc798e945dd7f19f8d0be0d8d3289d1 (diff)
downloadlibimobiledevice-b9f9675e1e3978693bb2e7f66a7125473b3cb30e.tar.gz
libimobiledevice-b9f9675e1e3978693bb2e7f66a7125473b3cb30e.tar.bz2
Initial pairing implementation.
Signed-off-by: Matt Colyer <matt@colyer.name>
Diffstat (limited to 'src/lockdown.c')
-rw-r--r--src/lockdown.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/lockdown.c b/src/lockdown.c
index 7d5c16d..5f73a49 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -25,9 +25,22 @@
25#include "userpref.h" 25#include "userpref.h"
26#include <errno.h> 26#include <errno.h>
27#include <string.h> 27#include <string.h>
28#include <glib.h>
29#include <libtasn1.h>
28 30
29extern int debug; 31extern int debug;
30 32
33const ASN1_ARRAY_TYPE pkcs1_asn1_tab[]={
34 {"PKCS1",536872976,0},
35 {0,1073741836,0},
36 {"RSAPublicKey",536870917,0},
37 {"modulus",1073741827,0},
38 {"publicExponent",3,0},
39 {0,0,0}
40};
41
42
43
31lockdownd_client *new_lockdownd_client(iPhone *phone) { 44lockdownd_client *new_lockdownd_client(iPhone *phone) {
32 if (!phone) return NULL; 45 if (!phone) return NULL;
33 lockdownd_client *control = (lockdownd_client*)malloc(sizeof(lockdownd_client)); 46 lockdownd_client *control = (lockdownd_client*)malloc(sizeof(lockdownd_client));
@@ -139,6 +152,283 @@ int lockdownd_hello(lockdownd_client *control) {
139 return 0; 152 return 0;
140} 153}
141 154
155int lockdownd_get_device_public_key(lockdownd_client *control, char **public_key)
156{
157 xmlDocPtr plist = new_plist();
158 xmlNode *dict = NULL;
159 xmlNode *key = NULL;;
160 char **dictionary = NULL;
161 int bytes = 0, i = 0;
162 char *XML_content = NULL;
163 uint32 length = 0;
164
165 /* Setup DevicePublicKey request plist */
166 dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
167 key = add_key_str_dict_element(plist, dict, "Key", "DevicePublicKey", 1);
168 key = add_key_str_dict_element(plist, dict, "Request", "GetValue", 1);
169 xmlDocDumpMemory(plist, (xmlChar**)&XML_content, &length);
170
171 /* send to iPhone */
172 bytes = lockdownd_send(control, XML_content, length);
173
174 xmlFree(XML_content);
175 xmlFreeDoc(plist); plist = NULL;
176
177 /* Now get iPhone's answer */
178 bytes = lockdownd_recv(control, &XML_content);
179
180 plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0);
181 if (!plist) return 0;
182 dict = xmlDocGetRootElement(plist);
183 for (dict = dict->children; dict; dict = dict->next) {
184 if (!xmlStrcmp(dict->name, "dict")) break;
185 }
186 if (!dict) return 0;
187
188 /* Parse xml to check success and to find public key */
189 dictionary = read_dict_element_strings(dict);
190 xmlFreeDoc(plist);
191 free(XML_content);
192
193 int success = 0;
194 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
195 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) {
196 success = 1;
197 }
198 if (!strcmp(dictionary[i], "Value")) {
199 *public_key = strdup(dictionary[i+1]);
200 }
201 }
202
203 if (dictionary) {
204 free_dictionary(dictionary);
205 dictionary = NULL;
206 }
207 return success;
208}
209
210int lockdownd_init(iPhone *phone, lockdownd_client **control)
211{
212 int ret = 0;
213 char *host_id = NULL;
214
215 if (!phone)
216 return 0;
217
218 *control = new_lockdownd_client(phone);
219 if (!lockdownd_hello(*control)){
220 fprintf(stderr, "Hello failed in the lockdownd client.\n");
221 }
222
223 char *public_key = NULL;
224 if(!lockdownd_get_device_public_key(*control, &public_key)){
225 fprintf(stderr, "Device refused to send public key.\n");
226 }
227
228 host_id = get_host_id();
229 if (!is_device_known(public_key)){
230 ret = lockdownd_pair_device(*control, public_key, host_id);
231 }
232 free(public_key);
233 public_key = NULL;
234
235 if (ret && host_id && !lockdownd_start_SSL_session(*control, host_id)) {
236 fprintf(stderr, "SSL Session opening failed.\n");
237 } else {
238 ret = 1;
239 free(host_id);
240 host_id = NULL;
241 }
242
243 return ret;
244}
245
246int lockdownd_pair_device(lockdownd_client *control, char *public_key_b64, char *host_id)
247{
248 int ret = 0;
249 xmlDocPtr plist = new_plist();
250 xmlNode *dict = NULL;
251 xmlNode *dictRecord = NULL;
252 char **dictionary = NULL;
253 int bytes = 0, i = 0;
254 char *XML_content = NULL;
255 uint32 length = 0;
256
257 char* device_cert_b64 = NULL;
258 char* host_cert_b64 = NULL;
259 char* root_cert_b64 = NULL;
260
261 lockdownd_gen_pair_cert(public_key_b64, &device_cert_b64, &host_cert_b64, &root_cert_b64);
262
263 /* Setup Pair request plist */
264 dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
265 add_key_str_dict_element(plist, dict, "Key", "PairRecord", 1);
266 dictRecord = add_child_to_plist(plist, "dict", "\n", NULL, 1);
267 add_key_data_dict_element(plist, dictRecord, "DeviceCertificate", device_cert_b64, 2);
268 add_key_data_dict_element(plist, dictRecord, "HostCertificate", host_cert_b64, 2);
269 add_key_str_dict_element(plist, dictRecord, "HostID", host_id, 2);
270 add_key_data_dict_element(plist, dictRecord, "RootCertificate", root_cert_b64, 2);
271 add_key_str_dict_element(plist, dict, "Request", "Pair", 1);
272
273 xmlDocDumpMemory(plist, (xmlChar**)&XML_content, &length);
274
275 /* send to iPhone */
276 bytes = lockdownd_send(control, XML_content, length);
277
278 xmlFree(XML_content);
279 xmlFreeDoc(plist); plist = NULL;
280
281 /* Now get iPhone's answer */
282 bytes = lockdownd_recv(control, &XML_content);
283
284 plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0);
285 if (!plist) return 0;
286 dict = xmlDocGetRootElement(plist);
287 for (dict = dict->children; dict; dict = dict->next) {
288 if (!xmlStrcmp(dict->name, "dict")) break;
289 }
290 if (!dict) return 0;
291
292 /* Parse xml to check success and to find public key */
293 dictionary = read_dict_element_strings(dict);
294 xmlFreeDoc(plist);
295 free(XML_content);
296
297 int success = 0;
298 for (i = 0; strcmp(dictionary[i], ""); i+=2) {
299 if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) {
300 success = 1;
301 }
302 }
303
304 if (dictionary) {
305 free_dictionary(dictionary);
306 dictionary = NULL;
307 }
308
309 /* store public key in config if pairing succeeded */
310 if (success)
311 store_device_public_key(public_key_b64);
312 return ret;
313}
314
315int lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_b64, char **host_cert_b64, char **root_cert_b64)
316{
317 int ret = 0;
318
319 gnutls_datum_t modulus = {NULL, 0};
320 gnutls_datum_t exponent = {NULL, 0};
321
322 /* first decode base64 public_key */
323 gnutls_datum_t pem_pub_key;
324 pem_pub_key.data = g_base64_decode (public_key_b64, &pem_pub_key.size);
325
326
327 /* now decode the PEM encoded key */
328 gnutls_datum_t der_pub_key;
329 if( GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc ("RSA PUBLIC KEY", &pem_pub_key, &der_pub_key) ){
330 ret = 1;
331
332 /* initalize asn.1 parser */
333 ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY;
334 if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) {
335
336 ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY;
337 asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key);
338
339 if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) {
340
341 /* get size to read */
342 int ret1 = asn1_read_value (asn1_pub_key, "modulus", NULL, &modulus.size);
343 int ret2 = asn1_read_value (asn1_pub_key, "publicExponent", NULL, &exponent.size);
344
345 modulus.data = gnutls_malloc(modulus.size);
346 exponent.data = gnutls_malloc(exponent.size);
347
348 ret1 = asn1_read_value (asn1_pub_key, "modulus", modulus.data, &modulus.size);
349 ret2 = asn1_read_value (asn1_pub_key, "publicExponent", exponent.data, &exponent.size);
350 if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2)
351 ret = 1;
352 }
353 if (asn1_pub_key)
354 asn1_delete_structure(&asn1_pub_key);
355 }
356 if (pkcs1)
357 asn1_delete_structure(&pkcs1);
358 }
359
360 /* now generate certifcates */
361 if (1 == ret && 0 != modulus.size && 0 != exponent.size) {
362
363 gnutls_global_init();
364 int effthis = 0;
365 gnutls_datum_t essentially_null = {strdup("abababababababab"), strlen("abababababababab")};
366
367 gnutls_x509_privkey_t fake_privkey, root_privkey;
368 gnutls_x509_crt_t dev_cert, root_cert;
369
370 gnutls_x509_privkey_init(&fake_privkey);
371 gnutls_x509_crt_init(&dev_cert);
372
373 if ( GNUTLS_E_SUCCESS == gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null, &essentially_null, &essentially_null) ) {
374
375 gnutls_x509_privkey_init(&root_privkey);
376
377 /* get certificate stored in config */
378 *host_cert_b64 = get_host_certificate();
379 *root_cert_b64 = get_root_certificate();
380
381 gnutls_datum_t pem_root_cert = {NULL, 0};
382 pem_root_cert.data = g_base64_decode (*root_cert_b64, &pem_root_cert.size);
383
384 ret = gnutls_x509_crt_import (root_cert, &pem_root_cert, GNUTLS_X509_FMT_PEM);
385 gnutls_free(pem_root_cert.data);
386
387
388 /* get root private key */
389 char *root_priv_b64 = get_root_private_key();
390 gnutls_datum_t pem_root_priv = {NULL, 0};
391 pem_root_priv.data = g_base64_decode (root_priv_b64, &pem_root_priv.size);
392
393 ret = gnutls_x509_privkey_import (root_privkey, &pem_root_priv, GNUTLS_X509_FMT_PEM);
394 gnutls_free(pem_root_priv.data);
395
396 /* generate device certificate */
397
398 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
399 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
400 gnutls_x509_crt_set_version(dev_cert, 3);
401 gnutls_x509_crt_set_ca_status(dev_cert, 0);
402 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
403 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
404 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
405
406 //TODO handle errors
407 ret = 1;
408
409 if (ret) {
410 /* if everything went well, export in PEM format */
411
412 gnutls_datum_t dev_pem = {NULL, 0};
413 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &dev_pem.size);
414 dev_pem.data = gnutls_malloc(dev_pem.size);
415 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &dev_pem.size);
416
417 /* now encode certificates for output */
418 *device_cert_b64 = g_base64_encode(dev_pem.data, dev_pem.size);
419 ret = 1;
420 }
421 }
422 }
423
424 gnutls_free(modulus.data);
425 gnutls_free(exponent.data);
426
427 gnutls_free(der_pub_key.data);
428 g_free(pem_pub_key.data);
429 return ret;
430}
431
142int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID) { 432int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID) {
143 xmlDocPtr plist = new_plist(); 433 xmlDocPtr plist = new_plist();
144 xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); 434 xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);