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