static uint8_t *ccder_encode_nanoseconds(CFAbsoluteTime at, const uint8_t *der, uint8_t *der_end) { int dotoff; int sign; char *end; char *str = __dtoa(at, 0, 0, &dotoff, &sign, &end); char *begin = str + (dotoff < 0 ? 0 : dotoff); // Compute 1.0000000 - fraction in ascii space if (at < 0.0 && begin < end) { char *p = end - 1; // Borrow for last digit *p = ('9' + 1) - (*p - '0'); while (p-- > begin) { // Every other digit is a 9 since we borrowed from the last one *p = '9' - (*p - '0'); } } ptrdiff_t len = end - str; if (len > dotoff) { if (dotoff < 0) { assert(-1.0 < at && at < 1.0); der_end = ccder_encode_body(len, (const uint8_t *)str, der, der_end); der_end = ccder_encode_body_nocopy(-dotoff, der, der_end); if (der_end) memset(der_end, at < 0.0 ? '9' : '0', -dotoff); } else { der_end = ccder_encode_body(len - dotoff, (const uint8_t *)(str + dotoff), der, der_end); } der_end = ccder_encode_byte('.', der, der_end); } __freedtoa(str); return der_end; }
uint8_t* ccder_encode_bool(bool value, const uint8_t *der, uint8_t *der_end) { uint8_t value_byte = value; return ccder_encode_tl(CCDER_BOOLEAN, 1, der, ccder_encode_body(1, &value_byte, der, der_end)); }
uint8_t* der_encode_string(CFStringRef string, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { // Obey the NULL allowed rules. if (!der_end) return NULL; const CFIndex str_length = CFStringGetLength(string); ptrdiff_t der_space = der_end - der; CFIndex bytes_used = 0; uint8_t *buffer = der_end - der_space; CFIndex converted = CFStringGetBytes(string, CFRangeMake(0, str_length), kCFStringEncodingUTF8, 0, false, buffer, der_space, &bytes_used); if (converted != str_length){ SecCFDERCreateError(kSecDERErrorUnsupportedCFObject, CFSTR("String extraction failed"), NULL, error); return NULL; } return ccder_encode_tl(CCDER_UTF8_STRING, bytes_used, der, ccder_encode_body(bytes_used, buffer, der, der_end)); }
size_t der_sizeof_dictionary(CFDictionaryRef dict, CFErrorRef *error) { struct size_context context = { .success = true, .size = 0, .error = error }; CFDictionaryApplyFunction(dict, add_key_value_size, &context); if (!context.success) return 0; return ccder_sizeof(CCDER_CONSTRUCTED_SET, context.size); } static uint8_t* der_encode_key_value(CFPropertyListRef key, CFPropertyListRef value, CFErrorRef *error, const uint8_t* der, uint8_t *der_end) { return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, der_encode_plist(key, error, der, der_encode_plist(value, error, der, der_end))); } struct encode_context { bool success; CFErrorRef * error; CFMutableArrayRef list; CFAllocatorRef allocator; }; static void add_sequence_to_array(const void *key_void, const void *value_void, void *context_void) { struct encode_context *context = (struct encode_context *) context_void; if (context->success) { CFTypeRef key = (CFTypeRef) key_void; CFTypeRef value = (CFTypeRef) value_void; size_t der_size = der_sizeof_key_value(key, value, context->error); if (der_size == 0) { context-> success = false; } else { CFMutableDataRef encoded_kv = CFDataCreateMutable(context->allocator, der_size); CFDataSetLength(encoded_kv, der_size); uint8_t* const encode_begin = CFDataGetMutableBytePtr(encoded_kv); uint8_t* encode_end = encode_begin + der_size; encode_end = der_encode_key_value(key, value, context->error, encode_begin, encode_end); if (encode_end != NULL) { CFDataDeleteBytes(encoded_kv, CFRangeMake(0, (encode_end - encode_begin))); CFArrayAppendValue(context->list, encoded_kv); } else { context-> success = false; } CFReleaseNull(encoded_kv); } } } static CFComparisonResult cfdata_compare_contents(const void *val1, const void *val2, void *context __unused) { return CFDataCompare((CFDataRef) val1, (CFDataRef) val2); } uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { CFMutableArrayRef elements = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); struct encode_context context = { .success = true, .error = error, .list = elements }; CFDictionaryApplyFunction(dictionary, add_sequence_to_array, &context); if (!context.success) { CFReleaseNull(elements); return NULL; } CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements)); CFArraySortValues(elements, allOfThem, cfdata_compare_contents, NULL); uint8_t* original_der_end = der_end; for(CFIndex position = CFArrayGetCount(elements); position > 0;) { --position; CFDataRef data = CFArrayGetValueAtIndex(elements, position); der_end = ccder_encode_body(CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end); } CFReleaseNull(elements); return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET, original_der_end, der, der_end); }
static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, uint8_t *der_end) { return ccder_encode_tl(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length, der, ccder_encode_body(secasn_oid->Length, secasn_oid->Data, der, der_end)); }