static const uint8_t *get_oid(const uint8_t *der, const uint8_t *der_end) { ccoid_t oid; if((der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end)) == NULL) return NULL; if((der = ccder_decode_oid(&oid, der, der_end)) == NULL) return NULL; if((der = ccder_decode_constructed_tl(CCASN1_NULL, &der_end, der, der_end)) == NULL) return NULL; return der; }
static const uint8_t* der_decode_key_value(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { const uint8_t *payload_end = 0; const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end); if (NULL == payload) { SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error); return NULL; } CFTypeRef keyObject = NULL; CFTypeRef valueObject = NULL; payload = der_decode_plist(allocator, mutability, &keyObject, error, payload, payload_end); payload = der_decode_plist(allocator, mutability, &valueObject, error, payload, payload_end); if (payload != NULL) { *key = keyObject; *value = valueObject; } else { CFReleaseNull(keyObject); CFReleaseNull(valueObject); } return payload; }
// Key is expected to be in PKCS #1 format cc_size ccder_decode_rsa_pub_n(const uint8_t *der, const uint8_t *der_end) { cc_size n = ccn_nof(8192); cc_unit m[n]; if((der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end)) == NULL) return 0; if((der = ccder_decode_uint(n, m, der, der_end)) == NULL) return 0; return ccn_nof(ccn_bitlen(n, m)); }
cc_size ccder_decode_rsa_priv_n(const uint8_t *der, const uint8_t *der_end) { cc_unit version_0[ccn_nof(1)] = {0x00}; cc_size n = ccn_nof(8192); cc_unit m[n]; if((der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end)) == NULL) return 0; if((der = ccder_decode_uint(1, version_0, der, der_end)) == NULL) return 0; if(version_0[0] != 0) return 0; if((der = ccder_decode_uint(n, m, der, der_end)) == NULL) return 0; return ccn_nof(ccn_bitlen(n, m)); }
const uint8_t* der_decode_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability, CFDictionaryRef* dictionary, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { if (NULL == der) return NULL; const uint8_t *payload_end = 0; const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end); if (NULL == payload) { SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error); return NULL; } CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (NULL == dict) { SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error); payload = NULL; goto exit; } while (payload != NULL && payload < payload_end) { CFTypeRef key = NULL; CFTypeRef value = NULL; payload = der_decode_key_value(allocator, mutability, &key, &value, error, payload, payload_end); if (payload) { CFDictionaryAddValue(dict, key, value); } CFReleaseNull(key); CFReleaseNull(value); } exit: if (payload == payload_end) { *dictionary = dict; dict = NULL; } CFReleaseNull(dict); return payload; }
const uint8_t* der_decode_date(CFAllocatorRef allocator, CFOptionFlags mutability, CFDateRef* date, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { if (NULL == der) return NULL; der = ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME, &der_end, der, der_end); CFAbsoluteTime at = 0; der = der_decode_generalizedtime_body(&at, error, der, der_end); if (der) { *date = CFDateCreate(allocator, at); if (NULL == *date) { SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create date"), NULL, error); return NULL; } } return der; }
static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen, const uint8_t **salt, unsigned long *iterationCount, unsigned long *keyLength, const uint8_t *der, const uint8_t *der_end) { const uint8_t * body_end = NULL; der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &body_end, der, der_end); if (body_end != der_end) der = NULL; size_t salt_size = 0; const uint8_t *salt_bytes = NULL; der = ccder_decode_tl(CCDER_OCTET_STRING, &salt_size, der, body_end); salt_bytes = der; der += salt_size; uint64_t iteration_count = 0; uint64_t key_len = 0; der = ccder_decode_uint64(&iteration_count, der, body_end); if (iteration_count > UINT32_MAX) der = NULL; der = ccder_decode_uint64(&key_len, der, body_end); if (key_len > UINT32_MAX) der = NULL; der = der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, body_end); if (der) { if (salt) *salt = salt_bytes; if (saltLen) *saltLen = salt_size; if (iterationCount) *iterationCount = (unsigned long)iteration_count; if (keyLength) *keyLength = (unsigned long) key_len; } return der; }
SOSAccountRef SOSAccountCreateFromDER_V1(CFAllocatorRef allocator, SOSDataSourceFactoryRef factory, CFErrorRef* error, const uint8_t** der_p, const uint8_t *der_end) { SOSAccountRef account = NULL; const uint8_t *sequence_end; *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end); { CFDictionaryRef decoded_gestalt = NULL; *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, *der_p, der_end); if (*der_p == 0) return NULL; account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory); CFReleaseNull(decoded_gestalt); } CFArrayRef array = NULL; *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, sequence_end); *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, sequence_end); *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, sequence_end); *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, sequence_end); *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &account->retired_peers, error, *der_p, sequence_end); if (*der_p != sequence_end) *der_p = NULL; __block bool success = true; require_quiet(array && *der_p, fail); CFArrayForEach(array, ^(const void *value) { if (success) { if (isString(value)) { CFDictionaryAddValue(account->circles, value, kCFNull); } else { CFDataRef circleData = NULL; CFDataRef fullPeerInfoData = NULL; if (isData(value)) { circleData = (CFDataRef) value; } else if (isArray(value)) { CFArrayRef pair = (CFArrayRef) value; CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0); CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1); if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) { circleData = (CFDataRef) circleObject; fullPeerInfoData = (CFDataRef) fullPeerInfoObject; } } if (circleData) { SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error); require_action_quiet(circle, fail, success = false); CFStringRef circleName = SOSCircleGetName(circle); CFDictionaryAddValue(account->circles, circleName, circle); if (fullPeerInfoData) { SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error); require_action_quiet(full_peer, fail, success = false); CFDictionaryAddValue(account->circle_identities, circleName, full_peer); CFReleaseNull(full_peer); } fail: CFReleaseNull(circle); } } } });
cc_size ccder_decode_rsa_pub_x509_n(const uint8_t *der, const uint8_t *der_end) { if((der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end)) == NULL) return 0; if((der = get_oid(der, der_end)) == NULL) return 0; return get_pub_n(der, der_end); }
static cc_size get_pub_n(const uint8_t *der, const uint8_t *der_end) { if((der = ccder_decode_constructed_tl(CCDER_BIT_STRING, &der_end, der, der_end)) == NULL) return 0; if(*der == 0) der++; // Skip the null byte return ccder_decode_rsa_pub_n(der, der_end); }