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; }
// 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_plist(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { if (NULL == der) return NULL; if (ccder_decode_tag == NULL) { printf("ccder functions missing, check /usr/lib/system/libcommonCrypto.dylib\n"); return NULL; } ccder_tag tag; if (NULL == ccder_decode_tag(&tag, der, der_end)) return NULL; switch (tag) { case CCDER_NULL: return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end); case CCDER_BOOLEAN: return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end); case CCDER_OCTET_STRING: return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end); case CCDER_GENERALIZED_TIME: return der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end); case CCDER_CONSTRUCTED_SEQUENCE: return der_decode_array(allocator, mutability, (CFArrayRef*)pl, error, der, der_end); case CCDER_UTF8_STRING: return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end); case CCDER_INTEGER: return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end); case CCDER_CONSTRUCTED_SET: return der_decode_dictionary(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end); default: SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error); return NULL; } }