KCDer.m   [plain text]

//
// KCDer.m
// Security
//
//

#import <Foundation/Foundation.h>

#include <KeychainCircle/KCDer.h>
#import <KeychainCircle/KCError.h>
#import <os/overflow.h>

// These should probably be shared with security, but we don't export our der'izing functions yet.

static const uint8_t* kcder_decode_data_internal(NSData** data, bool copy,
NSError**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);

uintptr_t payload_end_computed = 0;
if(os_add_overflow((uintptr_t)payload, payload_size, &payload_end_computed)) {
KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad payload size");
return NULL;
}
if (NULL == payload || payload_end_computed > (uintptr_t) der_end) {
KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Unknown data encoding");
return NULL;
}

*data = copy ? [NSData dataWithBytes: (void*)payload length: payload_size] :
[NSData dataWithBytesNoCopy: (void*)payload length:payload_size freeWhenDone:NO];

if (NULL == *data) {
KCJoiningErrorCreate(kAllocationFailure, error, @"Allocation failure!");
return NULL;
}

return payload + payload_size;
}

const uint8_t* kcder_decode_data_nocopy(NSData** data,
NSError**error,
const uint8_t* der, const uint8_t *der_end)
{
return kcder_decode_data_internal(data, NO, error, der, der_end);
}

const uint8_t* kcder_decode_data(NSData** data,
NSError**error,
const uint8_t* der, const uint8_t *der_end) {
return kcder_decode_data_internal(data, YES, error, der, der_end);
}

size_t kcder_sizeof_data(NSData* data, NSError** error) {
return ccder_sizeof_raw_octet_string(data.length);
}

uint8_t* kcder_encode_data_optional(NSData* _Nullable data, NSError**error,
const uint8_t *der, uint8_t *der_end)
{
if (data == nil) return der_end;

return kcder_encode_data(data, error, der, der_end);

}

uint8_t* kcder_encode_data(NSData* data, NSError**error,
const uint8_t *der, uint8_t *der_end)
{
return ccder_encode_tl(CCDER_OCTET_STRING, data.length, der,
ccder_encode_body(data.length, data.bytes, der, der_end));

}

const uint8_t* kcder_decode_string(NSString** string, NSError**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);

uintptr_t payload_end_computed = 0;
if(os_add_overflow((uintptr_t)payload, payload_size, &payload_end_computed)) {
KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad payload size");
return NULL;
}
if (NULL == payload || payload_end_computed > (uintptr_t) der_end) {
KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Unknown string encoding");
return NULL;
}

*string = [[NSString alloc] initWithBytes:payload length:payload_size encoding:NSUTF8StringEncoding];

if (nil == *string) {
KCJoiningErrorCreate(kAllocationFailure, error, @"Allocation failure!");
return NULL;
}

return payload + payload_size;
}

size_t kcder_sizeof_string(NSString* string, NSError** error)
{
return ccder_sizeof(CCDER_UTF8_STRING, [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
}

uint8_t* kcder_encode_string(NSString* string, NSError** error,
const uint8_t *der, uint8_t *der_end)
{
// Obey the NULL allowed rules.
if (!der_end)
return NULL;

NSUInteger max = (der_end - der);
void *buffer = der_end - max;
NSUInteger used = 0;
if (![string getBytes:buffer
maxLength:max
usedLength:&used
encoding:NSUTF8StringEncoding
options:0
range:NSMakeRange(0, string.length)
remainingRange:nil]) {
KCJoiningErrorCreate(kDERStringEncodingFailed, error, @"String encoding failed");
return NULL;
}

return ccder_encode_tl(CCDER_UTF8_STRING, used, der,
ccder_encode_body(used, buffer, der, der_end));

}

uint8_t *kcder_encode_raw_octet_space(size_t s_size, uint8_t **location,
const uint8_t *der, uint8_t *der_end) {
der_end = ccder_encode_body_nocopy(s_size, der, der_end);
if (der_end && location)
*location = der_end;

return ccder_encode_tl(CCDER_OCTET_STRING, s_size, der, der_end);
}