2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #import "OTIdentity.h"
27 #import <SecurityFoundation/SFKey.h>
28 #import <SecurityFoundation/SFKey_Private.h>
29 #import "keychain/ot/OTDefines.h"
31 #import "keychain/SecureObjectSync/SOSAccountTransaction.h"
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
34 #import "keychain/SecureObjectSync/SOSAccount.h"
35 #pragma clang diagnostic pop
37 @interface OTIdentity ()
39 @property (nonatomic, strong) NSString* peerID;
40 @property (nonatomic, strong) NSString* spID;
41 @property (nonatomic, strong) SFECKeyPair* peerSigningKey;
42 @property (nonatomic, strong) SFECKeyPair* peerEncryptionKey;
46 @implementation OTIdentity
48 - (instancetype) initWithPeerID:(nullable NSString*)peerID
49 spID:(nullable NSString*)spID
50 peerSigningKey:(SFECKeyPair*)peerSigningKey
51 peerEncryptionkey:(SFECKeyPair*)peerEncryptionKey
52 error:(NSError**)error
58 _peerSigningKey = peerSigningKey;
59 _peerEncryptionKey = peerEncryptionKey;
64 + (nullable instancetype) currentIdentityFromSOS:(NSError**)error
66 CFErrorRef circleCheckError = NULL;
67 SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(&circleCheckError);
68 if(circleStatus != kSOSCCInCircle){
70 secerror("octagon: cannot retrieve octagon keys from SOS, not in circle, error: %@", circleCheckError);
72 *error = (__bridge NSError*)circleCheckError;
75 secerror("octagon: current circle status: %d",circleStatus);
78 __block NSString* sosPeerID = nil;
79 __block NSError* sosPeerIDError = nil;
81 SOSCCPerformWithPeerID(^(CFStringRef peerID, CFErrorRef error) {
82 sosPeerID = (__bridge NSString *)(peerID);
84 secerror("octagon: retrieving sos peer id error: %@", error);
85 sosPeerIDError = CFBridgingRelease(error);
89 if(sosPeerID == nil || sosPeerIDError != nil){
90 secerror("octagon: cannot retrieve peer id from SOS, error: %@", sosPeerIDError);
92 *error = sosPeerIDError;
97 __block SFECKeyPair *peerEncryptionKey;
98 __block SFECKeyPair *peerSigningKey;
99 __block NSError* localError = nil;
101 SOSCCPerformWithAllOctagonKeys(^(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef cferror) {
103 localError = (__bridge NSError*)cferror;
106 if (!cferror && octagonEncryptionKey && octagonSigningKey) {
107 peerSigningKey = [[SFECKeyPair alloc] initWithSecKey:octagonSigningKey];
108 peerEncryptionKey = [[SFECKeyPair alloc] initWithSecKey:octagonEncryptionKey];
113 if(!peerEncryptionKey || !peerSigningKey || localError != nil){
114 secerror("octagon: failed to retrieve octagon keys from sos: %@", localError);
120 return [[OTIdentity alloc] initWithPeerID:nil
122 peerSigningKey:peerSigningKey
123 peerEncryptionkey:peerEncryptionKey
127 -(BOOL)isEqual:(OTIdentity*)identity
129 return [self.peerID isEqualToString:identity.peerID] &&
130 [self.spID isEqualToString:identity.spID] &&
131 [self.peerSigningKey isEqual:identity.peerSigningKey] &&
132 [self.peerEncryptionKey isEqual:identity.peerEncryptionKey];
135 + (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error
139 CFTypeRef results = NULL;
140 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &results);
142 NSError* localerror = nil;
144 if(status == errSecDuplicateItem || status == errSecSuccess) {
147 localerror = [NSError errorWithDomain:@"securityd"
151 if(status != errSecSuccess) {
152 CFReleaseNull(results);
162 + (BOOL)storeOtagonKey:(NSData*)keyData
163 octagonKeyType:(OctagonKeyType)octagonKeyType
164 restoredPeerID:(NSString*)restoredPeerID
165 escrowSigningPubKeyHash:(NSString*)escrowSigningPubKeyHash
166 error:(NSError**)error
168 NSNumber *keyType = [[NSNumber alloc]initWithInt:octagonKeyType];
170 NSDictionary* query = @{
171 (id)kSecClass : (id)kSecClassInternetPassword,
172 (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked,
173 (id)kSecUseDataProtectionKeychain : @YES,
174 (id)kSecAttrLabel : escrowSigningPubKeyHash,
175 (id)kSecAttrAccount : restoredPeerID,
176 (id)kSecAttrType : keyType,
177 (id)kSecAttrServer : (octagonKeyType == 1) ? @"Octagon Signing Key" : @"Octagon Encryption Key",
178 (id)kSecAttrAccessGroup: @"com.apple.security.ckks",
179 (id)kSecAttrSynchronizable : (id)kCFBooleanFalse,
180 (id)kSecValueData : keyData,
182 return [OTIdentity setKeyMaterialInKeychain:query error:error];
186 +(BOOL) storeOctagonIdentityIntoKeychain:(_SFECKeyPair *)restoredSigningKey
187 restoredEncryptionKey:(_SFECKeyPair *)restoredEncryptionKey
188 escrowSigningPubKeyHash:(NSString *)escrowSigningPubKeyHash
189 restoredPeerID:(NSString *)peerID
190 error:(NSError**)error
192 NSError* localError = nil;
194 BOOL result = [OTIdentity storeOtagonKey:[restoredSigningKey keyData] octagonKeyType:OctagonSigningKey restoredPeerID:peerID escrowSigningPubKeyHash:escrowSigningPubKeyHash error:&localError];
195 if(!result || localError){
196 secerror("octagon: could not store octagon signing key in keychain:%@", localError);
202 result = [OTIdentity storeOtagonKey:[restoredEncryptionKey keyData] octagonKeyType:OctagonEncryptionKey restoredPeerID:peerID escrowSigningPubKeyHash:escrowSigningPubKeyHash error:&localError];
203 if(!result || localError){
204 secerror("octagon: could not store octagon encryption key in keychain:%@", localError);