]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2013-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 | ||
b54c578e | 24 | #include "keychain/SecureObjectSync/SOSKVSKeys.h" |
d8f41ccd | 25 | #include <utilities/SecCFWrappers.h> |
b54c578e | 26 | #include "keychain/SecureObjectSync/SOSAccountPriv.h" |
5c19dc3a | 27 | #include <CoreFoundation/CFDate.h> |
d8f41ccd A |
28 | |
29 | void AppendCircleKeyName(CFMutableArrayRef array, CFStringRef name) { | |
30 | CFStringRef circle_key = SOSCircleKeyCreateWithName(name, NULL); | |
31 | CFArrayAppendValue(array, circle_key); | |
32 | CFReleaseNull(circle_key); | |
33 | } | |
34 | ||
35 | // | |
36 | // | |
37 | // MARK: KVS Keys | |
38 | // TODO: Handle '|' and "¬" in other strings. | |
39 | // | |
40 | const CFStringRef kSOSKVSKeyParametersKey = CFSTR(">KeyParameters"); | |
41 | const CFStringRef kSOSKVSInitialSyncKey = CFSTR("^InitialSync"); | |
42 | const CFStringRef kSOSKVSAccountChangedKey = CFSTR("^AccountChanged"); | |
5c19dc3a A |
43 | const CFStringRef kSOSKVSRequiredKey = CFSTR("^Required"); |
44 | const CFStringRef kSOSKVSOfficialDSIDKey = CFSTR("^OfficialDSID"); | |
866f8763 A |
45 | const CFStringRef kSOSKVSLastCleanupTimestampKey = CFSTR("tLastKVSKeyCleanup"); |
46 | const CFStringRef kSOSKVSOTRConfigVersion = CFSTR("OTRConfigVersion"); | |
47 | const CFStringRef kSOSKVSWroteLastKeyParams = CFSTR("WroteLastKeyParams"); | |
5c19dc3a A |
48 | const CFStringRef kSOSKVSDebugScope = CFSTR("^DebugScope"); |
49 | ||
5c19dc3a A |
50 | const CFStringRef sRingPrefix = CFSTR("~"); |
51 | const CFStringRef sDebugInfoPrefix = CFSTR("dbg-"); | |
d8f41ccd A |
52 | |
53 | const CFStringRef sWarningPrefix = CFSTR("!"); | |
d8f41ccd A |
54 | const CFStringRef sCirclePrefix = CFSTR("o"); |
55 | const CFStringRef sRetirementPrefix = CFSTR("-"); | |
5c19dc3a | 56 | const CFStringRef sLastKeyParametersPushedPrefix = CFSTR("k"); |
d8f41ccd A |
57 | const CFStringRef sCircleSeparator = CFSTR("|"); |
58 | const CFStringRef sFromToSeparator = CFSTR(":"); | |
59 | ||
60 | static CFStringRef copyStringEndingIn(CFMutableStringRef in, CFStringRef token) { | |
61 | if(token == NULL) return CFStringCreateCopy(NULL, in); | |
62 | CFRange tokenAt = CFStringFind(in, token, 0); | |
63 | if(tokenAt.location == kCFNotFound) return NULL; | |
64 | CFStringRef retval = CFStringCreateWithSubstring(NULL, in, CFRangeMake(0, tokenAt.location)); | |
65 | CFStringDelete(in, CFRangeMake(0, tokenAt.location+1)); | |
66 | return retval; | |
67 | } | |
68 | ||
fa7225c8 | 69 | SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key) { |
d8f41ccd A |
70 | SOSKVSKeyType retval = kUnknownKey; |
71 | ||
72 | if(CFStringHasPrefix(key, sCirclePrefix)) retval = kCircleKey; | |
5c19dc3a | 73 | else if (CFStringHasPrefix(key, sRingPrefix)) retval = kRingKey; |
d8f41ccd A |
74 | else if(CFStringHasPrefix(key, sRetirementPrefix)) retval = kRetirementKey; |
75 | else if(CFStringHasPrefix(key, kSOSKVSKeyParametersKey)) retval = kParametersKey; | |
76 | else if(CFStringHasPrefix(key, kSOSKVSInitialSyncKey)) retval = kInitialSyncKey; | |
77 | else if(CFStringHasPrefix(key, kSOSKVSAccountChangedKey)) retval = kAccountChangedKey; | |
5c19dc3a | 78 | else if(CFStringHasPrefix(key, sDebugInfoPrefix)) retval = kDebugInfoKey; |
5c19dc3a | 79 | else if(CFStringHasPrefix(key, sLastKeyParametersPushedPrefix)) retval = kLastKeyParameterKey; |
d8f41ccd | 80 | else retval = kMessageKey; |
fa7225c8 A |
81 | |
82 | return retval; | |
83 | } | |
84 | ||
85 | bool SOSKVSKeyParse(SOSKVSKeyType keyType, CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to) { | |
86 | bool retval = true; | |
d8f41ccd | 87 | |
fa7225c8 | 88 | switch(keyType) { |
d8f41ccd A |
89 | case kCircleKey: |
90 | if (circle) { | |
91 | CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); | |
92 | *circle = CFStringCreateWithSubstring(NULL, key, fromRange); | |
93 | } | |
94 | break; | |
95 | case kMessageKey: { | |
96 | CFStringRef mCircle = NULL; | |
97 | CFStringRef mFrom = NULL; | |
98 | CFStringRef mTo = NULL; | |
99 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
100 | ||
101 | if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
102 | ((mFrom = copyStringEndingIn(keycopy, sFromToSeparator)) != NULL) && | |
103 | (CFStringGetLength(mFrom) > 0) ) { | |
104 | mTo = copyStringEndingIn(keycopy, NULL); | |
105 | if (circle && mCircle) *circle = CFStringCreateCopy(NULL, mCircle); | |
106 | if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom); | |
107 | if (to && mTo) *to = CFStringCreateCopy(NULL, mTo); | |
108 | } else { | |
fa7225c8 | 109 | retval = false; |
d8f41ccd A |
110 | } |
111 | CFReleaseNull(mCircle); | |
112 | CFReleaseNull(mFrom); | |
113 | CFReleaseNull(mTo); | |
114 | CFReleaseNull(keycopy); | |
115 | } | |
116 | break; | |
117 | case kRetirementKey: { | |
118 | CFStringRef mCircle = NULL; | |
119 | CFStringRef mPeer = NULL; | |
120 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
121 | CFStringDelete(keycopy, CFRangeMake(0, 1)); | |
122 | if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
123 | ((mPeer = copyStringEndingIn(keycopy, NULL)) != NULL)) { | |
124 | if (circle) *circle = CFStringCreateCopy(NULL, mCircle); | |
125 | if (from) *from = CFStringCreateCopy(NULL, mPeer); | |
126 | } else { | |
fa7225c8 | 127 | retval = false; |
d8f41ccd | 128 | } |
d8f41ccd A |
129 | CFReleaseNull(mCircle); |
130 | CFReleaseNull(mPeer); | |
131 | CFReleaseNull(keycopy); | |
132 | } | |
133 | break; | |
5c19dc3a A |
134 | case kRingKey: |
135 | if (ring) { | |
136 | CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); | |
137 | *ring = CFStringCreateWithSubstring(NULL, key, fromRange); | |
138 | } | |
139 | break; | |
5c19dc3a A |
140 | case kDebugInfoKey: |
141 | /* piggybacking on peerinfo */ | |
142 | if (peerInfo) { | |
143 | CFRange dbgRange = CFRangeMake(CFStringGetLength(sDebugInfoPrefix), | |
144 | CFStringGetLength(key)-CFStringGetLength(sDebugInfoPrefix)); | |
145 | *peerInfo = CFStringCreateWithSubstring(NULL, key, dbgRange); | |
146 | } | |
147 | break; | |
d8f41ccd A |
148 | case kAccountChangedKey: |
149 | case kParametersKey: | |
150 | case kInitialSyncKey: | |
151 | case kUnknownKey: | |
fa7225c8 | 152 | break; |
5c19dc3a | 153 | case kLastKeyParameterKey: |
fa7225c8 A |
154 | if(from) { |
155 | CFStringRef mPrefix = NULL; | |
156 | CFStringRef mFrom = NULL; | |
157 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
158 | ||
159 | if( ((mPrefix = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
160 | ((mFrom = copyStringEndingIn(keycopy, NULL)) != NULL)) { | |
161 | if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom); | |
162 | } else { | |
163 | retval = false; | |
164 | } | |
165 | CFReleaseNull(mPrefix); | |
166 | CFReleaseNull(mFrom); | |
167 | CFReleaseNull(keycopy); | |
168 | } | |
169 | break; | |
5c19dc3a | 170 | case kLastCircleKey: |
fa7225c8 A |
171 | if (circle && from) { |
172 | CFStringRef mCircle = NULL; | |
173 | CFStringRef mFrom = NULL; | |
174 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
175 | ||
176 | if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
177 | ((mFrom = copyStringEndingIn(keycopy, NULL)) != NULL)) { | |
178 | if (circle && mCircle) *circle = CFStringCreateCopy(NULL, mCircle); | |
179 | if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom); | |
180 | } else { | |
181 | retval = false; | |
182 | } | |
183 | CFReleaseNull(mCircle); | |
184 | CFReleaseNull(mFrom); | |
185 | CFReleaseNull(keycopy); | |
186 | } | |
187 | ||
d8f41ccd A |
188 | break; |
189 | } | |
d8f41ccd A |
190 | return retval; |
191 | } | |
192 | ||
fa7225c8 | 193 | SOSKVSKeyType SOSKVSKeyGetKeyTypeAndParse(CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to) |
d8f41ccd | 194 | { |
fa7225c8 A |
195 | SOSKVSKeyType retval = SOSKVSKeyGetKeyType(key); |
196 | bool parsed = SOSKVSKeyParse(retval, key, circle, peerInfo, ring, backupName, from, to); | |
197 | if(!parsed) retval = kUnknownKey; | |
198 | ||
199 | return retval; | |
d8f41ccd A |
200 | } |
201 | ||
fa7225c8 | 202 | |
d8f41ccd A |
203 | CFStringRef SOSCircleKeyCreateWithCircle(SOSCircleRef circle, CFErrorRef *error) |
204 | { | |
205 | return SOSCircleKeyCreateWithName(SOSCircleGetName(circle), error); | |
206 | } | |
207 | ||
208 | ||
209 | CFStringRef SOSCircleKeyCreateWithName(CFStringRef circleName, CFErrorRef *error) | |
210 | { | |
211 | if(!circleName) return NULL; | |
212 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sCirclePrefix, circleName); | |
213 | } | |
214 | ||
5c19dc3a A |
215 | CFStringRef SOSRingKeyCreateWithName(CFStringRef ring_name, CFErrorRef *error) |
216 | { | |
217 | if(!ring_name) return NULL; | |
218 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sRingPrefix, ring_name); | |
219 | } | |
220 | ||
d8f41ccd A |
221 | CFStringRef SOSCircleKeyCopyCircleName(CFStringRef key, CFErrorRef *error) |
222 | { | |
223 | CFStringRef circleName = NULL; | |
224 | ||
5c19dc3a | 225 | if (kCircleKey != SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL, NULL, NULL, NULL)) { |
d8f41ccd A |
226 | SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find circle name in key '%@'"), key); |
227 | ||
228 | CFReleaseNull(circleName); | |
229 | } | |
230 | ||
231 | return circleName; | |
232 | } | |
233 | ||
234 | CFStringRef SOSMessageKeyCopyCircleName(CFStringRef key, CFErrorRef *error) | |
235 | { | |
236 | CFStringRef circleName = NULL; | |
237 | ||
5c19dc3a | 238 | if (SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL, NULL, NULL, NULL) != kMessageKey) { |
d8f41ccd A |
239 | SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find circle name in key '%@'"), key); |
240 | ||
241 | CFReleaseNull(circleName); | |
242 | } | |
243 | return circleName; | |
244 | } | |
245 | ||
246 | CFStringRef SOSMessageKeyCopyFromPeerName(CFStringRef messageKey, CFErrorRef *error) | |
247 | { | |
248 | CFStringRef fromPeer = NULL; | |
249 | ||
5c19dc3a | 250 | if (SOSKVSKeyGetKeyTypeAndParse(messageKey, NULL, NULL, NULL, NULL, &fromPeer, NULL) != kMessageKey) { |
d8f41ccd A |
251 | SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find from peer in key '%@'"), messageKey); |
252 | ||
253 | CFReleaseNull(fromPeer); | |
254 | } | |
255 | return fromPeer; | |
256 | } | |
257 | ||
258 | CFStringRef SOSMessageKeyCreateWithCircleNameAndPeerNames(CFStringRef circleName, CFStringRef from_peer_name, CFStringRef to_peer_name) | |
259 | { | |
260 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@%@"), | |
261 | circleName, sCircleSeparator, from_peer_name, sFromToSeparator, to_peer_name); | |
262 | } | |
263 | ||
264 | CFStringRef SOSMessageKeyCreateWithCircleAndPeerNames(SOSCircleRef circle, CFStringRef from_peer_name, CFStringRef to_peer_name) | |
265 | { | |
266 | return SOSMessageKeyCreateWithCircleNameAndPeerNames(SOSCircleGetName(circle), from_peer_name, to_peer_name); | |
267 | } | |
268 | ||
269 | CFStringRef SOSMessageKeyCreateWithCircleAndPeerInfos(SOSCircleRef circle, SOSPeerInfoRef from_peer, SOSPeerInfoRef to_peer) | |
270 | { | |
271 | return SOSMessageKeyCreateWithCircleAndPeerNames(circle, SOSPeerInfoGetPeerID(from_peer), SOSPeerInfoGetPeerID(to_peer)); | |
272 | } | |
273 | ||
866f8763 | 274 | CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSMessage* transport, CFStringRef myName, CFStringRef peer_name){ |
d8f41ccd | 275 | CFErrorRef error = NULL; |
866f8763 A |
276 | |
277 | CFStringRef circleName = [transport SOSTransportMessageGetCircleName]; | |
278 | CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, peer_name, myName); | |
d8f41ccd A |
279 | CFReleaseSafe(error); |
280 | return result; | |
281 | } | |
282 | ||
866f8763 | 283 | CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSMessage* transport, CFStringRef myID, CFStringRef peer_name) { |
d8f41ccd | 284 | CFErrorRef error = NULL; |
866f8763 A |
285 | |
286 | CFStringRef circleName = [transport SOSTransportMessageGetCircleName]; | |
287 | ||
288 | CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, myID, peer_name); | |
d8f41ccd A |
289 | CFReleaseSafe(error); |
290 | return result; | |
291 | } | |
292 | ||
293 | CFStringRef SOSRetirementKeyCreateWithCircleNameAndPeer(CFStringRef circle_name, CFStringRef retirement_peer_name) | |
294 | { | |
295 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), | |
296 | sRetirementPrefix, circle_name, sCircleSeparator, retirement_peer_name); | |
297 | } | |
298 | ||
5c19dc3a A |
299 | CFStringRef SOSRingKeyCreateWithRingName(CFStringRef ring_name) |
300 | { | |
301 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), | |
302 | sRingPrefix, ring_name); | |
303 | } | |
304 | ||
d8f41ccd A |
305 | CFStringRef SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle, CFStringRef retirement_peer_name) |
306 | { | |
307 | return SOSRetirementKeyCreateWithCircleNameAndPeer(SOSCircleGetName(circle), retirement_peer_name); | |
308 | } | |
309 | ||
ecaf5866 A |
310 | static CFStringRef SOSAccountCreateCompactDescription(SOSAccount* a) { |
311 | ||
312 | CFStringRef gestaltDescription = CFDictionaryCopySuperCompactDescription((__bridge CFDictionaryRef)(a.gestalt)); | |
313 | ||
314 | CFStringRef result = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), gestaltDescription); | |
315 | ||
316 | CFReleaseNull(gestaltDescription); | |
317 | ||
318 | return result; | |
319 | } | |
320 | ||
5c19dc3a A |
321 | //should be >KeyParameters|ourPeerID |
322 | CFStringRef SOSLastKeyParametersPushedKeyCreateWithPeerID(CFStringRef peerID){ | |
323 | ||
324 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), | |
325 | sLastKeyParametersPushedPrefix,kSOSKVSKeyParametersKey, sCircleSeparator, peerID); | |
326 | } | |
327 | ||
328 | ||
329 | //should be >KeyParameters|ourPeerID | |
866f8763 | 330 | CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccount* account){ |
5c19dc3a A |
331 | |
332 | CFStringRef gestaltInfo = SOSAccountCreateCompactDescription(account); | |
333 | CFStringRef key= CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), | |
334 | sLastKeyParametersPushedPrefix, kSOSKVSKeyParametersKey, sCircleSeparator, gestaltInfo); | |
335 | CFReleaseNull(gestaltInfo); | |
336 | return key; | |
337 | } | |
338 | ||
339 | CFStringRef SOSDebugInfoKeyCreateWithTypeName(CFStringRef type_name) | |
340 | { | |
341 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), | |
342 | sDebugInfoPrefix, type_name); | |
343 | } | |
344 |