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