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