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