]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecOTRFullIdentity.c
Security-59306.80.4.tar.gz
[apple/security.git] / OSX / sec / Security / SecOTRFullIdentity.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/array_size.h>
28 #include <utilities/SecCFError.h>
29 #include <utilities/SecCFWrappers.h>
30
31 #include <AssertMacros.h>
32
33 #include <CoreFoundation/CFNumber.h>
34 #include <CoreFoundation/CFString.h>
35 #include <CoreFoundation/CFData.h>
36
37 #include <Security/SecItem.h>
38 #include <Security/SecItemPriv.h>
39 #include <Security/SecKeyPriv.h>
40
41 #include <Security/oidsalg.h>
42 #include <Security/SecCertificatePriv.h>
43
44 #include "SecOTRErrors.h"
45
46 #include <TargetConditionals.h>
47
48 //
49 // Algorthim ID initialization
50 //
51
52 #define kMessageIdentityRSAKeyBits 1280
53 #define kMessageIdentityECKeyBits 256
54
55 const SecAsn1AlgId *kOTRSignatureAlgIDPtr;
56
57 void EnsureOTRAlgIDInited(void)
58 {
59 static dispatch_once_t kSignatureAlgID_ONCE;
60 static SecAsn1AlgId kOTRECSignatureAlgID;
61
62 dispatch_once(&kSignatureAlgID_ONCE, ^{
63 kOTRECSignatureAlgID.algorithm = CSSMOID_ECDSA_WithSHA1;
64 kOTRSignatureAlgIDPtr = &kOTRECSignatureAlgID;
65 });
66 }
67
68
69 static CFStringRef sSigningKeyName = CFSTR("OTR Signing Key");
70
71 //
72 // SecOTRFullIdentity implementation
73 //
74
75 CFGiblisFor(SecOTRFullIdentity);
76
77 static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
78 SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
79 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
80 requestor,
81 requestor->publicIDHash[0], requestor->publicIDHash[1],
82 requestor->publicIDHash[2], requestor->publicIDHash[3],
83 requestor->publicIDHash[4], requestor->publicIDHash[5],
84 requestor->publicIDHash[6], requestor->publicIDHash[7]);
85 }
86
87 static void SecOTRFullIdentityDestroy(CFTypeRef cf) {
88 SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
89
90 CFReleaseNull(requestor->privateSigningKey);
91 CFReleaseNull(requestor->publicSigningKey);
92 CFReleaseNull(requestor->privateKeyPersistentRef);
93 }
94
95
96 //
97 // Shared statics
98 //
99
100 static OSStatus SecOTRFIPurgeFromKeychainByValue(SecKeyRef key, CFStringRef label)
101 {
102 OSStatus status;
103 const void *keys[] = { kSecClass,
104 kSecAttrLabel,
105 kSecValueRef,
106 };
107 const void *values[] = { kSecClassKey,
108 label,
109 key,
110 };
111 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, array_size(values), NULL, NULL);
112 status = SecItemDelete(dict);
113 CFReleaseSafe(dict);
114
115 return status;
116 }
117
118 static bool SecKeyDigestAndSignWithError(
119 SecKeyRef key, /* Private key */
120 const SecAsn1AlgId *algId, /* algorithm oid/params */
121 const uint8_t *dataToDigest, /* signature over this data */
122 size_t dataToDigestLen,/* length of dataToDigest */
123 uint8_t *sig, /* signature, RETURNED */
124 size_t *sigLen, /* IN/OUT */
125 CFErrorRef *error) {
126
127 OSStatus status = SecKeyDigestAndSign(key, algId, dataToDigest, dataToDigestLen, sig, sigLen);
128 require_noerr(status, fail);
129 return true;
130 fail:
131 SecOTRCreateError(secOTRErrorOSError, status, CFSTR("Error signing message. OSStatus in error code."), NULL, error);
132 return false;
133 }
134
135 //
136 // SecOTRFullIdentity Functions
137 //
138
139 static bool SecOTRFICachePublicHash(SecOTRFullIdentityRef fullID, CFErrorRef *error)
140 {
141 SecOTRPublicIdentityRef pubID = SecOTRPublicIdentityCopyFromPrivate(NULL, fullID, error);
142
143 require(pubID, fail);
144
145 SecOTRPICopyHash(pubID, fullID->publicIDHash);
146
147 fail:
148 CFReleaseSafe(pubID);
149 return (pubID != NULL); // This is safe because we're not accessing the value after release, just checking if it ever had a value of some nature.
150 }
151
152 static SecKeyRef SecOTRCreateSigningKey(CFAllocatorRef allocator) {
153 SecKeyRef publicKey = NULL;
154 SecKeyRef fullKey = NULL;
155 CFDictionaryRef keygen_parameters = NULL;
156 const int signing_keySizeLocal = kMessageIdentityECKeyBits;
157 CFNumberRef signing_bitsize = CFNumberCreate(allocator, kCFNumberIntType, &signing_keySizeLocal);
158
159 const void *signing_keygen_keys[] = { kSecAttrKeyType,
160 kSecAttrKeySizeInBits,
161 kSecAttrIsPermanent,
162 kSecAttrAccessible,
163 kSecAttrLabel,
164 };
165
166 const void *signing_keygen_vals[] = { kSecAttrKeyTypeEC,
167 signing_bitsize,
168 kCFBooleanTrue,
169 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
170 sSigningKeyName
171 };
172 keygen_parameters = CFDictionaryCreate(allocator,
173 signing_keygen_keys, signing_keygen_vals, array_size(signing_keygen_vals),
174 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
175 CFReleaseNull(signing_bitsize);
176 require_noerr_action(SecKeyGeneratePair(keygen_parameters, &publicKey, &fullKey),
177 errOut,
178 secerror("keygen failed"));
179 SecOTRFIPurgeFromKeychainByValue(publicKey, sSigningKeyName);
180
181 CFReleaseNull(keygen_parameters);
182 errOut:
183 return fullKey;
184 }
185
186 SecOTRFullIdentityRef SecOTRFullIdentityCreate(CFAllocatorRef allocator, CFErrorRef *error)
187 {
188 SecKeyRef signingKey = SecOTRCreateSigningKey(allocator);
189 SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRef(allocator, signingKey, error);
190 CFReleaseNull(signingKey);
191
192 return newID;
193 }
194
195
196 static
197 OSStatus SecOTRFICreatePrivateKeyReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef* privateKey, CFDataRef *newPersistentRef)
198 {
199 OSStatus status = errSecParam;
200 uint16_t dataSize;
201 CFDataRef foundPersistentRef = NULL;
202
203 require_quiet(newPersistentRef, fail);
204
205 require_noerr_quiet(readSize(bytes, size, &dataSize), fail);
206 require_quiet(dataSize <= *size, fail);
207
208 foundPersistentRef = CFDataCreate(kCFAllocatorDefault, *bytes, dataSize);
209 require_quiet(foundPersistentRef, fail);
210
211 require_noerr_quiet(status = SecKeyFindWithPersistentRef(foundPersistentRef, privateKey), fail);
212
213 *bytes += dataSize;
214 *size -= dataSize;
215
216 status = errSecSuccess;
217
218 *newPersistentRef = foundPersistentRef;
219 foundPersistentRef = NULL;
220
221 fail:
222 CFReleaseSafe(foundPersistentRef);
223 return status;
224 }
225
226 static
227 OSStatus SecOTRFICreateKeysFromReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, CFDataRef *persistentRef)
228 {
229 SecKeyRef foundKey = NULL;
230 CFDataRef foundRef = NULL;
231
232 OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey, &foundRef);
233 require_noerr_quiet(status, fail);
234
235 require_action_quiet(*publicKey = SecKeyCreatePublicFromPrivate(foundKey), fail, status = errSecInternalComponent);
236
237 *privateKey = foundKey;
238 foundKey = NULL;
239 *persistentRef = foundRef;
240 foundRef = NULL;
241
242 fail:
243 CFReleaseSafe(foundKey);
244 CFReleaseSafe(foundRef);
245 return status;
246 }
247
248 typedef SecKeyRef (*SecOTRPublicKeyCreateFunction)(CFAllocatorRef allocator, const uint8_t** data, size_t* limit);
249
250 static
251 OSStatus SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, CFDataRef *persistentRef, SecOTRPublicKeyCreateFunction createPublic)
252 {
253 SecKeyRef foundKey = NULL;
254 CFDataRef foundRef = NULL;
255
256 OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey, &foundRef);
257 require_noerr_quiet(status, fail);
258
259 require_action_quiet(*publicKey = createPublic(NULL, bytes, size), fail, status = errSecInternalComponent);
260
261 *privateKey = foundKey;
262 foundKey = NULL;
263 *persistentRef = foundRef;
264 foundRef = NULL;
265
266 fail:
267 CFReleaseSafe(foundKey);
268 CFReleaseSafe(foundRef);
269 return status;
270 }
271
272 static
273 OSStatus SecOTRFIInitFromV1Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
274 const uint8_t **bytes,size_t *size) {
275 OSStatus status;
276 require_action(**bytes == 1, fail, status = errSecParam);
277 ++*bytes;
278 --*size;
279
280 require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRef(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef), fail);
281
282 return status;
283
284 fail:
285 CFReleaseNull(newID->publicSigningKey);
286 CFReleaseNull(newID->privateSigningKey);
287 CFReleaseNull(newID->privateKeyPersistentRef);
288
289 return status;
290 }
291
292 static
293 OSStatus SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
294 const uint8_t **bytes,size_t *size) {
295 OSStatus status;
296 require_action(**bytes == 2, fail, status = errSecParam);
297 ++*bytes;
298 --*size;
299
300 require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef, &CreateECPublicKeyFrom), fail);
301
302 return status;
303
304 fail:
305 CFReleaseNull(newID->privateKeyPersistentRef);
306 CFReleaseNull(newID->publicSigningKey);
307 CFReleaseNull(newID->privateSigningKey);
308
309 return status;
310 }
311
312 // TODO: Probably move to SecKey
313 static CFDataRef SecKeyCreatePersistentRef(SecKeyRef theKey, CFErrorRef *error) {
314 CFDataRef persistentRef = NULL;
315 OSStatus status = SecKeyCopyPersistentRef(theKey, &persistentRef);
316 if (status)
317 SecError(status, error, CFSTR("failed to find persistent ref for key: %d"), (int)status);
318 return persistentRef;
319 }
320
321 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef privateKey,
322 CFErrorRef *error) {
323 // TODO - make sure this is an appropriate key type
324 SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
325 CFRetainAssign(newID->privateSigningKey, privateKey);
326 require_action(newID->publicSigningKey = SecKeyCreatePublicFromPrivate(privateKey), fail,
327 SecError(errSecInternalComponent, error, CFSTR("Failed to extract public key from private key")));
328 require(newID->privateKeyPersistentRef = SecKeyCreatePersistentRef(privateKey, error), fail);
329 require(SecOTRFICachePublicHash(newID, error), fail);
330 return newID;
331 fail:
332 CFReleaseNull(newID);
333 return NULL;
334 }
335
336 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromBytes(CFAllocatorRef allocator, const uint8_t**bytes, size_t *size, CFErrorRef *error)
337 {
338 SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
339 EnsureOTRAlgIDInited();
340
341 require(*size > 0, fail);
342 OSStatus status;
343 switch (**bytes) {
344 case 1:
345 require_noerr_action_quiet(status = SecOTRFIInitFromV1Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v1 otr session: %d"), (int)status));
346 break;
347 case 2:
348 require_noerr_action_quiet(status = SecOTRFIInitFromV2Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v2 otr session: %d"), (int)status));
349 break;
350 case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
351 default:
352 SecError(errSecParam, error, CFSTR("unknown otr session version %hhu"), **bytes);
353 goto fail;
354 }
355
356 require(SecOTRFICachePublicHash(newID, error), fail);
357
358 return newID;
359
360 fail:
361 if (NULL != newID) {
362 SecOTRFIPurgeFromKeychain(newID, NULL);
363 }
364 CFReleaseSafe(newID);
365 return NULL;
366 }
367
368 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error)
369 {
370 if (data == NULL)
371 return NULL;
372
373 size_t size = (size_t)CFDataGetLength(data);
374 const uint8_t* bytes = CFDataGetBytePtr(data);
375
376 return SecOTRFullIdentityCreateFromBytes(allocator, &bytes, &size, error);
377 }
378
379 bool SecOTRFIPurgeFromKeychain(SecOTRFullIdentityRef thisID, CFErrorRef *error)
380 {
381 OSStatus result = SecOTRFIPurgeFromKeychainByValue(thisID->privateSigningKey, sSigningKeyName);
382 if (errSecSuccess == result) {
383 return true;
384 } else {
385 SecOTRCreateError(secOTRErrorOSError, result, CFSTR("OSStatus returned in error code"), NULL, error);
386 return false;
387 }
388 }
389
390
391 static OSStatus SecOTRFIPurgeAllFromKeychainByLabel(CFStringRef label)
392 {
393 OSStatus status;
394 const void *keys[] = { kSecClass,
395 kSecAttrKeyClass,
396 kSecAttrLabel,
397 };
398 const void *values[] = { kSecClassKey,
399 kSecAttrKeyClassPrivate,
400 label,
401 };
402 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, array_size(values), NULL, NULL);
403 bool deleteAtLeastOne = false;
404 int loopLimiter = 500;
405 do {
406 status = SecItemDelete(dict);
407 if (status == errSecSuccess) {
408 deleteAtLeastOne = true;
409 }
410 loopLimiter--;
411 } while ((status == errSecSuccess) && (loopLimiter > 0));
412 if ((status == errSecItemNotFound) && (deleteAtLeastOne)) {
413 // We've looped until we can't delete any more keys.
414 // Since this will produce an expected 'itemNotFound', but we don't want to break the contract above
415 // (and also we want to make sense)
416 // we muffle the non-error to a success case, which it is.
417 status = errSecSuccess;
418 }
419 CFReleaseSafe(dict);
420
421 return status;
422 }
423
424 bool SecOTRFIPurgeAllFromKeychain(CFErrorRef *error)
425 {
426 OSStatus result = SecOTRFIPurgeAllFromKeychainByLabel(sSigningKeyName);
427 if (errSecSuccess == result) {
428 return true;
429 } else {
430 SecOTRCreateError(secOTRErrorOSError, result, CFSTR("OSStatus returned in error code"), NULL, error);
431 return false;
432 }
433 }
434
435
436 static OSStatus SecOTRFIAppendV2Serialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto)
437 {
438 const uint8_t version = 2;
439 CFIndex start = CFDataGetLength(serializeInto);
440
441 CFDataAppendBytes(serializeInto, &version, sizeof(version));
442 appendSizeAndData(fullID->privateKeyPersistentRef, serializeInto);
443 require(errSecSuccess == appendPublicOctetsAndSize(fullID->publicSigningKey, serializeInto), fail);
444 return errSecSuccess;
445
446 fail:
447 CFDataSetLength(serializeInto, start);
448
449 return errSecParam;
450 }
451
452
453 bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto, CFErrorRef *error)
454 {
455 OSStatus status = SecOTRFIAppendV2Serialization(fullID, serializeInto);
456 if (errSecSuccess == status) {
457 return true;
458 } else {
459 SecOTRCreateError(secOTRErrorOSError, status, CFSTR("OSStatus returned in error code"), NULL, error);
460 return false;
461 }
462 }
463
464 size_t SecOTRFISignatureSize(SecOTRFullIdentityRef fullID)
465 {
466 return SecKeyGetSize(fullID->publicSigningKey, kSecKeySignatureSize);
467 }
468
469 bool SecOTRFICompareToPublicKey(SecOTRFullIdentityRef fullID, SecKeyRef publicKey) {
470 return CFEqualSafe(fullID->publicSigningKey, publicKey);
471 }
472
473 bool SecOTRFIAppendSignature(SecOTRFullIdentityRef fullID,
474 CFDataRef dataToHash,
475 CFMutableDataRef appendTo,
476 CFErrorRef *error)
477 {
478 const size_t signatureSize = SecOTRFISignatureSize(fullID);
479 const CFIndex sourceLength = CFDataGetLength(dataToHash);
480 const uint8_t* sourceData = CFDataGetBytePtr(dataToHash);
481
482 CFIndex start = CFDataGetLength(appendTo);
483
484 require(((CFIndex)signatureSize) >= 0, fail);
485
486 CFDataIncreaseLength(appendTo, (CFIndex)signatureSize + 1);
487
488 uint8_t *size = CFDataGetMutableBytePtr(appendTo) + start;
489 uint8_t* signatureStart = size + 1;
490 size_t signatureUsed = signatureSize;
491
492 require(SecKeyDigestAndSignWithError(fullID->privateSigningKey, kOTRSignatureAlgIDPtr,
493 sourceData, (size_t)sourceLength,
494 signatureStart, &signatureUsed, error), fail);
495
496 require(signatureUsed < 256, fail);
497 require(((CFIndex)signatureUsed) >= 0, fail);
498 *size = signatureUsed;
499
500 CFDataSetLength(appendTo, start + (CFIndex)signatureUsed + 1);
501
502 return true;
503
504 fail:
505 CFDataSetLength(appendTo, start);
506
507 return false;
508 }
509
510 void SecOTRFIAppendPublicHash(SecOTRFullIdentityRef fullID, CFMutableDataRef appendTo)
511 {
512 CFDataAppendBytes(appendTo, fullID->publicIDHash, sizeof(fullID->publicIDHash));
513 }
514
515 bool SecOTRFIComparePublicHash(SecOTRFullIdentityRef fullID, const uint8_t hash[kMPIDHashSize])
516 {
517 return 0 == memcmp(hash, fullID->publicIDHash, kMPIDHashSize);
518 }