]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSCurrentKeyPointer.m
Security-58286.70.7.tar.gz
[apple/security.git] / keychain / ckks / CKKSCurrentKeyPointer.m
1 /*
2 * Copyright (c) 2017 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 #import "CKKSCurrentKeyPointer.h"
25
26 #if OCTAGON
27
28 @implementation CKKSCurrentKeyPointer
29
30 - (instancetype)initForClass:(CKKSKeyClass*)keyclass
31 currentKeyUUID:(NSString*)currentKeyUUID
32 zoneID:(CKRecordZoneID*)zoneID
33 encodedCKRecord: (NSData*) encodedrecord
34 {
35 if(self = [super initWithCKRecordType: SecCKRecordCurrentKeyType encodedCKRecord:encodedrecord zoneID:zoneID]) {
36 _keyclass = keyclass;
37 _currentKeyUUID = currentKeyUUID;
38
39 if(self.currentKeyUUID == nil) {
40 secerror("ckkscurrentkey: created a CKKSCurrentKey with a nil currentKeyUUID. Why?");
41 }
42 }
43 return self;
44 }
45
46 - (NSString*)description {
47 return [NSString stringWithFormat:@"<CKKSCurrentKeyPointer(%@) %@: %@>", self.zoneID.zoneName, self.keyclass, self.currentKeyUUID];
48 }
49
50 - (instancetype)copyWithZone:(NSZone*)zone {
51 CKKSCurrentKeyPointer* copy = [super copyWithZone:zone];
52 copy.keyclass = [self.keyclass copyWithZone:zone];
53 copy.currentKeyUUID = [self.currentKeyUUID copyWithZone:zone];
54 return copy;
55 }
56 - (BOOL)isEqual: (id) object {
57 if(![object isKindOfClass:[CKKSCurrentKeyPointer class]]) {
58 return NO;
59 }
60
61 CKKSCurrentKeyPointer* obj = (CKKSCurrentKeyPointer*) object;
62
63 return ([self.zoneID isEqual: obj.zoneID] &&
64 ((self.currentKeyUUID == nil && obj.currentKeyUUID == nil) || [self.currentKeyUUID isEqual: obj.currentKeyUUID]) &&
65 ((self.keyclass == nil && obj.keyclass == nil) || [self.keyclass isEqual:obj.keyclass]) &&
66 YES) ? YES : NO;
67 }
68
69 #pragma mark - CKKSCKRecordHolder methods
70
71 - (NSString*) CKRecordName {
72 return self.keyclass;
73 }
74
75 - (CKRecord*) updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID {
76 // The record name should already match keyclass...
77 if(![record.recordID.recordName isEqualToString: self.keyclass]) {
78 @throw [NSException
79 exceptionWithName:@"WrongCKRecordNameException"
80 reason:[NSString stringWithFormat: @"CKRecord name (%@) was not %@", record.recordID.recordName, self.keyclass]
81 userInfo:nil];
82 }
83
84 // Set the parent reference
85 record[SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: self.currentKeyUUID zoneID: zoneID] action: CKReferenceActionNone];
86 return record;
87 }
88
89 - (bool) matchesCKRecord: (CKRecord*) record {
90 if(![record.recordType isEqualToString: SecCKRecordCurrentKeyType]) {
91 return false;
92 }
93
94 if(![record.recordID.recordName isEqualToString: self.keyclass]) {
95 return false;
96 }
97
98 if(![[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqualToString: self.currentKeyUUID]) {
99 return false;
100 }
101
102 return true;
103 }
104
105 - (void) setFromCKRecord: (CKRecord*) record {
106 if(![record.recordType isEqualToString: SecCKRecordCurrentKeyType]) {
107 @throw [NSException
108 exceptionWithName:@"WrongCKRecordTypeException"
109 reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordCurrentKeyType]
110 userInfo:nil];
111 }
112
113 [self setStoredCKRecord:record];
114
115 // TODO: verify this is a real keyclass
116 self.keyclass = (CKKSKeyClass*) record.recordID.recordName;
117 self.currentKeyUUID = [record[SecCKRecordParentKeyRefKey] recordID].recordName;
118
119 if(self.currentKeyUUID == nil) {
120 secerror("ckkscurrentkey: No current key UUID in record! How/why? %@", record);
121 }
122 }
123
124 #pragma mark - Load from database
125
126 + (instancetype) fromDatabase: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
127 return [self fromDatabaseWhere: @{@"keyclass": keyclass, @"ckzone":zoneID.zoneName} error: error];
128 }
129
130 + (instancetype) tryFromDatabase: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
131 return [self tryFromDatabaseWhere: @{@"keyclass": keyclass, @"ckzone":zoneID.zoneName} error: error];
132 }
133
134 + (instancetype) forKeyClass: (CKKSKeyClass*) keyclass withKeyUUID: (NSString*) keyUUID zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
135 NSError* localerror = nil;
136 CKKSCurrentKeyPointer* current = [self tryFromDatabase: keyclass zoneID:zoneID error: &localerror];
137 if(localerror) {
138 if(error) {
139 *error = localerror;
140 }
141 return nil;
142 }
143
144 if(current) {
145 current.currentKeyUUID = keyUUID;
146 return current;
147 }
148
149 return [[CKKSCurrentKeyPointer alloc] initForClass: keyclass currentKeyUUID: keyUUID zoneID:zoneID encodedCKRecord:nil];
150 }
151
152 + (NSArray<CKKSCurrentKeyPointer*>*)all:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
153 return [self allWhere:@{@"ckzone":zoneID.zoneName} error:error];
154 }
155
156 + (bool) deleteAll:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error {
157 bool ok = [CKKSSQLDatabaseObject deleteFromTable:[self sqlTable] where: @{@"ckzone":zoneID.zoneName} connection:nil error: error];
158
159 if(ok) {
160 secdebug("ckksitem", "Deleted all %@", self);
161 } else {
162 secdebug("ckksitem", "Couldn't delete all %@: %@", self, error ? *error : @"unknown");
163 }
164 return ok;
165 }
166
167 #pragma mark - CKKSSQLDatabaseObject methods
168
169 + (NSString*) sqlTable {
170 return @"currentkeys";
171 }
172
173 + (NSArray<NSString*>*) sqlColumns {
174 return @[@"keyclass", @"currentKeyUUID", @"ckzone", @"ckrecord"];
175 }
176
177 - (NSDictionary<NSString*,NSString*>*) whereClauseToFindSelf {
178 return @{@"keyclass": self.keyclass, @"ckzone":self.zoneID.zoneName};
179 }
180
181 - (NSDictionary<NSString*,NSString*>*) sqlValues {
182 return @{@"keyclass": self.keyclass,
183 @"currentKeyUUID": CKKSNilToNSNull(self.currentKeyUUID),
184 @"ckzone": CKKSNilToNSNull(self.zoneID.zoneName),
185 @"ckrecord": CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]),
186 };
187 }
188
189 + (instancetype) fromDatabaseRow: (NSDictionary*) row {
190 return [[CKKSCurrentKeyPointer alloc] initForClass: row[@"keyclass"]
191 currentKeyUUID: [row[@"currentKeyUUID"] isEqual: [NSNull null]] ? nil : row[@"currentKeyUUID"]
192 zoneID: [[CKRecordZoneID alloc] initWithZoneName: row[@"ckzone"] ownerName:CKCurrentUserDefaultName]
193 encodedCKRecord: [[NSData alloc] initWithBase64EncodedString: row[@"ckrecord"] options:0]];
194 }
195
196 @end
197
198 @implementation CKKSCurrentKeySet
199 -(instancetype)init {
200 if((self = [super init])) {
201 }
202
203 return self;
204 }
205 -(instancetype)initForZone:(CKRecordZoneID*)zoneID {
206 if((self = [super init])) {
207 NSError* error = nil;
208 _currentTLKPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassTLK zoneID:zoneID error:&error];
209 _currentClassAPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassA zoneID:zoneID error:&error];
210 _currentClassCPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassC zoneID:zoneID error:&error];
211
212 _tlk = _currentTLKPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:_currentTLKPointer.currentKeyUUID zoneID:zoneID error:&error] : nil;
213 _classA = _currentClassAPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:_currentClassAPointer.currentKeyUUID zoneID:zoneID error:&error] : nil;
214 _classC = _currentClassCPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:_currentClassCPointer.currentKeyUUID zoneID:zoneID error:&error] : nil;
215
216 _tlkShares = [CKKSTLKShare allForUUID:_currentTLKPointer.currentKeyUUID zoneID:zoneID error:&error];
217
218 _error = error;
219
220 }
221
222 return self;
223 }
224 -(NSString*)description {
225 if(self.error) {
226 return [NSString stringWithFormat:@"<CKKSCurrentKeySet: %@:%@ %@:%@ %@:%@ %@>",
227 self.currentTLKPointer.currentKeyUUID, self.tlk,
228 self.currentClassAPointer.currentKeyUUID, self.classA,
229 self.currentClassCPointer.currentKeyUUID, self.classC,
230 self.error];
231
232 } else {
233 return [NSString stringWithFormat:@"<CKKSCurrentKeySet: %@:%@ %@:%@ %@:%@>",
234 self.currentTLKPointer.currentKeyUUID, self.tlk,
235 self.currentClassAPointer.currentKeyUUID, self.classA,
236 self.currentClassCPointer.currentKeyUUID, self.classC];
237 }
238 }
239 - (instancetype)copyWithZone:(NSZone*)zone {
240 CKKSCurrentKeySet* copy = [[[self class] alloc] init];
241 copy.currentTLKPointer = [self.currentTLKPointer copyWithZone:zone];
242 copy.currentClassAPointer = [self.currentClassAPointer copyWithZone:zone];
243 copy.currentClassCPointer = [self.currentClassCPointer copyWithZone:zone];
244 copy.tlk = [self.tlk copyWithZone:zone];
245 copy.classA = [self.classA copyWithZone:zone];
246 copy.classC = [self.classC copyWithZone:zone];
247
248 copy.error = [self.error copyWithZone:zone];
249 return copy;
250 }
251 @end
252
253 #endif // OCTAGON