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