1// 2// der_number.c 3// utilities 4// 5// Created by Mitch Adler on 6/19/12. 6// Copyright (c) 2012 Apple Inc. All rights reserved. 7// 8 9 10#include <stdio.h> 11 12#include "utilities/SecCFRelease.h" 13#include "utilities/der_plist.h" 14#include "utilities/der_plist_internal.h" 15 16#include <corecrypto/ccder.h> 17#include <CoreFoundation/CoreFoundation.h> 18 19 20const uint8_t* der_decode_number(CFAllocatorRef allocator, CFOptionFlags mutability, 21 CFNumberRef* number, CFErrorRef *error, 22 const uint8_t* der, const uint8_t *der_end) 23{ 24 if (NULL == der) 25 return NULL; 26 27 size_t payload_size = 0; 28 const uint8_t *payload = ccder_decode_tl(CCDER_INTEGER, &payload_size, der, der_end); 29 30 if (NULL == payload || (der_end - payload) < payload_size) { 31 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown number encoding"), NULL, error); 32 return NULL; 33 } 34 if (payload_size > sizeof(long long)) { 35 SecCFDERCreateError(kSecDERErrorUnsupportedNumberType, CFSTR("Number too large"), NULL, error); 36 return NULL; 37 38 } 39 40 long long value = 0; 41 42 if (payload_size > 0) { 43 if ((*payload & 0x80) == 0x80) 44 value = -1; // Negative integers fill with 1s so we end up negative. 45 46 const uint8_t* const payload_end = payload + payload_size; 47 48 for (const uint8_t *payload_byte = payload; 49 payload_byte < payload_end; 50 ++payload_byte) { 51 value <<= 8; 52 value |= *payload_byte; 53 } 54 } 55 56 *number = CFNumberCreate(allocator, kCFNumberLongLongType, &value); 57 58 if (*number == NULL) { 59 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Number allocation failed"), NULL, error); 60 return NULL; 61 } 62 63 return payload + payload_size; 64} 65 66 67static inline uint8_t byte_of(size_t byteNumber, long long value) 68{ 69 return value >> (8 * (byteNumber - 1)); 70} 71 72static inline size_t bytes_when_encoded(long long value) 73{ 74 size_t bytes_encoded = sizeof(long long); 75 76 uint8_t first_byte = byte_of(bytes_encoded, value); 77 78 // Skip initial 0xFFs or 0x00 79 if (first_byte == 0xFF || first_byte == 0x00) { 80 do { 81 --bytes_encoded; 82 } while (bytes_encoded > 1 && (byte_of(bytes_encoded, value) == first_byte)); 83 84 if ((first_byte & 0x80) != (byte_of(bytes_encoded, value) & 0x80)) 85 bytes_encoded += 1; 86 } 87 88 return bytes_encoded; 89} 90 91size_t der_sizeof_number(CFNumberRef data, CFErrorRef *error) 92{ 93 long long value; 94 if (!CFNumberGetValue(data, kCFNumberLongLongType, &value)) 95 return 0; 96 97 return ccder_sizeof(CCDER_INTEGER, bytes_when_encoded(value)); 98} 99 100uint8_t* der_encode_number(CFNumberRef number, CFErrorRef *error, 101 const uint8_t *der, uint8_t *der_end) 102{ 103 long long value; 104 if (!CFNumberGetValue(number, kCFNumberLongLongType, &value)) 105 return NULL; 106 107 size_t first_byte_to_include = bytes_when_encoded(value); 108 109 if (!der_end || der_end - der < first_byte_to_include) 110 return NULL; 111 112 // Put the bytes we should include on the end. 113 for(int bytes_included = 0; bytes_included < first_byte_to_include; ++bytes_included) 114 { 115 --der_end; 116 *der_end = value & 0xFF; 117 value >>= 8; 118 } 119 120 return ccder_encode_tl(CCDER_INTEGER, first_byte_to_include, der, der_end); 121 122} 123