1/* 2 * Copyright (c) 2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25 26#include <stdio.h> 27 28#include "utilities/SecCFRelease.h" 29#include "utilities/der_plist.h" 30#include "utilities/der_plist_internal.h" 31 32#include <corecrypto/ccder.h> 33#include <CoreFoundation/CoreFoundation.h> 34 35 36const uint8_t* der_decode_number(CFAllocatorRef allocator, CFOptionFlags mutability, 37 CFNumberRef* number, CFErrorRef *error, 38 const uint8_t* der, const uint8_t *der_end) 39{ 40 if (NULL == der) 41 return NULL; 42 43 size_t payload_size = 0; 44 const uint8_t *payload = ccder_decode_tl(CCDER_INTEGER, &payload_size, der, der_end); 45 46 if (NULL == payload || (der_end - payload) < payload_size) { 47 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown number encoding"), NULL, error); 48 return NULL; 49 } 50 if (payload_size > sizeof(long long)) { 51 SecCFDERCreateError(kSecDERErrorUnsupportedNumberType, CFSTR("Number too large"), NULL, error); 52 return NULL; 53 54 } 55 56 long long value = 0; 57 58 if (payload_size > 0) { 59 if ((*payload & 0x80) == 0x80) 60 value = -1; // Negative integers fill with 1s so we end up negative. 61 62 const uint8_t* const payload_end = payload + payload_size; 63 64 for (const uint8_t *payload_byte = payload; 65 payload_byte < payload_end; 66 ++payload_byte) { 67 value <<= 8; 68 value |= *payload_byte; 69 } 70 } 71 72 *number = CFNumberCreate(allocator, kCFNumberLongLongType, &value); 73 74 if (*number == NULL) { 75 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Number allocation failed"), NULL, error); 76 return NULL; 77 } 78 79 return payload + payload_size; 80} 81 82 83static inline uint8_t byte_of(size_t byteNumber, long long value) 84{ 85 return value >> (8 * (byteNumber - 1)); 86} 87 88static inline size_t bytes_when_encoded(long long value) 89{ 90 size_t bytes_encoded = sizeof(long long); 91 92 uint8_t first_byte = byte_of(bytes_encoded, value); 93 94 // Skip initial 0xFFs or 0x00 95 if (first_byte == 0xFF || first_byte == 0x00) { 96 do { 97 --bytes_encoded; 98 } while (bytes_encoded > 1 && (byte_of(bytes_encoded, value) == first_byte)); 99 100 if ((first_byte & 0x80) != (byte_of(bytes_encoded, value) & 0x80)) 101 bytes_encoded += 1; 102 } 103 104 return bytes_encoded; 105} 106 107size_t der_sizeof_number(CFNumberRef data, CFErrorRef *error) 108{ 109 long long value; 110 if (!CFNumberGetValue(data, kCFNumberLongLongType, &value)) 111 return 0; 112 113 return ccder_sizeof(CCDER_INTEGER, bytes_when_encoded(value)); 114} 115 116uint8_t* der_encode_number(CFNumberRef number, CFErrorRef *error, 117 const uint8_t *der, uint8_t *der_end) 118{ 119 long long value; 120 if (!CFNumberGetValue(number, kCFNumberLongLongType, &value)) 121 return NULL; 122 123 size_t first_byte_to_include = bytes_when_encoded(value); 124 125 if (!der_end || der_end - der < first_byte_to_include) 126 return NULL; 127 128 // Put the bytes we should include on the end. 129 for(int bytes_included = 0; bytes_included < first_byte_to_include; ++bytes_included) 130 { 131 --der_end; 132 *der_end = value & 0xFF; 133 value >>= 8; 134 } 135 136 return ccder_encode_tl(CCDER_INTEGER, first_byte_to_include, der, der_end); 137 138} 139