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