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;
}
Ejemplo n.º 2
0
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;
}
static const uint8_t* der_decode_commontime_body(CFAbsoluteTime *at, CFErrorRef *error, int year,
                                                 const uint8_t* der, const uint8_t *der_end)
{
	int month = der_decode_decimal_pair(&der, der_end, error);
	int day = der_decode_decimal_pair(&der, der_end, error);
	int hour = der_decode_decimal_pair(&der, der_end, error);
	int minute = der_decode_decimal_pair(&der, der_end, error);
    int second = der_decode_decimal_pair(&der, der_end, error);
    double fraction;
    der = der_decode_decimal_fraction(&fraction, error, der, der_end);

	CFTimeInterval timeZoneOffset = der_decode_timezone_offset(&der, der_end, error);

#if 0
    secdebug("dateparse",
             "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
             length, bytes, g.year, g.month,
             g.day, g.hour, g.minute, g.second,
             timeZoneOffset / 60);
#endif

    if (der) {
        if (der != der_end) {
            SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                                CFSTR("trailing garbage at end of datetime"), 0, error);
            return NULL;
        }

        *at = SecGregorianDateGetAbsoluteTime(year, month, day, hour, minute, second, timeZoneOffset, error) + fraction;
        if (*at == NULL_TIME)
            return NULL;
    }

    return der;
}
static const CFTimeInterval der_decode_timezone_offset(const uint8_t **der_p,
                                                       const uint8_t *der_end,
                                                       CFErrorRef *error) {
    CFTimeInterval timeZoneOffset;
    int ch = der_get_char(der_p, der_end, error);
    if (ch == 'Z') {
        /* Zulu time. */
        timeZoneOffset = 0.0;
    } else {
		/* ZONE INDICATOR */
        int multiplier;
        if (ch == '-')
            multiplier = -60;
        else if (ch == '+')
            multiplier = +60;
        else {
            SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                                CFSTR("Invalid datetime character"), 0, error);
            return NULL_TIME;
        }
        
        timeZoneOffset = multiplier *
            (der_decode_decimal_pair(der_p, der_end, error)
             * 60 + der_decode_decimal_pair(der_p, der_end, error));
    }
    return timeZoneOffset;
}
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;
}
static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *month, int *day, int *hour, int *minute, int *second, CFErrorRef *error) {
    // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires filesystem access to timezone files when we are only doing zulu time anyway
    if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), at, "yMdHms", year, month, day, hour, minute, second)) {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Failed to encode date."), 0, error);
        return false;
    }
    return true;
}
const uint8_t* der_decode_number(CFAllocatorRef allocator, CFOptionFlags mutability,
                                 CFNumberRef* number, CFErrorRef *error,
                                 const uint8_t* der, const uint8_t *der_end)
{
    if (NULL == der)
        return NULL;

    size_t payload_size = 0;
    const uint8_t *payload = ccder_decode_tl(CCDER_INTEGER, &payload_size, der, der_end);

    if (NULL == payload || (der_end - payload) < payload_size) {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown number encoding"), NULL, error);
        return NULL;
    }
    if (payload_size > sizeof(long long)) {
        SecCFDERCreateError(kSecDERErrorUnsupportedNumberType, CFSTR("Number too large"), NULL, error);
        return NULL;

    }

    long long value = 0;

    if (payload_size > 0) {
        if ((*payload & 0x80) == 0x80)
            value = -1; // Negative integers fill with 1s so we end up negative.
        
        const uint8_t* const payload_end = payload + payload_size;
        
        for (const uint8_t *payload_byte = payload;
             payload_byte < payload_end;
             ++payload_byte) {
            value <<= 8;
            value |= *payload_byte;
        }
    }

    *number = CFNumberCreate(allocator, kCFNumberLongLongType, &value);

    if (*number == NULL) {
        SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Number allocation failed"), NULL, error);
        return NULL;
    }
    
    return payload + payload_size;
}
static int der_decode_decimal(const uint8_t **der_p, const uint8_t *der_end,
                             CFErrorRef *error) {
    char ch = der_get_char(der_p, der_end, error);
    if (ch < '0' || ch > '9') {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                            CFSTR("Not a decimal digit"), 0, error);
        *der_p = NULL;
        return -1;
    }
    return ch - '0';
}
Ejemplo n.º 9
0
CFGregorianDate SecCFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeInterval timeZoneOffset, CFErrorRef *error) {
    CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(0, timeZoneOffset);
    if (!tz) {
        SecCFDERCreateError(-1000, CFSTR("timezone creation failed."), 0, error);
        CFGregorianDate g = {};
        return g;
    } else {
        CFGregorianDate g = CFAbsoluteTimeGetGregorianDate(at, tz);
        CFRelease(tz);
        return g;
    }
}
Ejemplo n.º 10
0
static const uint8_t *der_decode_decimal_fraction(double *fraction, CFErrorRef *error,
                                                  const uint8_t* der, const uint8_t *der_end) {
    int ch = der_peek_byte(der, der_end);
    if (ch == -1) {
        der = NULL;
    } else if (ch == '.') {
        uint64_t divisor = 1;
        uint64_t value = 0;
        int last = -1;
        while (++der < der_end) {
            last = ch;
            ch = *der;
            if (ch < '0' || ch > '9') {
                break;
            }
            if (divisor < UINT64_MAX / 10) {
                divisor *= 10;
                value *= 10;
                value += (ch - '0');
            }
        }
        if (der >= der_end)
            der = NULL;
        else if (last == '0') {
            SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                                CFSTR("fraction ends in 0"), 0, error);
            der = NULL;
        } else if (last == '.') {
            SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                                CFSTR("fraction without digits"), 0, error);
            der = NULL;
        } else {
            *fraction = (double)value / divisor;
        }
    } else {
        *fraction = 0.0;
    }

    return der;
}
Ejemplo n.º 11
0
const uint8_t* der_decode_string(CFAllocatorRef allocator, CFOptionFlags mutability,
                                 CFStringRef* string, CFErrorRef *error,
                                 const uint8_t* der, const uint8_t *der_end)
{
    if (NULL == der)
        return NULL;

    size_t payload_size = 0;
    const uint8_t *payload = ccder_decode_tl(CCDER_UTF8_STRING, &payload_size, der, der_end);

    if (NULL == payload || (ssize_t) (der_end - payload) < (ssize_t) payload_size){
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown string encoding"), NULL, error);
        return NULL;
    }

    *string = CFStringCreateWithBytes(allocator, payload, payload_size, kCFStringEncodingUTF8, false);

    if (NULL == *string) {
        SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("String allocation failed"), NULL, error);
        return NULL;
    }

    return payload + payload_size;
}
const uint8_t* der_decode_data(CFAllocatorRef allocator, CFOptionFlags mutability,
                               CFDataRef* data, CFErrorRef *error,
                               const uint8_t* der, const uint8_t *der_end)
{
    if (NULL == der)
        return NULL;

    size_t payload_size = 0;
    const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payload_size, der, der_end);

    if (NULL == payload || (der_end - payload) < payload_size) {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding"), NULL, error);
        return NULL;
    }

    *data = CFDataCreate(allocator, payload, payload_size);

    if (NULL == *data) {
        SecCFDERCreateError(kSecDERErrorUnderlyingError, CFSTR("Failed to create data"), NULL, error);
        return NULL;
    }

    return payload + payload_size;
}
Ejemplo n.º 13
0
const uint8_t* der_decode_universaltime_body(CFAbsoluteTime *at, CFErrorRef *error,
                                             const uint8_t* der, const uint8_t *der_end)
{
    SInt32 year = der_decode_decimal_pair(&der, der_end, error);
    if (year < 50) {
        /* 0  <= year <  50 : assume century 21 */
        year += 2000;
    } else if (year < 70) {
        /* 50 <= year <  70 : illegal per PKIX */
        SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                            CFSTR("Invalid universal time year between 50 and 70"), 0, error);
        der = NULL;
    } else {
        /* 70 <  year <= 99 : assume century 20 */
        year += 1900;
    }

    return der_decode_commontime_body(at, error, year, der, der_end);
}
const uint8_t* der_decode_boolean(CFAllocatorRef allocator, CFOptionFlags mutability,
                                  CFBooleanRef* boolean, CFErrorRef *error,
                                  const uint8_t* der, const uint8_t *der_end)
{
    if (NULL == der)
        return NULL;

    size_t payload_size = 0;
    const uint8_t *payload = ccder_decode_tl(CCDER_BOOLEAN, &payload_size, der, der_end);

    if (NULL == payload || (der_end - payload) < payload_size || payload_size != 1) {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown boolean encoding"), NULL, error);
        return NULL;
    }

    *boolean = *payload ? kCFBooleanTrue : kCFBooleanFalse;

    return payload + payload_size;
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
0
const uint8_t* der_decode_null(CFAllocatorRef allocator, CFOptionFlags mutability,
                                  CFNullRef* nul, CFErrorRef *error,
                                  const uint8_t* der, const uint8_t *der_end)
{
    if (NULL == der)
        return NULL;
	
    size_t payload_size = 0;
    const uint8_t *payload = ccder_decode_tl(CCDER_NULL, &payload_size, der, der_end);
	
	if (NULL == payload || payload_size != 0) {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown null encoding"), NULL, error);
        return NULL;
    }
	
    *nul = kCFNull;
	
    return payload + payload_size;
}
Ejemplo n.º 17
0
static int der_get_char(const uint8_t **der_p, const uint8_t *der_end,
                         CFErrorRef *error) {
    const uint8_t *der = *der_p;
    if (!der) {
        /* Don't create a new error in this case. */
        return -1;
    }

    if (der >= der_end) {
        SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                            CFSTR("Unexpected end of datetime"), 0, error);
        *der_p = NULL;
        return -1;
    }

    int ch = *der++;
    *der_p = der;
    return ch;
}
Ejemplo n.º 18
0
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));

}
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;
    }
}
Ejemplo n.º 20
0
CFAbsoluteTime SecCFGregorianDateGetAbsoluteTime(CFGregorianDate g, CFTimeInterval timeZoneOffset, CFErrorRef *error) {
    int day = g.day;
    int is_leap_year = g.year % 4 == 0 && (g.year % 100 != 0 || g.year % 400 == 0) ? 1 : 0;
    if (g.month < 1 || g.month > 12 || day < 1 || day > 31 || g.hour >= 24 || g.minute >= 60 || g.second >= 60.0
        || (g.month == 2 && day > mdays[g.month] - mdays[g.month - 1] + is_leap_year)
        || (g.month != 2 && day > mdays[g.month] - mdays[g.month - 1])) {
        /* Invalid date. */
        SecCFDERCreateError(-1000, CFSTR("Invalid date."), 0, error);
        return NULL_TIME;
    }

    int dy = g.year - 2001;
    if (dy < 0) {
        dy += 1;
        day -= 1;
    }

    int leap_days = dy / 4 - dy / 100 + dy / 400;
    day += ((g.year - 2001) * 365 + leap_days) + mdays[g.month - 1] - 1;
    if (g.month > 2)
        day += is_leap_year;

#if 0
    int64_t time = day;
    time *= 24;
    time += g.hour;
    time *= 60;
    time += g.minute;
    time *= 60;
    time += lrint(g.second);
    time -= lrint(timeZoneOffset);
    return time;
#else
    CFAbsoluteTime absTime = (CFAbsoluteTime)((day * 24 + g.hour) * 60 + g.minute) * 60 + g.second;
	return absTime - timeZoneOffset;
#endif
}
Ejemplo n.º 21
0
static CFAbsoluteTime SecGregorianDateGetAbsoluteTime(int year, int month, int day, int hour, int minute, int second, CFTimeInterval timeZoneOffset, CFErrorRef *error) {
    int is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0;
    if (month < 1 || month > 12 || day < 1 || day > 31 || hour >= 24 || minute >= 60 || second >= 60.0
        || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year)
        || (month != 2 && day > mdays[month] - mdays[month - 1])) {
        /* Invalid date. */
        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Invalid date."), 0, error);
        return NULL_TIME;
    }

    int dy = year - 2001;
    if (dy < 0) {
        dy += 1;
        day -= 1;
    }

    int leap_days = dy / 4 - dy / 100 + dy / 400;
    day += ((year - 2001) * 365 + leap_days) + mdays[month - 1] - 1;
    if (month > 2)
        day += is_leap_year;

    CFAbsoluteTime absTime = (CFAbsoluteTime)((day * 24 + hour) * 60 + minute) * 60 + second;
	return absTime - timeZoneOffset;
}