1/* 2 * Copyright (c) 2006 Apple Computer, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * 6-July-2006 31 * DRI: Christopher Ryan <ryanc@apple.com> 32*/ 33 34#include <stdlib.h> 35#include <string.h> 36#include <assert.h> 37#include <libxml/xmlwriter.h> 38#include <libxml/xmlreader.h> 39#include <inttypes.h> /* for PRIu64 */ 40#include <unistd.h> 41 42#include "xar.h" 43#include "archive.h" 44#include "b64.h" 45#include "signature.h" 46 47struct _signature_copy_context{ 48 void *buffer; 49 size_t length; 50 off_t offset; 51}; 52 53#ifdef __APPLE__ 54xar_signature_t xar_signature_new_internal(xar_t x, int is_extended, const char *type, int32_t length, xar_signer_callback callback, void *callback_context) 55#else 56xar_signature_t xar_signature_new(xar_t x,const char *type, int32_t length, xar_signer_callback callback, void *callback_context) 57#endif 58{ 59 xar_signature_t ret; 60 61 if( XAR(x)->files ){ 62 xar_err_new(x); 63 xar_err_set_string(x, "Signatures must be added before files are added"); 64 xar_err_callback(x, XAR_SEVERITY_WARNING, XAR_ERR_ARCHIVE_CREATION); 65 return NULL; 66 } 67 68 ret = malloc(sizeof(struct __xar_signature_t)); 69 if( ! ret ) 70 return NULL; 71 72 memset(XAR_SIGNATURE(ret), 0, sizeof(struct __xar_signature_t)); 73 XAR_SIGNATURE(ret)->type = strdup(type); 74 XAR_SIGNATURE(ret)->len = length; 75 XAR_SIGNATURE(ret)->offset = XAR(x)->heap_offset; 76 XAR_SIGNATURE(ret)->signer_callback = callback; 77 XAR_SIGNATURE(ret)->callback_context = callback_context; 78#ifdef __APPLE__ 79 XAR_SIGNATURE(ret)->is_extended = is_extended; 80#endif 81 82 /* Pre allocate space in the heap */ 83 XAR(x)->heap_offset += length; 84 XAR(x)->heap_len += length; 85 86 // Put the new on at the end of the list 87 if( XAR_SIGNATURE(XAR(x)->signatures) ) { 88 struct __xar_signature_t *sig; 89 90 // (Apple) Find the end of the signatures list 91 // The open source code seems to smash list items 1 through n when the head of this list is already defined 92 // despite the fact that the xar signatures are implemented as a list. This is an Apple xar 1.4 edit 93 // to allow that list to grow beyond 2 94 for( sig = XAR_SIGNATURE(XAR(x)->signatures); sig->next; sig = sig->next); 95 96 sig->next = XAR_SIGNATURE(ret); 97 } else 98 XAR(x)->signatures = ret; 99 100 XAR_SIGNATURE(ret)->x = x; 101 102 return ret; 103 104} 105 106#ifdef __APPLE__ 107xar_signature_t xar_signature_new(xar_t x,const char *type, int32_t length, xar_signer_callback callback, void *callback_context) 108{ 109 return xar_signature_new_internal(x, 0, type, length, callback, callback_context); 110} 111#endif 112 113xar_signature_t xar_signature_new_extended(xar_t x,const char *type, int32_t length, xar_signer_callback callback, void *callback_context) 114{ 115#ifdef __APPLE__ 116 return xar_signature_new_internal(x, 1, type, length, callback, callback_context); 117#else 118 return xar_signature_new(x, type, length, callback, callback_context); 119#endif 120} 121 122const char *xar_signature_type(xar_signature_t s) 123{ 124 if( !s ) 125 return NULL; 126 127 return XAR_SIGNATURE(s)->type; 128} 129 130/* Add x509 cert data to this signature */ 131int32_t xar_signature_add_x509certificate(xar_signature_t sig, const uint8_t *cert_data, uint32_t cert_len ) 132{ 133 struct __xar_x509cert_t *newcert; 134 135 if( !sig ) 136 return -1; 137 138 newcert = malloc(sizeof(struct __xar_x509cert_t)); 139 memset(newcert, 0, sizeof(struct __xar_x509cert_t)); 140 newcert->content = malloc(sizeof(const char)*cert_len); 141 memcpy(newcert->content,cert_data,cert_len); 142 newcert->len = cert_len; 143 144 if( XAR_SIGNATURE(sig)->x509certs ){ 145 struct __xar_x509cert_t *cert; 146 147 // Find the end of the linked list 148 for( cert = XAR_SIGNATURE(sig)->x509certs; cert->next; cert = cert->next ); 149 150 cert->next = newcert; 151 }else{ 152 XAR_SIGNATURE(sig)->x509certs = newcert; 153 } 154 155 XAR_SIGNATURE(sig)->x509cert_count++; 156 157 return 0; 158} 159 160int32_t xar_signature_get_x509certificate_count(xar_signature_t sig) 161{ 162 if( !sig ){ 163 return 0; 164 } 165 166 return XAR_SIGNATURE(sig)->x509cert_count; 167} 168 169int32_t xar_signature_get_x509certificate_data(xar_signature_t sig, int32_t index, const uint8_t **cert_data, uint32_t *cert_len) 170{ 171 struct __xar_x509cert_t *cert; 172 int i = 0; 173 174 /* If there are no certs to return, return immediatly */ 175 if( !XAR_SIGNATURE(sig)->x509cert_count ){ 176 if( cert_data ) 177 *cert_data = 0; 178 179 return -1; 180 } 181 182 183 /* Loop through the certs, copying each one's string ptr to the array */ 184 for( cert = XAR_SIGNATURE(sig)->x509certs; cert; cert = cert->next ){ 185 if( i == index ){ 186 if( cert_data ) 187 *cert_data = cert->content; 188 189 if( cert_len ) 190 *cert_len = cert->len; 191 break; 192 } 193 i++; 194 } 195 196 /* If the cert iterator is still valid, we did not find the proper index */ 197 if( !cert ){ 198 return -1; 199 } 200 201 return 0; 202} 203 204xar_signature_t xar_signature_first(xar_t x) 205{ 206 return XAR(x)->signatures; 207} 208 209xar_signature_t xar_signature_next(xar_signature_t s) 210{ 211 return XAR_SIGNATURE(s)->next; 212} 213 214int32_t _xar_signature_read_from_heap(xar_t x ,off_t offset,size_t length,uint8_t *data) 215{ 216 off_t seek_off = XAR(x)->toc_count + sizeof(xar_header_t) + offset; 217 int r = 0; 218 219 r = lseek(XAR(x)->fd, seek_off, SEEK_SET); 220 221 /* can't seek to the proper location */ 222 if( -1 == r ){ 223 xar_err_new(x); 224 xar_err_set_string(x, "Unable to seek"); 225 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 226 return -1; 227 } 228 229 r = read(XAR(x)->fd,data,length); 230 231 if( r != length ){ 232 xar_err_new(x); 233 xar_err_set_string(x, "Unable to read"); 234 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 235 return -1; 236 } 237 238 return 0; 239} 240 241/* This method retrieves the signed data for this segment as well as the data the signed data is signing */ 242uint8_t xar_signature_copy_signed_data(xar_signature_t sig, uint8_t **data, uint32_t *length, uint8_t **signed_data, uint32_t *signed_length, off_t *signed_offset) 243{ 244 uint32_t offset = 0; 245 xar_t x = NULL; 246 const char *value; 247 248 // xar 1.6 fails this method if any of data, length, signed_data, signed_length are NULL 249 // within OS X we use this method to get combinations of signature, signed data, or signed_offset, 250 // so this method checks and sets these out values independently 251 252 if( !sig ) 253 return -1; 254 255 x = XAR_SIGNATURE(sig)->x; 256 257 258 /* Get the checksum, to be used for signing. If we support multiple checksums 259 in the future, all checksums should be retrieved */ 260 if(length) { 261 if(0 == xar_prop_get( XAR_FILE(x) , "checksum/size", &value)){ 262 *length = strtoull( value, (char **)NULL, 10); 263 } 264 265 if(0 == xar_prop_get( XAR_FILE(x) , "checksum/offset", &value)){ 266 offset = strtoull( value, (char **)NULL, 10); 267 } 268 269 if(data) { 270 *data = malloc(sizeof(char)*(*length)); 271 272 _xar_signature_read_from_heap(x, offset, *length, *data); 273 } 274 } 275 276 /* read signature data */ 277 offset = XAR_SIGNATURE(sig)->offset; 278 279 // This parameter is an Apple edit 280 // This out value is ignored OS X in SL, but this method prototype is included in the 10.5 SDK 281 if( signed_offset ) 282 *signed_offset = offset; 283 284 if(signed_length) { 285 286 *signed_length = XAR_SIGNATURE(sig)->len; 287 288 if(signed_data) { 289 *signed_data = malloc(sizeof(char)*(*signed_length)); 290 291 _xar_signature_read_from_heap(x, offset, *signed_length, *signed_data); 292 } 293 } 294 295 return 0; 296} 297 298xar_signature_t xar_signature_unserialize(xar_t x, xmlTextReaderPtr reader) 299{ 300 struct __xar_signature_t *ret = NULL; 301#ifdef __APPLE__ 302 const xmlChar *sig_type = NULL; 303#endif 304 const xmlChar *value = NULL; 305 const xmlChar *name = NULL; 306 int type; 307 size_t outputLength = 0; 308 309 ret = malloc(sizeof(struct __xar_signature_t)); 310 311 if( ! ret ) 312 return NULL; 313 314 memset(ret, 0, sizeof(struct __xar_signature_t)); 315 316 ret->x = x; 317 318 /* Read One Signature Element */ 319#ifdef __APPLE__ 320 sig_type = xmlTextReaderConstLocalName(reader); 321 if(strcmp((const char*)sig_type, "x-signature") == 0) { 322 ret->is_extended = 1; 323 } 324#endif 325 326 /* Retrieve the type attr */ 327 value = xmlTextReaderGetAttribute(reader, (const xmlChar*)"style"); 328 329 if( value ){ 330 ret->type = strdup((const char *)value); 331 } 332 333 /* Look for the rest of the child elements */ 334 while( xmlTextReaderRead(reader) == 1 ) { 335 type = xmlTextReaderNodeType(reader); 336 name = xmlTextReaderConstLocalName(reader); 337 338 if (value) { 339 xmlFree((void*)value); 340 value = NULL; 341 } 342 343 if( type == XML_READER_TYPE_ELEMENT ) { 344 if(strcmp((const char*)name, "size") == 0) { 345 while( xmlTextReaderRead(reader) == 1 ) { 346 type = xmlTextReaderNodeType(reader); 347 if( type == XML_READER_TYPE_TEXT ) { 348 349 value = xmlTextReaderConstValue(reader); 350 ret->len = strtoull( (const char *)value, (char **)NULL, 10); 351 value = NULL; /* We don't want to accidentally release this const. */ 352 }else if( type == XML_READER_TYPE_END_ELEMENT ) { 353 break; 354 } 355 } 356 } else if( strcmp((const char*)name, "offset") == 0 ){ 357 while( xmlTextReaderRead(reader) == 1 ) { 358 type = xmlTextReaderNodeType(reader); 359 if( type == XML_READER_TYPE_TEXT ) { 360 361 value = xmlTextReaderConstValue(reader); 362 ret->offset = strtoull( (const char *)value, (char **)NULL, 10); 363 value = NULL; /* We don't want to accidentally release this const. */ 364 }else if( type == XML_READER_TYPE_END_ELEMENT ) { 365 break; 366 } 367 } 368 } else if( strcmp((const char*)name, "KeyInfo") == 0 ){ 369 while( xmlTextReaderRead(reader) == 1 ) { 370 type = xmlTextReaderNodeType(reader); 371 name = xmlTextReaderConstLocalName(reader); 372 373 if( type == XML_READER_TYPE_ELEMENT ) { 374 if(strcmp((const char*)name, "X509Data") == 0) { 375 while( xmlTextReaderRead(reader) == 1 ) { 376 type = xmlTextReaderNodeType(reader); 377 name = xmlTextReaderConstLocalName(reader); 378 379 if( type == XML_READER_TYPE_ELEMENT ) { 380 if(strcmp((const char*)name, "X509Certificate") == 0) { 381 while( xmlTextReaderRead(reader) == 1 ) { 382 type = xmlTextReaderNodeType(reader); 383 if( type == XML_READER_TYPE_TEXT ) { 384 unsigned char *sig_data = NULL; 385 386 value = xmlTextReaderConstValue(reader); 387 388 /* this method allocates the resulting data */ 389 sig_data = xar_from_base64(value, strlen((const char *)value), &outputLength); 390 391 if(sig_data){ 392 /* for convience we just use the same method, which means multiple allocations */ 393 xar_signature_add_x509certificate(ret, sig_data, outputLength); 394 free(sig_data); 395 }else{ 396 ret = NULL; 397 } 398 399 value = NULL; /* We don't want to accidentally release this const. */ 400 //break; 401 }else if( type == XML_READER_TYPE_END_ELEMENT ) { 402 break; 403 } 404 } 405 } 406 }else if( type == XML_READER_TYPE_END_ELEMENT ) { 407 break; 408 } 409 } 410 } 411 }else if( type == XML_READER_TYPE_END_ELEMENT ) { 412 break; 413 } 414 415 } 416 } 417 }else if( type == XML_READER_TYPE_TEXT ) { 418 419 value = xmlTextReaderConstValue(reader); 420 value = NULL; /* We don't want to accidentally release this const. */ 421 422 break; 423 }else if( type == XML_READER_TYPE_END_ELEMENT ) { 424 break; 425 } 426 } 427 428 if (value) { 429 xmlFree((void*)value); 430 value = NULL; 431 } 432 433 return ret; 434} 435 436/* 437 <signature style="SHA1withRSA"> 438 <offset>20</offset> 439 <size>256</size> 440 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 441 <X509Data> 442 <X509Certificate>MIICXTCCA...base64...</X509Certificate> 443 </X509Data> 444 </KeyInfo> 445 </signature> 446 */ 447/* This function will serialize an entire list of signatures */ 448int32_t xar_signature_serialize(xar_signature_t sig, xmlTextWriterPtr writer) 449{ 450 if( !sig ) return 0; 451 452 /* <signature type='EncryptionAlgorithm'> */ 453#ifdef __APPLE__ 454 const char* element_name = XAR_SIGNATURE(sig)->is_extended ? "x-signature" : "signature"; 455 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST(element_name), NULL); 456#else 457 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST("signature"), NULL); 458#endif 459 460 /* write out the style */ 461 xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(XAR_SIGNATURE(sig)->type)); 462 463 /* <offset> */ 464 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST("offset"), NULL); 465 xmlTextWriterWriteFormatString(writer, "%"PRIu64, (uint64_t)(XAR_SIGNATURE(sig)->offset)); 466 xmlTextWriterEndElement(writer); 467 468 /* <size> */ 469 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST("size"), NULL); 470 xmlTextWriterWriteFormatString(writer, "%d", (XAR_SIGNATURE(sig)->len)); 471 xmlTextWriterEndElement(writer); 472 473 /* <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> */ 474 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST("KeyInfo"), NULL); 475 xmlTextWriterWriteAttribute(writer, BAD_CAST("xmlns"), BAD_CAST("http://www.w3.org/2000/09/xmldsig#")); 476 477 /* If we have x509 certs, write them out */ 478 if( XAR_SIGNATURE(sig)->x509certs ){ 479 struct __xar_x509cert_t *cert; 480 481 /* <X509Data> */ 482 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST("X509Data"), NULL); 483 484 /* Loop through the certs, copying each one's string ptr to the array */ 485 for( cert = XAR_SIGNATURE(sig)->x509certs; cert; cert = cert->next ){ 486 xmlTextWriterStartElementNS( writer, NULL, BAD_CAST("X509Certificate"), NULL); 487 xmlTextWriterWriteBase64( writer, (const char *)cert->content, 0, cert->len); 488 xmlTextWriterEndElement(writer); 489 } 490 491 /* </X509Data> */ 492 xmlTextWriterEndElement(writer); 493 } 494 495 /* </KeyInfo> */ 496 xmlTextWriterEndElement(writer); 497 498 499 /* </signature> */ 500 xmlTextWriterEndElement(writer); 501 502 /* serialize the next signature */ 503 if( XAR_SIGNATURE(sig)->next ) 504 xar_signature_serialize(XAR_SIGNATURE(sig)->next,writer); 505 506 return 0; 507} 508 509void _xar_signature_remove_cert(struct __xar_x509cert_t *cert) 510{ 511 struct __xar_x509cert_t *next; 512 513 if( !cert ) 514 return; 515 516 next = cert->next; 517 518 if( cert->content ) 519 free(cert->content); 520 521 free(cert); 522 523 _xar_signature_remove_cert(next); 524 525 return; 526} 527 528void xar_signature_remove(xar_signature_t sig) 529{ 530 xar_signature_t next; 531 532 if( !sig ) 533 return; 534 535 next = XAR_SIGNATURE(sig)->next; 536 537 if( XAR_SIGNATURE(sig)->type ) 538 free(XAR_SIGNATURE(sig)->type); 539 540 if( XAR_SIGNATURE(sig)->x509cert_count ){ 541 _xar_signature_remove_cert(XAR_SIGNATURE(sig)->x509certs); 542 } 543 544 free(XAR_SIGNATURE(sig)); 545 546 /* remove the next one in the list */ 547 xar_signature_remove(next); 548 549 return; 550} 551