// Der encoding/decoding const uint8_t* der_decode_RecoveryKeyBag(CFAllocatorRef allocator, SOSRecoveryKeyBagRef* RecoveryKeyBag, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { if (der == NULL) return der; const uint8_t *result = NULL; SOSRecoveryKeyBagRef rb = CFTypeAllocate(SOSRecoveryKeyBag, struct __OpaqueSOSRecoveryKeyBag, allocator); require_quiet(SecAllocationError(rb, error, CFSTR("Recovery bag allocation failed")), fail); const uint8_t *sequence_end = NULL; der = ccder_decode_sequence_tl(&sequence_end, der, der_end); require_quiet(sequence_end == der_end, fail); der = der_decode_string(kCFAllocatorDefault, kCFPropertyListImmutable, &rb->accountDSID, error, der, sequence_end); rb->generation = SOSGenCountCreateFromDER(kCFAllocatorDefault, error, &der, sequence_end); der = ccder_decode_uint64(&rb->rkbVersion, der, sequence_end); der = der_decode_data(allocator, kCFPropertyListImmutable, &rb->recoveryKeyBag, error, der, sequence_end); require_quiet(SecRequirementError(der == der_end, error, CFSTR("Extra space in sequence")), fail); if (RecoveryKeyBag) CFTransferRetained(*RecoveryKeyBag, rb); result = der; fail: CFReleaseNull(rb); return result; }
const uint8_t* der_decode_array(CFAllocatorRef allocator, CFOptionFlags mutability, CFArrayRef* array, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { if (NULL == der) return NULL; CFMutableArrayRef result = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); const uint8_t *elements_end; const uint8_t *current_element = ccder_decode_sequence_tl(&elements_end, der, der_end); while (current_element != NULL && current_element < elements_end) { CFPropertyListRef element = NULL; current_element = der_decode_plist(allocator, mutability, &element, error, current_element, elements_end); if (current_element) { CFArrayAppendValue(result, element); CFReleaseNull(element); } } if (current_element) { *array = result; result = NULL; } CFReleaseNull(result); return current_element; }
SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) { SOSCoderRef p = calloc(1, sizeof(struct __OpaqueSOSCoder)); const uint8_t *der = CFDataGetBytePtr(exportedData); const uint8_t *der_end = der + CFDataGetLength(exportedData); CFDataRef otr_data = NULL; ccder_tag tag; require(ccder_decode_tag(&tag, der, der_end),fail); switch (tag) { case CCDER_OCTET_STRING: // TODO: this code is safe to delete? { der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, der_end); p->waitingForDataPacket = false; } break; case CCDER_CONSTRUCTED_SEQUENCE: { const uint8_t *sequence_end = NULL; der = ccder_decode_sequence_tl(&sequence_end, der, der_end); require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error)); der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, sequence_end); der = der_decode_bool(&p->waitingForDataPacket, der, sequence_end); if (der != sequence_end) { // optionally a pending response der = der_decode_data(kCFAllocatorDefault, 0, &p->pendingResponse, error, der, sequence_end); } } break; default: SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Unsupported SOS Coder DER"), NULL, error); goto fail; } require(der, fail); p->sessRef = SecOTRSessionCreateFromData(NULL, otr_data); require(p->sessRef, fail); CFReleaseSafe(otr_data); return p; fail: SOSCoderDispose(p); CFReleaseSafe(otr_data); return NULL; }
static const uint8_t* der_decode_cloud_parameters(CFAllocatorRef allocator, CFIndex algorithmID, SecKeyRef* publicKey, CFDataRef *parameters, CFErrorRef* error, const uint8_t* der, const uint8_t* der_end) { const uint8_t *sequence_end; der = ccder_decode_sequence_tl(&sequence_end, der, der_end); der = der_decode_public_bytes(allocator, algorithmID, publicKey, error, der, sequence_end); der = der_decode_data_or_null(allocator, parameters, error, der, sequence_end); return der; }