X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_manifest/lib/SecureDownloadInternal.c?ds=sidebyside diff --git a/libsecurity_manifest/lib/SecureDownloadInternal.c b/libsecurity_manifest/lib/SecureDownloadInternal.c deleted file mode 100644 index a12dd14c..00000000 --- a/libsecurity_manifest/lib/SecureDownloadInternal.c +++ /dev/null @@ -1,877 +0,0 @@ -#include - -#include "SecureDownloadInternal.h" - -// -// SecureDownloadXML: SecureDownloadXML.c -// cc -g -framework CoreFoundation -o $@ $^ -// - -#define LOCAL_DEBUG 0 - -#if LOCAL_DEBUG -extern CFDataRef read_data(char* path); -#endif - -#define SD_XML_NAMESPACE CFSTR("http://www.apple.com/2006/SecureDownload/1") -#define SD_XML_ROOT CFSTR("SecureDownload") -#define SD_XML_RESOURCE CFSTR("resource") -#define SD_XML_SITES CFSTR("sites") -#define SD_XML_VERIFICATION CFSTR("verification") -#define SD_XML_ATTR_ALGORITHM CFSTR("algorithm") - -struct parseState { - CFDictionaryRef namespaces; // array of dictionaries of namespace declarations -#if LOCAL_DEBUG - char* prefix; -#endif - CFMutableArrayRef plists; // array of all resource plists - CFMutableDictionaryRef plist; // most recent entry in the plists array -}; - - -static inline unsigned char decode64(unsigned char c) -{ - switch(c) { - case 'A': return 0; - case 'B': return 1; - case 'C': return 2; - case 'D': return 3; - case 'E': return 4; - case 'F': return 5; - case 'G': return 6; - case 'H': return 7; - case 'I': return 8; - case 'J': return 9; - case 'K': return 10; - case 'L': return 11; - case 'M': return 12; - case 'N': return 13; - case 'O': return 14; - case 'P': return 15; - case 'Q': return 16; - case 'R': return 17; - case 'S': return 18; - case 'T': return 19; - case 'U': return 20; - case 'V': return 21; - case 'W': return 22; - case 'X': return 23; - case 'Y': return 24; - case 'Z': return 25; - case 'a': return 26; - case 'b': return 27; - case 'c': return 28; - case 'd': return 29; - case 'e': return 30; - case 'f': return 31; - case 'g': return 32; - case 'h': return 33; - case 'i': return 34; - case 'j': return 35; - case 'k': return 36; - case 'l': return 37; - case 'm': return 38; - case 'n': return 39; - case 'o': return 40; - case 'p': return 41; - case 'q': return 42; - case 'r': return 43; - case 's': return 44; - case 't': return 45; - case 'u': return 46; - case 'v': return 47; - case 'w': return 48; - case 'x': return 49; - case 'y': return 50; - case 'z': return 51; - case '0': return 52; - case '1': return 53; - case '2': return 54; - case '3': return 55; - case '4': return 56; - case '5': return 57; - case '6': return 58; - case '7': return 59; - case '8': return 60; - case '9': return 61; - case '+': return 62; - case '/': return 63; - } - return 255; -} - -// Decodes base64 data into a binary CFData object -// If first character on a line is not in the base64 alphabet, the line -// is ignored. -static CFDataRef decodeBase64Data(const UInt8* ptr, size_t len) { - CFMutableDataRef result = CFDataCreateMutable(NULL, len); // data can't exceed len bytes - if (!result) return NULL; - - CFIndex i, j; - - int skip = 0; - - UInt8 triplet[3] = {0, 0, 0}; - -/* -http://www.faqs.org/rfcs/rfc3548.html - +--first octet--+-second octet--+--third octet--+ - |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| - +-----------+---+-------+-------+---+-----------+ - |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0| - +--1.index--+--2.index--+--3.index--+--4.index--+ -*/ - - for (i = 0, j = 0; i < len; ++i) { - unsigned char c = ptr[i]; - if (c == ' ') { continue; } - if (c == '\t') { continue; } - if (c == '\r') { continue; } - if (c == '\n') { skip = 0; continue; } - if (skip) { continue; } - if (!skip && c == '=') { --j; skip = 1; continue; } - unsigned char x = decode64(c); - if (x == 255) { skip = 1; continue; } - - if (j == 0) { - triplet[0] |= ((x << 2) & 0xFC); - ++j; - } else if (j == 1) { - triplet[0] |= ((x >> 4) & 0x03); - triplet[1] |= ((x << 4) & 0xF0); - ++j; - } else if (j == 2) { - triplet[1] |= ((x >> 2) & 0x0F); - triplet[2] |= ((x << 6) & 0xC0); - ++j; - } else if (j == 3) { - triplet[2] |= ((x) & 0x3F); - CFDataAppendBytes(result, triplet, j); - memset(triplet, 0, sizeof(triplet)); - j = 0; - } - } - if (j > 0) { - CFDataAppendBytes(result, triplet, j); - } - return result; -} - -// Returns a CFString containing the base64 representation of the data. -// boolean argument for whether to line wrap at 64 columns or not. -static CFStringRef encodeBase64String(const UInt8* ptr, size_t len, int wrap) { - const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/="; - - // base64 encoded data uses 4 ASCII characters to represent 3 octets. - // There can be up to two == at the end of the base64 data for padding. - // If we are line wrapping then we need space for one newline character - // every 64 characters of output. - // Rounded 4/3 up to 2 to avoid floating point math. - - //CFIndex max_len = (2*len) + 2; - //if (wrap) len = len + ((2*len) / 64) + 1; - - CFMutableStringRef string = CFStringCreateMutable(NULL, 0); - if (!string) return NULL; - -/* -http://www.faqs.org/rfcs/rfc3548.html - +--first octet--+-second octet--+--third octet--+ - |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| - +-----------+---+-------+-------+---+-----------+ - |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0| - +--1.index--+--2.index--+--3.index--+--4.index--+ -*/ - int i = 0; // octet offset into input data - int column = 0; // output column number (used for line wrapping) - for (;;) { - UniChar c[16]; // buffer of characters to add to output - int j = 0; // offset to place next character in buffer - int index; // index into output alphabet - -#define ADDCHAR(_X_) do { c[j++] = _X_; if (wrap && (++column == 64)) { column = 0; c[j++] = '\n'; } } while (0); - - // 1.index - index = (ptr[i] >> 2) & 0x3F; - ADDCHAR(alphabet[index]); - - // 2.index - index = (ptr[i] << 4) & 0x30; - if ((i+1) < len) { - index = index | ((ptr[i+1] >> 4) & 0x0F); - ADDCHAR(alphabet[index]); - } else { // end of input, pad as necessary - ADDCHAR(alphabet[index]); - ADDCHAR('='); - ADDCHAR('='); - } - - // 3.index - if ((i+1) < len) { - index = (ptr[i+1] << 2) & 0x3C; - if ((i+2) < len) { - index = index | ((ptr[i+2] >> 6) & 0x03); - ADDCHAR(alphabet[index]); - } else { // end of input, pad as necessary - ADDCHAR(alphabet[index]); - ADDCHAR('='); - } - } - - // 4.index - if ((i+2) < len) { - index = (ptr[i+2]) & 0x3F; - ADDCHAR(alphabet[index]); - } - - CFStringAppendCharacters(string, c, j); - i += 3; // we processed 3 bytes of input - if (i >= len) { - // end of data, append newline if we haven't already - if (wrap && c[j-1] != '\n') { - c[0] = '\n'; - CFStringAppendCharacters(string, c, 1); - } - break; - } - } - return string; -} - - -// makes a copy of the current namespaces dictionary, adding in any -// namespaces defined by the current node. -static CFDictionaryRef copyNamespacesForNode(CFDictionaryRef namespaces, CFXMLNodeRef node) { - CFMutableDictionaryRef result = NULL; - - CFXMLNodeTypeCode type = CFXMLNodeGetTypeCode(node); - - // careful, don't use the info unless we ensure type == kCFXMLNodeTypeElement - CFXMLElementInfo* info = (CFXMLElementInfo*)CFXMLNodeGetInfoPtr(node); - - // - // create our result dictionary - // there are four possible configurations: - // 1. previous dictionary exists, this is an element, and has attributes: - // clone existing dictionary, we may be adding to it - // 2. previous dictionary exists, not an element or no attributes: - // retain existing dictionary and return - // 3. no previous dictionary, this is an element, and has attributes: - // create new dictionary, we may be adding to it - // 4. no previous dictionary, not an element or no attributes: - // create new dictionary and return - // - if (namespaces && type == kCFXMLNodeTypeElement && info->attributes && info->attributeOrder) { - result = CFDictionaryCreateMutableCopy(NULL, 0, namespaces); - } else if (namespaces) { - result = (CFMutableDictionaryRef)CFRetain(namespaces); - return result; - } else if (type == kCFXMLNodeTypeElement && info->attributes && info->attributeOrder) { - result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (result) CFDictionarySetValue(result, CFSTR(""), CFSTR("")); - } else { - result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (result) CFDictionarySetValue(result, CFSTR(""), CFSTR("")); - return result; - } - if (!result) return NULL; - - // - // if we got this far, we're dealing with an XML element with - // attributes. check to see if any are xml namespace attributes. - // - CFArrayRef attrs = info->attributeOrder; - CFIndex i, count = CFArrayGetCount(attrs); - for (i = 0; i < count; ++i) { - CFStringRef attr = CFArrayGetValueAtIndex(attrs, i); - - if (CFEqual(CFSTR("xmlns"), attr)) { - // default namespace - CFStringRef value = CFDictionaryGetValue(info->attributes, attr); - if (value) { - CFDictionarySetValue(result, CFSTR(""), value); - } - } else { - // if the attribute is in the "xmlns" namespace, then it's - // really a declaration of a new namespace. record it in our dictionary. - CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(NULL, attr, CFSTR(":")); - CFIndex numparts = parts ? CFArrayGetCount(parts) : 0; - if (numparts == 2) { - CFStringRef prefix = CFArrayGetValueAtIndex(parts, 0); - CFStringRef suffix = CFArrayGetValueAtIndex(parts, 1); - if (CFEqual(CFSTR("xmlns"), prefix)) { - CFStringRef value = CFDictionaryGetValue(info->attributes, attr); - if (value) { - CFDictionarySetValue(result, suffix, value); - } - } - } - if (parts) CFRelease(parts); - } - } - return result; -} - -// returns the current node's element name and namespace URI -// based on the currently defined namespaces. -static void copyNodeNamespaceAndName(CFDictionaryRef namespaces, CFXMLNodeRef node, CFStringRef* namespace, CFStringRef* name) { - CFXMLNodeTypeCode type = CFXMLNodeGetTypeCode(node); - *namespace = NULL; - *name = NULL; - if (type == kCFXMLNodeTypeElement) { - CFStringRef qname = CFXMLNodeGetString(node); - CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(NULL, qname, CFSTR(":")); - CFIndex numparts = parts ? CFArrayGetCount(parts) : 0; - if (numparts == 1) { - // default namespace - *namespace = CFRetain(CFDictionaryGetValue(namespaces, CFSTR(""))); - *name = CFRetain(CFArrayGetValueAtIndex(parts, 0)); - } else if (numparts == 2) { - CFStringRef prefix = CFArrayGetValueAtIndex(parts, 0); - CFStringRef ns = CFDictionaryGetValue(namespaces, prefix); - *namespace = ns ? CFRetain(ns) : NULL; - *name = CFRetain(CFArrayGetValueAtIndex(parts, 1)); - } else { - // bogus xml - } - if (parts) CFRelease(parts); - } -} - -// helper function for copyTreeString() below -// appends text nodes to the mutable string context -static void _appendTreeString(const void *value, void *context) { - CFXMLTreeRef tree = (CFXMLTreeRef)value; - CFMutableStringRef result = (CFMutableStringRef)context; - - CFXMLNodeRef node = CFXMLTreeGetNode(tree); - CFXMLNodeTypeCode type = CFXMLNodeGetTypeCode(node); - if (type == kCFXMLNodeTypeElement) { - CFTreeApplyFunctionToChildren(tree, _appendTreeString, result); - } else if (type == kCFXMLNodeTypeText) { - CFStringRef str = CFXMLNodeGetString(node); - if (str) CFStringAppend(result, str); - } -} - -// equivalent to the XPATH string() function -// concatenates all text nodes into a single string -static CFMutableStringRef copyTreeString(CFXMLTreeRef tree) { - CFMutableStringRef result = CFStringCreateMutable(NULL, 0); - CFTreeApplyFunctionToChildren(tree, _appendTreeString, result); - return result; -} - - -// returns an array of CFXMLTreeRef objects that are immediate -// children of the context node that match the specified element -// name and namespace URI -static CFArrayRef copyChildrenWithName(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - tree = CFTreeGetFirstChild(tree); - while (tree) { - CFXMLNodeRef node = CFXMLTreeGetNode(tree); - CFXMLNodeTypeCode type = CFXMLNodeGetTypeCode(node); - if (type == kCFXMLNodeTypeElement) { - CFDictionaryRef namespaces = copyNamespacesForNode(inNamespaces, node); - if (namespaces) { - CFStringRef ns, n; - copyNodeNamespaceAndName(namespaces, node, &ns, &n); - - if (ns && n && CFEqual(ns, namespace) && CFEqual(n, name)) { - CFArrayAppendValue(result, tree); - } - if (ns) CFRelease(ns); - if (n) CFRelease(n); - - CFRelease(namespaces); - } - } - tree = CFTreeGetNextSibling(tree); - } - return result; -} - -// convenience function to find the first child element -// with the given element name and namespace URI -static CFXMLTreeRef getChildWithName(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFXMLTreeRef result = NULL; - CFArrayRef array = copyChildrenWithName(tree, inNamespaces, namespace, name); - if (array && CFArrayGetCount(array) > 0) { - result = (CFXMLTreeRef)CFArrayGetValueAtIndex(array, 0); - } - if (array) CFRelease(array); - return result; -} - -// returns the string value of the specified child node -static CFStringRef copyChildWithNameAsString(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFStringRef result = NULL; - CFXMLTreeRef child = getChildWithName(tree, inNamespaces, namespace, name); - if (child) result = copyTreeString(child); - return result; -} - -// returns the integer value of the specified child node -static CFNumberRef copyChildWithNameAsInteger(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFNumberRef result = NULL; - CFXMLTreeRef child = getChildWithName(tree, inNamespaces, namespace, name); - if (child) { - CFStringRef str = copyTreeString(child); - if (str) { - SInt32 size = CFStringGetIntValue(str); - result = CFNumberCreate(NULL, kCFNumberSInt32Type, &size); - CFRelease(str); - } - } - return result; -} - -// returns an array of URLs aggregated from the child -// nodes matching the given name and namespace URI. -static CFArrayRef copyChildrenWithNameAsURLs(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFArrayRef children = copyChildrenWithName(tree, inNamespaces, namespace, name); - if (children) { - CFIndex i, count = CFArrayGetCount(children); - for (i = 0; i < count; ++i) { - CFXMLTreeRef child = (CFXMLTreeRef)CFArrayGetValueAtIndex(children, i); - CFStringRef str = copyTreeString(child); - if (str) { - CFURLRef url = CFURLCreateWithString(NULL, str, NULL); - if (url) { - CFArrayAppendValue(result, url); - CFRelease(url); - } - CFRelease(str); - } - } - CFRelease(children); - } - return result; -} - -// returns the base 64 decoded value of the specified child node -static CFDataRef copyChildWithNameAsData(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFDataRef result = NULL; - CFXMLTreeRef child = getChildWithName(tree, inNamespaces, namespace, name); - if (child) { - CFStringRef str = copyTreeString(child); - if (str) { - CFIndex len = CFStringGetLength(str); - CFIndex used; - UInt8* buffer = malloc(len); - // ASCII is one byte per character. Any inconvertible characters - // are assigned to whitespace and skipped. - if (buffer) { - if (CFStringGetBytes(str, CFRangeMake(0, len), kCFStringEncodingASCII, ' ', 0, buffer, len, &used)) { - result = decodeBase64Data(buffer, used); - } - free(buffer); - } - CFRelease(str); - } - } - return result; -} - -// returns the CFDate value of the specified child node -// whose string value is interpreted in W3C DateTime format -static CFDateRef copyChildWithNameAsDate(CFXMLTreeRef tree, CFDictionaryRef inNamespaces, CFStringRef namespace, CFStringRef name) { - CFDateRef result = NULL; - CFXMLTreeRef child = getChildWithName(tree, inNamespaces, namespace, name); - if (child) { - CFMutableStringRef str = copyTreeString(child); - if (str) { - CFStringTrimWhitespace(str); - if (CFStringGetLength(str) > 21) { - CFStringRef year = CFStringCreateWithSubstring(NULL, str, CFRangeMake(0, 4)); - CFStringRef month = CFStringCreateWithSubstring(NULL, str, CFRangeMake(5, 2)); - CFStringRef day = CFStringCreateWithSubstring(NULL, str, CFRangeMake(8, 2)); - CFStringRef hour = CFStringCreateWithSubstring(NULL, str, CFRangeMake(11, 2)); - CFStringRef minute = CFStringCreateWithSubstring(NULL, str, CFRangeMake(14, 2)); - CFStringRef second = CFStringCreateWithSubstring(NULL, str, CFRangeMake(17, 2)); - CFStringRef tenth = CFStringCreateWithSubstring(NULL, str, CFRangeMake(20, 1)); - - CFGregorianDate gregory; - memset(&gregory, 0, sizeof(gregory)); - if (year) { gregory.year = CFStringGetIntValue(year); CFRelease(year); } - if (month) { gregory.month = CFStringGetIntValue(month); CFRelease(month); } - if (day) { gregory.day = CFStringGetIntValue(day); CFRelease(day); } - if (hour) { gregory.hour = CFStringGetIntValue(hour); CFRelease(hour); } - if (minute) { gregory.minute = CFStringGetIntValue(minute); CFRelease(minute); } - if (second) { gregory.second = (double)CFStringGetIntValue(second); CFRelease(second); } - if (tenth) { gregory.second += ((double)CFStringGetIntValue(tenth)/(double)10.0); CFRelease(tenth); } - - CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0); - if (tz) { - CFAbsoluteTime at = CFGregorianDateGetAbsoluteTime(gregory, tz); - result = CFDateCreate(NULL, at); - CFRelease(tz); - } - } - CFRelease(str); - } - } - return result; -} - - -// generic parser for XML nodes in our ticket format -static void _parseXMLNode(const void *value, void *context) { - CFXMLTreeRef tree = (CFXMLTreeRef)value; - struct parseState* state = (struct parseState*)context; - - CFXMLNodeRef node = CFXMLTreeGetNode(tree); - assert(node); - - CFDictionaryRef namespaces = copyNamespacesForNode(state->namespaces, node); - - CFXMLNodeTypeCode type = CFXMLNodeGetTypeCode(node); - - int descend = 0; - - if (type == kCFXMLNodeTypeElement) { - CFStringRef ns, name; - copyNodeNamespaceAndName(namespaces, node, &ns, &name); - - if (ns && name) { - - if (CFEqual(ns, SD_XML_NAMESPACE)) { - if (CFEqual(name, SD_XML_ROOT)) { - - descend = 1; - - } else if (CFEqual(name, SD_XML_RESOURCE)) { - - state->plist = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (state->plist) { - CFArrayAppendValue(state->plists, state->plist); - CFRelease(state->plist); - } - - CFStringRef name = copyChildWithNameAsString(tree, namespaces, SD_XML_NAMESPACE, SD_XML_NAME); - if (name && state->plist) { - CFDictionarySetValue(state->plist, SD_XML_NAME, name); - CFRelease(name); - } - - CFNumberRef size = copyChildWithNameAsInteger(tree, namespaces, SD_XML_NAMESPACE, SD_XML_SIZE); - if (size && state->plist) { - CFDictionarySetValue(state->plist, SD_XML_SIZE, size); - CFRelease(size); - } - - CFDateRef created = copyChildWithNameAsDate(tree, namespaces, SD_XML_NAMESPACE, SD_XML_CREATED); - if (created && state->plist) { - CFDictionarySetValue(state->plist, SD_XML_CREATED, created); - CFRelease(created); - } - - descend = 1; - - } else if (CFEqual(name, SD_XML_SITES)) { - CFArrayRef urls = copyChildrenWithNameAsURLs(tree, namespaces, SD_XML_NAMESPACE, SD_XML_URL); - if (urls && state->plist) { - CFDictionarySetValue(state->plist, SD_XML_URL, urls); - CFRelease(urls); - } - - } else if (CFEqual(name, SD_XML_VERIFICATIONS)) { - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (dict && state->plist) { - CFDictionarySetValue(state->plist, SD_XML_VERIFICATIONS, dict); - CFRelease(dict); - descend = 1; - } - - } else if (CFEqual(name, SD_XML_VERIFICATION) && state->plist) { - CFMutableDictionaryRef verifications = (CFMutableDictionaryRef)CFDictionaryGetValue(state->plist, SD_XML_VERIFICATIONS); - CFXMLElementInfo* info = (CFXMLElementInfo*)CFXMLNodeGetInfoPtr(node); - if (verifications && info && info->attributes) { - CFStringRef algorithm = CFDictionaryGetValue(info->attributes, SD_XML_ATTR_ALGORITHM); - if (algorithm) { - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (dict) { - CFXMLTreeRef child; - #pragma unused(child) - - CFNumberRef sector_size = copyChildWithNameAsInteger(tree, namespaces, SD_XML_NAMESPACE, SD_XML_SECTOR_SIZE); - if (sector_size) { - CFDictionarySetValue(dict, SD_XML_SECTOR_SIZE, sector_size); - CFRelease(sector_size); - } - - CFDataRef digest = copyChildWithNameAsData(tree, namespaces, SD_XML_NAMESPACE, SD_XML_DIGEST); - if (digest) { - CFDictionarySetValue(dict, SD_XML_DIGEST, digest); - CFRelease(digest); - } - - CFDataRef digests = copyChildWithNameAsData(tree, namespaces, SD_XML_NAMESPACE, SD_XML_DIGESTS); - if (digests) { - CFDictionarySetValue(dict, SD_XML_DIGESTS, digests); - CFRelease(digests); - } - - CFDictionarySetValue(verifications, algorithm, dict); - CFRelease(dict); - } - } - } - } - } -#if LOCAL_DEBUG - cfprintf(stderr, "%sELEM:\t%@\t[%@]\n", state->prefix, name, ns); -#endif - } - if (ns) CFRelease(ns); - if (name) CFRelease(name); - } else if (type == kCFXMLNodeTypeWhitespace) { - // do nothing - } else { -#if LOCAL_DEBUG - CFStringRef str = CFXMLNodeGetString(node); - cfprintf(stderr, "%s% 4d:\t%@\n", state->prefix, type, str); -#endif - } - - // only recurse further if we have been specifically instructed to - // do so. - if (descend) { - struct parseState local; - memcpy(&local, state, sizeof(struct parseState)); - local.namespaces = namespaces; -#if LOCAL_DEBUG - asprintf(&local.prefix, "%s ", state->prefix); -#endif - CFTreeApplyFunctionToChildren(tree, _parseXMLNode, &local); -#if LOCAL_DEBUG - free(local.prefix); -#endif - } - if (namespaces) CFRelease(namespaces); -} - -CFPropertyListRef _SecureDownloadParseTicketXML(CFDataRef xmlData) { - if (!xmlData) return NULL; - CFURLRef url = NULL; - - CFXMLTreeRef tree = CFXMLTreeCreateFromData(NULL, xmlData, url, kCFXMLParserNoOptions, kCFXMLNodeCurrentVersion); - if (!tree) return NULL; - - struct parseState state; - memset(&state, 0, sizeof(state)); -#if LOCAL_DEBUG - state.prefix = ""; -#endif - state.plists = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (state.plists) { - CFTreeApplyFunctionToChildren(tree, _parseXMLNode, &state); - } - CFRelease(tree); - - CFPropertyListRef result = NULL; - // For now, only return the first resource encountered - if (state.plists && CFArrayGetCount(state.plists) > 0) { - result = CFArrayGetValueAtIndex(state.plists, 0); - CFRetain(result); - } - if (state.plists) CFRelease(state.plists); - return result; -} - -static void _appendCString(CFMutableDataRef data, const char* cstring) { - CFDataAppendBytes(data, (UInt8*)cstring, strlen(cstring)); -} - -static void _appendCFString(CFMutableDataRef data, CFStringRef string) { - CFDataRef utf8 = CFStringCreateExternalRepresentation(NULL, string, kCFStringEncodingUTF8, '?'); - if (utf8) { - CFDataAppendBytes(data, CFDataGetBytePtr(utf8), CFDataGetLength(utf8)); - CFRelease(utf8); - } -} - -static void _appendCFNumber(CFMutableDataRef data, CFNumberRef number) { - CFStringRef str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), number); - if (str) { - _appendCFString(data, str); - CFRelease(str); - } -} - -static void _appendCFURL(CFMutableDataRef data, CFURLRef url) { - CFURLRef abs = CFURLCopyAbsoluteURL(url); - if (abs) { - CFStringRef str = CFURLGetString(abs); - if (str) { - _appendCFString(data, str); - } - CFRelease(abs); - } -} - -// appends data in base64 encoded form -static void _appendCFData(CFMutableDataRef data, CFDataRef moreData) { - CFStringRef str = encodeBase64String(CFDataGetBytePtr(moreData), CFDataGetLength(moreData), 0); - if (str) { - _appendCFString(data, str); - CFRelease(str); - } -} - -// appends a date in W3C DateTime format -static void _appendCFDate(CFMutableDataRef data, CFDateRef date) { - CFLocaleRef locale = CFLocaleCreate(NULL, CFSTR("en_US")); - if (locale) { - CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); - if (formatter) { - CFDateFormatterSetFormat(formatter, CFSTR("yyyy-MM-dd'T'HH:mm:ss.S'Z'")); - CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0); - if (tz) { - CFDateFormatterSetProperty(formatter, kCFDateFormatterTimeZone, tz); - CFStringRef str = CFDateFormatterCreateStringWithDate(NULL, formatter, date); - if (str) { - _appendCFString(data, str); - CFRelease(str); - } - CFRelease(tz); - } - CFRelease(formatter); - } - CFRelease(locale); - } -} - -static CFArrayRef dictionaryGetSortedKeys(CFDictionaryRef dictionary) { - CFIndex count = CFDictionaryGetCount(dictionary); - - const void** keys = malloc(sizeof(CFStringRef) * count); - CFDictionaryGetKeysAndValues(dictionary, keys, NULL); - CFArrayRef keysArray = CFArrayCreate(NULL, keys, count, &kCFTypeArrayCallBacks); - CFMutableArrayRef sortedKeys = CFArrayCreateMutableCopy(NULL, count, keysArray); - CFRelease(keysArray); - free(keys); - - CFArraySortValues(sortedKeys, CFRangeMake(0, count), (CFComparatorFunction)CFStringCompare, 0); - return sortedKeys; -} - -CFDataRef _SecureDownloadCreateTicketXML(CFPropertyListRef plist) { - CFMutableDataRef data = CFDataCreateMutable(NULL, 0); - if (!data) return NULL; - - _appendCString(data, "\n"); - _appendCString(data, "\n"); - _appendCString(data, " \n"); - - CFStringRef name = CFDictionaryGetValue(plist, SD_XML_NAME); - if (name) { - _appendCString(data, "\t"); - _appendCFString(data, name); - _appendCString(data, "\n"); - } - - CFNumberRef num = CFDictionaryGetValue(plist, SD_XML_SIZE); - if (num) { - _appendCString(data, "\t"); - _appendCFNumber(data, num); - _appendCString(data, "\n"); - } - - CFDateRef created = CFDictionaryGetValue(plist, SD_XML_CREATED); - if (created) { - _appendCString(data, "\t"); - _appendCFDate(data, created); - _appendCString(data, "\n"); - } - - _appendCString(data, "\t\n"); - CFArrayRef urls = CFDictionaryGetValue(plist, SD_XML_URL); - if (urls) { - CFIndex i, count = CFArrayGetCount(urls); - for (i = 0; i < count; ++i) { - _appendCString(data, "\t\t"); - _appendCFURL(data, CFArrayGetValueAtIndex(urls, i)); - _appendCString(data, "\n"); - } - } - _appendCString(data, "\t\n"); - - CFDictionaryRef verifications = CFDictionaryGetValue(plist, SD_XML_VERIFICATIONS); - if (verifications) { - _appendCString(data, "\t\n"); - CFArrayRef algorithms = dictionaryGetSortedKeys(verifications); - if (algorithms) { - CFIndex i, count = CFArrayGetCount(algorithms); - for (i = 0; i < count; ++i) { - CFStringRef algorithm = CFArrayGetValueAtIndex(algorithms, i); - if (algorithm) { - _appendCString(data, "\t\t\n"); - CFDictionaryRef dict = CFDictionaryGetValue(verifications, algorithm); - if (dict) { - CFDataRef digest = CFDictionaryGetValue(dict, SD_XML_DIGEST); - if (digest) { - _appendCString(data, "\t\t\t"); - _appendCFData(data, digest); - _appendCString(data, "\n"); - } - - CFNumberRef sector_size = CFDictionaryGetValue(dict, SD_XML_SECTOR_SIZE); - if (sector_size) { - _appendCString(data, "\t\t\t"); - _appendCFNumber(data, sector_size); - _appendCString(data, "\n"); - } - - CFDataRef digests = CFDictionaryGetValue(dict, SD_XML_DIGESTS); - if (digest) { - _appendCString(data, "\t\t\t"); - _appendCFData(data, digests); - _appendCString(data, "\n"); - } - } - _appendCString(data, "\t\t\n"); - } - } - CFRelease(algorithms); - } - _appendCString(data, "\t\n"); - } - - _appendCString(data, " \n"); - _appendCString(data, "\n"); - - return data; -} - -#if LOCAL_DEBUG -#include -int main(int argc, char* argv[]) { - - CFDataRef data = read_data("/Users/kevin/Desktop/SecureDownloadXML/SecureDownload.xml"); - if (data) { - CFPropertyListRef plist = _SecureDownloadParseTicketXML(data); - CFShow(plist); - if (plist) { - CFDataRef output = _SecureDownloadCreateTicketXML(plist); - if (output) { - write(STDOUT_FILENO, CFDataGetBytePtr(output), CFDataGetLength(output)); - CFRelease(output); - } - CFRelease(plist); - } - CFRelease(data); - } - - // help look for leaks - cfprintf(stderr, "pid = %d\n", getpid()); - sleep(1000); -} -#endif