]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecOTRUtils.c
Security-57336.1.9.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 <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
41 CFStringRef sLocalErrorDomain = CFSTR("com.apple.security.otr.error");
42
43 bool 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
55 OSStatus 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
64 fail:
65 return errSecParam;
66 }
67
68 OSStatus 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
77 fail:
78 return errSecParam;
79 }
80
81 OSStatus 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;
94 fail:
95 return errSecParam;
96 }
97
98 OSStatus 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
107 exit:
108 return status;
109 }
110
111 OSStatus 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
121 exit:
122 CFReleaseNull(serializedKey);
123 return status;
124 }
125
126 OSStatus 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
138 exit:
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. */
146 static 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
155 typedef SecKeyRef (*createFunction_t)(CFAllocatorRef allocator,
156 const uint8_t *keyData, CFIndex keyDataLength);
157
158 static 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
174 fail:
175
176 return create(allocator, foundData, foundLength);
177 }
178
179 SecKeyRef CreateECPublicKeyFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit)
180 {
181 return CallCreateFunctionFrom(allocator, data, limit, &SecKeyCreateECPublicKey);
182 }
183
184 CFDataRef 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
211 void 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