Пример #1
0
CFDictionaryRef APCreateDictionaryForLicenseData(CFDataRef data)
{
    if (!rsaKey->n || !rsaKey->e)
        return NULL;
    
    // Make the property list from the data
    CFStringRef errorString = NULL;
    CFPropertyListRef propertyList;
    propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, &errorString);
    if (errorString || CFDictionaryGetTypeID() != CFGetTypeID(propertyList) || !CFPropertyListIsValid(propertyList, kCFPropertyListXMLFormat_v1_0)) {
        if (propertyList)
            CFRelease(propertyList);
        return NULL;
    }
    
    // Load the signature
    CFMutableDictionaryRef licenseDictionary = (CFMutableDictionaryRef)propertyList;
    if (!CFDictionaryContainsKey(licenseDictionary, CFSTR("Signature"))) {
        CFRelease(licenseDictionary);
        return NULL;
    }
    
    CFDataRef sigData = CFDictionaryGetValue(licenseDictionary, CFSTR("Signature"));
	CFIndex sigDataLength = CFDataGetLength(sigData);
	UInt8 sigBytes[sigDataLength];
    CFDataGetBytes(sigData, CFRangeMake(0, sigDataLength), sigBytes);
    CFDictionaryRemoveValue(licenseDictionary, CFSTR("Signature"));
    
    // Decrypt the signature
	int checkDigestMaxSize = RSA_size(rsaKey)-11;
    unsigned char checkDigest[checkDigestMaxSize];
    if (RSA_public_decrypt((int) sigDataLength, sigBytes, checkDigest, rsaKey, RSA_PKCS1_PADDING) != SHA_DIGEST_LENGTH) {
        CFRelease(licenseDictionary);
        return NULL;
    }
    
    // Get the license hash
    CFMutableStringRef hashCheck = CFStringCreateMutable(kCFAllocatorDefault,0);
    int hashIndex;
    for (hashIndex = 0; hashIndex < SHA_DIGEST_LENGTH; hashIndex++)
        CFStringAppendFormat(hashCheck, nil, CFSTR("%02x"), checkDigest[hashIndex]);
    APSetHash(hashCheck);
    CFRelease(hashCheck);
    
    if (blacklist && (CFArrayContainsValue(blacklist, CFRangeMake(0, CFArrayGetCount(blacklist)), hash) == true))
        return NULL;
    
    // Get the number of elements
    CFIndex count = CFDictionaryGetCount(licenseDictionary);
    // Load the keys and build up the key array
    CFMutableArrayRef keyArray = CFArrayCreateMutable(kCFAllocatorDefault, count, NULL);
    CFStringRef keys[count];
    CFDictionaryGetKeysAndValues(licenseDictionary, (const void**)&keys, NULL);
    int i;
    for (i = 0; i < count; i++)
        CFArrayAppendValue(keyArray, keys[i]);
    
    // Sort the array
    int context = kCFCompareCaseInsensitive;
    CFArraySortValues(keyArray, CFRangeMake(0, count), (CFComparatorFunction)CFStringCompare, &context);
    
    // Setup up the hash context
    SHA_CTX ctx;
    SHA1_Init(&ctx);
    // Convert into UTF8 strings
    for (i = 0; i < count; i++)
    {
        char *valueBytes;
        CFIndex valueLengthAsUTF8;
        CFStringRef key = CFArrayGetValueAtIndex(keyArray, i);
        CFStringRef value = CFDictionaryGetValue(licenseDictionary, key);
        
        // Account for the null terminator
        valueLengthAsUTF8 = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8) + 1;
        valueBytes = (char *)malloc(valueLengthAsUTF8);
        CFStringGetCString(value, valueBytes, valueLengthAsUTF8, kCFStringEncodingUTF8);
        SHA1_Update(&ctx, valueBytes, strlen(valueBytes));
        free(valueBytes);
    }
    unsigned char digest[SHA_DIGEST_LENGTH];
    SHA1_Final(digest, &ctx);
    
    if (keyArray != NULL)
        CFRelease(keyArray);
    
    // Check if the signature is a match    
    for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
        if (checkDigest[i] ^ digest[i]) {
            CFRelease(licenseDictionary);
            return NULL;
        }
    }
    
    // If it's a match, we return the dictionary; otherwise, we never reach this
    return licenseDictionary;
}
Пример #2
0
CFDictionaryRef APCreateDictionaryForLicenseData(CFDataRef data)
{
    __block CFPropertyListRef propertyList = NULL;
    __block CFDataRef hashData = NULL;
    __block CFErrorRef error = NULL;
    __block SecTransformRef verifyFunction = NULL;
    __block CFBooleanRef valid = NULL;
    
    void(^cleanup)(void) = ^(void) {
        if (propertyList != NULL) {
            CFRelease(propertyList);
            propertyList = NULL;
        }
        if (hashData != NULL) {
            CFRelease(hashData);
            hashData = NULL;
        }
        if (error != NULL) {
            CFShow(error);
            CFRelease(error);
            error = NULL;
        }
        if (verifyFunction != NULL) {
            CFRelease(verifyFunction);
            verifyFunction = NULL;
        }
        if (valid != NULL) {
            CFRelease(valid);
            valid = NULL;
        }
    };
    
    if (!publicKeyRef) {
        CFShow(CFSTR("Public key is invalid"));
        return NULL;
    }
    
    
    // Make the property list from the data
    CFStringRef errorString = NULL;
    propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, &errorString);
    if (errorString || CFDictionaryGetTypeID() != CFGetTypeID(propertyList) || !CFPropertyListIsValid(propertyList, kCFPropertyListXMLFormat_v1_0)) {
        if (propertyList)
            CFRelease(propertyList);
        return NULL;
    }
    CFMutableDictionaryRef licenseDictionary = (CFMutableDictionaryRef)propertyList;
    
    
    CFDataRef signature = CFDictionaryGetValue(licenseDictionary, CFSTR("Signature"));
    if (!signature) {
        CFShow(CFSTR("No signature"));
        cleanup();
        return NULL;
    }
    
    
    hashData = APCreateHashFromDictionary(licenseDictionary);
    CFStringRef hashCheck = APCopyHexStringFromData(hashData);
    APSetHash(hashCheck);
    CFRelease(hashCheck);
    
    
    // Check the hash against license blacklist
    if (blacklist && CFArrayContainsValue(blacklist, CFRangeMake(0, CFArrayGetCount(blacklist)), hash)) {
        cleanup();
        return NULL;
    }
    
    
    // Verify the signed hash using the public key, passing the raw hash data as the input
    verifyFunction = SecVerifyTransformCreate(publicKeyRef, signature, &error);
    if (error) {
        cleanup();
        return NULL;
    }
    
    SecTransformSetAttribute(verifyFunction,
                             kSecTransformInputAttributeName,
                             hashData,
                             &error);
    if (error) {
        cleanup();
        return NULL;
    }
    
    SecTransformSetAttribute(verifyFunction,
                             kSecInputIsAttributeName,
                             kSecInputIsRaw,
                             &error);
    if (error) {
        cleanup();
        return NULL;
    }
    
    valid = SecTransformExecute(verifyFunction, &error);
    if (error) {
        cleanup();
        return NULL;
    }
    
    if (valid != kCFBooleanTrue) {
        cleanup();
        return NULL;
    }
    
    CFDictionaryRef resultDict = CFDictionaryCreateCopy(kCFAllocatorDefault, licenseDictionary);
    cleanup();
    return resultDict;
}