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#include "SecOTR.h" 26#include "SecOTRIdentityPriv.h" 27#include "SecOTRSessionPriv.h" 28#include <utilities/SecCFWrappers.h> 29#include <stdlib.h> 30 31#include <AssertMacros.h> 32 33#include <Security/SecBase.h> 34#include <Security/SecItem.h> 35#include <Security/SecKey.h> 36#include <Security/SecKeyPriv.h> 37#include <Security/SecBase64.h> 38 39#include <TargetConditionals.h> 40 41CFStringRef sLocalErrorDomain = CFSTR("com.apple.security.otr.error"); 42 43bool SecOTRCreateError(enum SecOTRError family, CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) { 44 if (newError && !(*newError)) { 45 const void* keys[2] = {kCFErrorDescriptionKey, kCFErrorUnderlyingErrorKey}; 46 const void* values[2] = {descriptionString, previousError}; 47 *newError = CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, (family == secOTRErrorLocal) ? sLocalErrorDomain : kCFErrorDomainOSStatus, errorCode, keys, values, (previousError != NULL) ? 2 : 1); 48 } else { 49 CFReleaseSafe(previousError); 50 } 51 52 return false; 53} 54 55OSStatus insertSize(CFIndex size, uint8_t* here) 56{ 57 require(size < 0xFFFF, fail); 58 59 uint8_t bytes[] = { (size >> 8) & 0xFF, size & 0xFF }; 60 memcpy(here, bytes, sizeof(bytes)); 61 62 return errSecSuccess; 63 64fail: 65 return errSecParam; 66} 67 68OSStatus appendSize(CFIndex size, CFMutableDataRef into) 69{ 70 require(size < 0xFFFF, fail); 71 72 uint8_t bytes[] = { (size >> 8) & 0xFF, size & 0xFF }; 73 CFDataAppendBytes(into, bytes, sizeof(bytes)); 74 75 return errSecSuccess; 76 77fail: 78 return errSecParam; 79} 80 81OSStatus readSize(const uint8_t** data, size_t* limit, uint16_t* size) 82{ 83 require(limit != NULL, fail); 84 require(data != NULL, fail); 85 require(size != NULL, fail); 86 require(*limit > 1, fail); 87 88 *size = ((uint16_t)(*data)[0]) << 8 | ((uint16_t) (*data)[1]) << 0; 89 90 *limit -= 2; 91 *data += 2; 92 93 return errSecSuccess; 94fail: 95 return errSecParam; 96} 97 98OSStatus appendSizeAndData(CFDataRef data, CFMutableDataRef appendTo) 99{ 100 OSStatus status = errSecNotAvailable; 101 102 require_noerr(appendSize(CFDataGetLength(data), appendTo), exit); 103 CFDataAppend(appendTo, data); 104 105 status = errSecSuccess; 106 107exit: 108 return status; 109} 110 111OSStatus appendPublicOctetsAndSize(SecKeyRef fromKey, CFMutableDataRef appendTo) 112{ 113 OSStatus status = errSecDecode; 114 CFDataRef serializedKey = NULL; 115 116 require_noerr(SecKeyCopyPublicBytes(fromKey, &serializedKey), exit); 117 require(serializedKey, exit); 118 119 status = appendSizeAndData(serializedKey, appendTo); 120 121exit: 122 CFReleaseNull(serializedKey); 123 return status; 124} 125 126OSStatus appendPublicOctets(SecKeyRef fromKey, CFMutableDataRef appendTo) 127{ 128 OSStatus status = errSecDecode; 129 CFDataRef serializedKey = NULL; 130 131 require_noerr(SecKeyCopyPublicBytes(fromKey, &serializedKey), exit); 132 require(serializedKey, exit); 133 134 CFDataAppend(appendTo, serializedKey); 135 136 status = errSecSuccess; 137 138exit: 139 CFReleaseNull(serializedKey); 140 return status; 141} 142 143 144/* Given an EC public key in encoded form return a SecKeyRef representing 145 that key. Supported encodings are kSecKeyEncodingPkcs1. */ 146static SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator, 147 const uint8_t *keyData, CFIndex keyDataLength) { 148 CFDataRef tempData = CFDataCreate(kCFAllocatorDefault, keyData, keyDataLength); 149 SecKeyRef newPublicKey = SecKeyCreateFromPublicData(kCFAllocatorDefault, kSecECDSAAlgorithmID, tempData); 150 151 CFRelease(tempData); 152 return newPublicKey; 153} 154 155typedef SecKeyRef (*createFunction_t)(CFAllocatorRef allocator, 156 const uint8_t *keyData, CFIndex keyDataLength); 157 158static SecKeyRef CallCreateFunctionFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit, createFunction_t create) 159{ 160 uint16_t foundLength = 0; 161 const uint8_t* foundData = NULL; 162 163 require(limit != NULL, fail); 164 require(data != NULL, fail); 165 166 require_noerr(readSize(data, limit, &foundLength), fail); 167 require(foundLength <= *limit, fail); 168 169 foundData = *data; 170 171 *limit -= foundLength; 172 *data += foundLength; 173 174fail: 175 176 return create(allocator, foundData, foundLength); 177} 178 179SecKeyRef CreateECPublicKeyFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit) 180{ 181 return CallCreateFunctionFrom(allocator, data, limit, &SecKeyCreateECPublicKey); 182} 183 184CFDataRef SecOTRCopyIncomingBytes(CFDataRef incomingMessage) 185{ 186 CFDataRef result = NULL; 187 188 CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?'); 189 CFRange headerLoc = CFDataFind(incomingMessage, header, CFRangeMake(0, CFDataGetLength(header)), 0); 190 191 if (kCFNotFound == headerLoc.location) { 192 CFRetainAssign(result, incomingMessage); 193 } else { 194 CFDataRef footer = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("."), kCFStringEncodingUTF8, '?'); 195 CFRange footerLoc = CFDataFind(incomingMessage, footer, CFRangeMake(0, CFDataGetLength(incomingMessage)), 0); 196 197 CFDataRef bodyData = CFDataCreateReferenceFromRange(kCFAllocatorDefault, incomingMessage, CFRangeMake(headerLoc.length, footerLoc.location - headerLoc.length)); 198 size_t size = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), NULL, 0); 199 uint8_t decodedByteArray[size]; 200 SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), decodedByteArray, size); 201 result = CFDataCreate(kCFAllocatorDefault, decodedByteArray, size); 202 203 CFRelease(bodyData); 204 CFRelease(footer); 205 } 206 CFRelease(header); 207 208 return result; 209} 210 211void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage, CFMutableDataRef protectedMessage) 212{ 213 CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?'); 214 CFDataRef footer = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("."), kCFStringEncodingUTF8, '?'); 215 size_t base64Len = SecBase64Encode(CFDataGetBytePtr(destinationMessage), CFDataGetLength(destinationMessage), NULL, 0); 216 char base64Message [base64Len]; 217 SecBase64Encode(CFDataGetBytePtr(destinationMessage), CFDataGetLength(destinationMessage), base64Message, base64Len); 218 CFDataRef base64Data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (uint8_t*)base64Message, base64Len, kCFAllocatorNull); 219 220 CFDataAppend(protectedMessage, header); 221 CFDataAppend(protectedMessage, base64Data); 222 CFDataAppend(protectedMessage, footer); 223 224 CFRelease(header); 225 CFRelease(footer); 226 CFRelease(base64Data); 227} 228 229 230