]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecOTRPublicIdentity.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / sec / Security / SecOTRPublicIdentity.c
1 /*
2 * Copyright (c) 2011-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 <utilities/SecCFWrappers.h>
28
29 #include <AssertMacros.h>
30
31 #include <CoreFoundation/CFNumber.h>
32 #include <CoreFoundation/CFString.h>
33 #include <CoreFoundation/CFData.h>
34
35 #include <Security/SecKey.h>
36 #include <Security/SecKeyPriv.h>
37
38 #include <corecrypto/ccn.h>
39 #include <corecrypto/ccec.h>
40 #include <corecrypto/ccder.h>
41
42 #import <sys/syslog.h>
43
44 #include "SecOTRErrors.h"
45 #include <TargetConditionals.h>
46
47 #include <CommonCrypto/CommonDigest.h>
48 #include <CommonCrypto/CommonDigestSPI.h>
49
50 /*
51 * Support for encoding and decoding DH parameter blocks.
52 * Apple form encodes the reciprocal of the prime p.
53 */
54
55 enum {
56 kOTRPIDER_SigningID = 1,
57 kOTRPIDER_SupportsHashes =3,
58 };
59
60 //
61 // SecOTRPublicIdentity implementation
62 //
63
64 CFGiblisFor(SecOTRPublicIdentity);
65
66 static bool sAdvertiseHashes = false;
67
68 static CF_RETURNS_RETAINED CFStringRef SecOTRPublicIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
69 SecOTRPublicIdentityRef requestor = (SecOTRPublicIdentityRef)cf;
70 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
71 requestor,
72 requestor->hash[0], requestor->hash[1],
73 requestor->hash[2], requestor->hash[3],
74 requestor->hash[4], requestor->hash[5],
75 requestor->hash[6], requestor->hash[7]);
76 }
77
78 static void SecOTRPublicIdentityDestroy(CFTypeRef cf) {
79 SecOTRPublicIdentityRef requestor = (SecOTRPublicIdentityRef)cf;
80
81 CFReleaseNull(requestor->publicSigningKey);
82 }
83
84 static bool SecKeyDigestAndVerifyWithError(
85 SecKeyRef key, /* Public key */
86 const SecAsn1AlgId *algId, /* algorithm oid/params */
87 const uint8_t *dataToDigest, /* signature over this data */
88 size_t dataToDigestLen,/* length of dataToDigest */
89 uint8_t *sig, /* signature to verify */
90 size_t sigLen, /* length of sig */
91 CFErrorRef *error) {
92
93 OSStatus status = SecKeyDigestAndVerify(key, algId, dataToDigest, dataToDigestLen, sig, sigLen);
94 require_noerr(status, fail);
95 return true;
96 fail:
97 SecOTRCreateError(secOTRErrorOSError, status, CFSTR("Error verifying message. OSStatus in error code."), NULL, error);
98 return false;
99 }
100
101 static bool SecOTRPICacheHash(SecOTRPublicIdentityRef pubID, CFErrorRef *error)
102 {
103 bool result = false;
104
105 CFMutableDataRef stream = CFDataCreateMutable(NULL, 0);
106
107 require(SecOTRPIAppendSerialization(pubID, stream, error), fail);
108
109 CCDigest(kCCDigestSHA1, CFDataGetBytePtr(stream), (CC_LONG)CFDataGetLength(stream), pubID->hash);
110
111 result = true;
112
113 fail:
114 CFReleaseSafe(stream);
115 return result;
116 }
117
118 void SecOTRAdvertiseHashes(bool advertise) {
119 sAdvertiseHashes = advertise;
120 }
121
122 SecOTRPublicIdentityRef SecOTRPublicIdentityCopyFromPrivate(CFAllocatorRef allocator, SecOTRFullIdentityRef fullID, CFErrorRef *error)
123 {
124 SecOTRPublicIdentityRef result = CFTypeAllocate(SecOTRPublicIdentity, struct _SecOTRPublicIdentity, allocator);
125
126 EnsureOTRAlgIDInited();
127
128 result->publicSigningKey = fullID->publicSigningKey;
129 CFRetain(result->publicSigningKey);
130
131 require(SecOTRPICacheHash(result, error), fail);
132
133 return result;
134
135 fail:
136 CFReleaseSafe(result);
137 return NULL;
138 }
139
140
141 SecOTRPublicIdentityRef SecOTRPublicIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef publicKey,
142 CFErrorRef *error) {
143 // TODO - make sure this is an appropriate key type
144 SecOTRPublicIdentityRef result = CFTypeAllocate(SecOTRPublicIdentity, struct _SecOTRPublicIdentity, allocator);
145 result->publicSigningKey = publicKey;
146 CFRetain(result->publicSigningKey);
147 require(SecOTRPICacheHash(result, error), fail);
148 return result;
149 fail:
150 CFRelease(result->publicSigningKey);
151 CFReleaseSafe(result);
152 return NULL;
153 }
154
155 typedef SecKeyRef (*SecOTRPublicKeyCreateFunction)(CFAllocatorRef allocator, const uint8_t** data, size_t* limit);
156
157 static SecKeyRef SecOTRCreatePublicKeyFrom(const uint8_t* keyData, size_t keyDataSize, ccder_tag tagContainingKey, SecOTRPublicKeyCreateFunction createFunction)
158 {
159 SecKeyRef createdKey = NULL;
160
161 createdKey = createFunction(kCFAllocatorDefault, &keyData, &keyDataSize);
162
163 require(createdKey != NULL, fail);
164 require(keyDataSize == 0, fail);
165
166 return createdKey;
167
168 fail:
169 CFReleaseSafe(createdKey);
170 return NULL;
171 }
172
173
174 SecOTRPublicIdentityRef SecOTRPublicIdentityCreateFromBytes(CFAllocatorRef allocator, const uint8_t**bytes, size_t* size, CFErrorRef *error)
175 {
176 CFErrorRef stackedError = NULL;
177
178 SecOTRPublicIdentityRef newID = CFTypeAllocate(SecOTRPublicIdentity, struct _SecOTRPublicIdentity, allocator);
179
180 EnsureOTRAlgIDInited();
181
182 const uint8_t* fullSequenceEnd = *bytes + *size;
183
184 const uint8_t* keyData = ccder_decode_sequence_tl(&fullSequenceEnd, *bytes, fullSequenceEnd);
185 size_t fullSize = (size_t)(fullSequenceEnd - *bytes);
186
187 size_t keyDataSize;
188 keyData = ccder_decode_tl(CCDER_CONTEXT_SPECIFIC | kOTRPIDER_SigningID, &keyDataSize, keyData, fullSequenceEnd);
189 newID->publicSigningKey = SecOTRCreatePublicKeyFrom(keyData, keyDataSize, kOTRPIDER_SigningID, &CreateECPublicKeyFrom);
190 require(newID->publicSigningKey != NULL, fail);
191 keyData += keyDataSize;
192
193 newID->wantsHashes = (NULL != ccder_decode_tl(CCDER_CONTEXT_SPECIFIC | kOTRPIDER_SupportsHashes, &keyDataSize, keyData, fullSequenceEnd));
194
195 require(SecOTRPICacheHash(newID, &stackedError), fail);
196
197 *bytes += fullSize;
198 *size -= fullSize;
199
200 return newID;
201
202 fail:
203 SecOTRCreateError(secOTRErrorLocal, kSecOTRErrorCreatePublicIdentity, CFSTR("Error creating public identity from bytes"), stackedError, error);
204 CFReleaseSafe(newID);
205 return NULL;
206 }
207
208 SecOTRPublicIdentityRef SecOTRPublicIdentityCreateFromData(CFAllocatorRef allocator, CFDataRef serializedData, CFErrorRef *error)
209 {
210 if (serializedData == NULL)
211 return NULL;
212
213 size_t length = (size_t)CFDataGetLength(serializedData);
214 const uint8_t* bytes = CFDataGetBytePtr(serializedData);
215 return SecOTRPublicIdentityCreateFromBytes(allocator, &bytes, &length, error);
216 }
217
218 bool SecOTRPIEqualToBytes(SecOTRPublicIdentityRef id, const uint8_t*bytes, CFIndex size)
219 {
220 CFDataRef dataToMatch = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, size, kCFAllocatorNull);
221 CFMutableDataRef idStreamed = CFDataCreateMutable(kCFAllocatorDefault, 0);
222
223 SecOTRPIAppendSerialization(id, idStreamed, NULL);
224
225 bool equal = CFEqualSafe(dataToMatch, idStreamed);
226
227 CFReleaseNull(dataToMatch);
228 CFReleaseNull(idStreamed);
229
230 return equal;
231 }
232
233 bool SecOTRPIEqual(SecOTRPublicIdentityRef left, SecOTRPublicIdentityRef right)
234 {
235 if (left == right)
236 return true;
237
238 CFMutableDataRef leftData = CFDataCreateMutable(kCFAllocatorDefault, 0);
239 CFMutableDataRef rightData = CFDataCreateMutable(kCFAllocatorDefault, 0);
240
241 SecOTRPIAppendSerialization(left, leftData, NULL);
242 SecOTRPIAppendSerialization(right, rightData, NULL);
243
244 bool match = CFEqualSafe(leftData, rightData);
245
246 CFReleaseNull(leftData);
247 CFReleaseNull(rightData);
248
249 return match;
250 }
251
252 size_t SecOTRPISignatureSize(SecOTRPublicIdentityRef publicID)
253 {
254 return SecKeyGetSize(publicID->publicSigningKey, kSecKeySignatureSize);
255 }
256
257 bool SecOTRPIAppendSerialization(SecOTRPublicIdentityRef publicID, CFMutableDataRef serializeInto, CFErrorRef *error)
258 {
259 CFIndex start = CFDataGetLength(serializeInto);
260 CFMutableDataRef signingKeySerialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
261
262 uint8_t sendHashes[1] = { 0xFF };
263
264 require_noerr(appendPublicOctetsAndSize(publicID->publicSigningKey, signingKeySerialized), fail);
265
266 size_t outputSize = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
267 ccder_sizeof_implicit_raw_octet_string(CCDER_CONTEXT_SPECIFIC | kOTRPIDER_SigningID, (size_t)CFDataGetLength(signingKeySerialized)) +
268 (sAdvertiseHashes ? ccder_sizeof_implicit_raw_octet_string(CCDER_CONTEXT_SPECIFIC | kOTRPIDER_SupportsHashes, sizeof(sendHashes)) : 0));
269
270 CFDataIncreaseLength(serializeInto, outputSize);
271
272 uint8_t *outputBuffer = CFDataGetMutableBytePtr(serializeInto) + start;
273 uint8_t *outputBufferEnd = outputBuffer + outputSize;
274
275 uint8_t *result = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, outputBufferEnd, outputBuffer,
276 ccder_encode_implicit_raw_octet_string(CCDER_CONTEXT_SPECIFIC | kOTRPIDER_SigningID, (size_t)CFDataGetLength(signingKeySerialized), CFDataGetBytePtr(signingKeySerialized), outputBuffer,
277 sAdvertiseHashes ? ccder_encode_implicit_raw_octet_string(CCDER_CONTEXT_SPECIFIC | kOTRPIDER_SupportsHashes, sizeof(sendHashes), sendHashes, outputBuffer, outputBufferEnd) : outputBufferEnd));
278
279 require_quiet(result == outputBuffer, fail);
280
281 CFReleaseSafe(signingKeySerialized);
282
283 return true;
284
285 fail:
286 CFReleaseSafe(signingKeySerialized);
287
288 CFDataSetLength(serializeInto, start);
289
290 SecOTRCreateError(secOTRErrorLocal, kSecOTRErrorCreatePublicBytes, CFSTR("Unable to create public key bytes"), NULL, error);
291 return false;
292 }
293
294 static const uint8_t *mp_decode_forced_uint(cc_size n, cc_unit *r, const uint8_t *der, const uint8_t *der_end) {
295 size_t len;
296 der = ccder_decode_tl(CCDER_INTEGER, &len, der, der_end);
297 if (der && ccn_read_uint(n, r, len, der) >= 0)
298 return der + len;
299
300 return NULL;
301 }
302
303 static void SecOTRPIRecreateSignature(const uint8_t *oldSignature, size_t oldSignatureSize, uint8_t **newSignature, size_t *newSignatureSize)
304 {
305 cc_unit r[ccec_cp_n(ccec_cp_256())], s[ccec_cp_n(ccec_cp_256())];
306 cc_size n = ccec_cp_n(ccec_cp_256());
307
308 const uint8_t *oldSignatureEnd = oldSignature + oldSignatureSize;
309
310 oldSignature = ccder_decode_sequence_tl(&oldSignatureEnd, oldSignature, oldSignatureEnd);
311 oldSignature = mp_decode_forced_uint(n, r, oldSignature, oldSignatureEnd);
312 oldSignature = mp_decode_forced_uint(n, s, oldSignature, oldSignatureEnd);
313 (void) oldSignature; // We could check for a good end, but it'll come out when we re-encode.
314
315 const uint8_t *outputPointer = *newSignature;
316 uint8_t *outputEndPointer = *newSignature + *newSignatureSize;
317
318 *newSignature = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, outputEndPointer, outputPointer, ccder_encode_integer(n, r, outputPointer, ccder_encode_integer(n, s, outputPointer, outputEndPointer)));
319 long newSigSize = outputEndPointer - *newSignature;
320 *newSignatureSize = (newSigSize >= 0) ? (size_t)newSigSize : 0;
321 }
322
323 bool SecOTRPIVerifySignature(SecOTRPublicIdentityRef publicID,
324 const uint8_t *dataToHash, size_t amountToHash,
325 const uint8_t *signatureStart, size_t signatureSize, CFErrorRef *error)
326 {
327 require(signatureSize > 0, fail);
328 require(*signatureStart == signatureSize - 1, fail);
329 signatureSize -= 1;
330 signatureStart += 1;
331
332 require(SecKeyDigestAndVerifyWithError(publicID->publicSigningKey, kOTRSignatureAlgIDPtr,
333 dataToHash, amountToHash,
334 (uint8_t*)signatureStart, signatureSize, NULL), fail);
335 return true;
336 fail: ;
337
338 uint8_t replacementSignature[signatureSize + 3];
339 size_t replacementSignatureLen = sizeof(replacementSignature);
340 uint8_t *replacementSignaturePtr = replacementSignature;
341
342 SecOTRPIRecreateSignature(signatureStart, signatureSize, &replacementSignaturePtr, &replacementSignatureLen);
343
344 require_action(replacementSignaturePtr, fail2, SecOTRCreateError(secOTRErrorLocal, kSecOTRErrorSignatureDidNotRecreate, CFSTR("Unable to recreate signature blob."), NULL, error));
345
346 require(SecKeyDigestAndVerifyWithError(publicID->publicSigningKey, kOTRSignatureAlgIDPtr,
347 dataToHash, amountToHash,
348 replacementSignaturePtr, replacementSignatureLen, error), fail2);
349 return true;
350
351 fail2:
352 return false;
353 }
354
355 void SecOTRPICopyHash(SecOTRPublicIdentityRef publicID, uint8_t hash[kMPIDHashSize])
356 {
357 memcpy(hash, publicID->hash, kMPIDHashSize);
358 }
359
360 void SecOTRPIAppendHash(SecOTRPublicIdentityRef publicID, CFMutableDataRef appendTo)
361 {
362 CFDataAppendBytes(appendTo, publicID->hash, sizeof(publicID->hash));
363 }
364
365 bool SecOTRPICompareHash(SecOTRPublicIdentityRef publicID, const uint8_t hash[kMPIDHashSize])
366 {
367 return 0 == memcmp(hash, publicID->hash, kMPIDHashSize);
368 }