2 * Copyright (c) 2013-2014 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@
24 #include <Security/SecureObjectSync/SOSKVSKeys.h>
25 #include <utilities/SecCFWrappers.h>
26 #include <Security/SecureObjectSync/SOSAccountPriv.h>
27 #include <CoreFoundation/CFDate.h>
29 void AppendCircleKeyName(CFMutableArrayRef array
, CFStringRef name
) {
30 CFStringRef circle_key
= SOSCircleKeyCreateWithName(name
, NULL
);
31 CFArrayAppendValue(array
, circle_key
);
32 CFReleaseNull(circle_key
);
38 // TODO: Handle '|' and "¬" in other strings.
40 const CFStringRef kSOSKVSKeyParametersKey
= CFSTR(">KeyParameters");
41 const CFStringRef kSOSKVSInitialSyncKey
= CFSTR("^InitialSync");
42 const CFStringRef kSOSKVSAccountChangedKey
= CFSTR("^AccountChanged");
43 const CFStringRef kSOSKVSRequiredKey
= CFSTR("^Required");
44 const CFStringRef kSOSKVSOfficialDSIDKey
= CFSTR("^OfficialDSID");
46 const CFStringRef kSOSKVSDebugScope
= CFSTR("^DebugScope");
48 const CFStringRef sPeerInfoPrefix
= CFSTR("+");
49 const CFStringRef sRingPrefix
= CFSTR("~");
50 const CFStringRef sDebugInfoPrefix
= CFSTR("dbg-");
52 const CFStringRef sWarningPrefix
= CFSTR("!");
53 const CFStringRef sAncientCirclePrefix
= CFSTR("@");
54 const CFStringRef sCirclePrefix
= CFSTR("o");
55 const CFStringRef sRetirementPrefix
= CFSTR("-");
56 const CFStringRef sLastCirclePushedPrefix
= CFSTR("p");
57 const CFStringRef sLastKeyParametersPushedPrefix
= CFSTR("k");
58 const CFStringRef sCircleSeparator
= CFSTR("|");
59 const CFStringRef sFromToSeparator
= CFSTR(":");
61 static CFStringRef
copyStringEndingIn(CFMutableStringRef in
, CFStringRef token
) {
62 if(token
== NULL
) return CFStringCreateCopy(NULL
, in
);
63 CFRange tokenAt
= CFStringFind(in
, token
, 0);
64 if(tokenAt
.location
== kCFNotFound
) return NULL
;
65 CFStringRef retval
= CFStringCreateWithSubstring(NULL
, in
, CFRangeMake(0, tokenAt
.location
));
66 CFStringDelete(in
, CFRangeMake(0, tokenAt
.location
+1));
70 SOSKVSKeyType
SOSKVSKeyGetKeyType(CFStringRef key
) {
71 SOSKVSKeyType retval
= kUnknownKey
;
73 if(CFStringHasPrefix(key
, sCirclePrefix
)) retval
= kCircleKey
;
74 else if (CFStringHasPrefix(key
, sRingPrefix
)) retval
= kRingKey
;
75 else if(CFStringHasPrefix(key
, sPeerInfoPrefix
)) retval
= kPeerInfoKey
;
76 else if(CFStringHasPrefix(key
, sRetirementPrefix
)) retval
= kRetirementKey
;
77 else if(CFStringHasPrefix(key
, kSOSKVSKeyParametersKey
)) retval
= kParametersKey
;
78 else if(CFStringHasPrefix(key
, kSOSKVSInitialSyncKey
)) retval
= kInitialSyncKey
;
79 else if(CFStringHasPrefix(key
, kSOSKVSAccountChangedKey
)) retval
= kAccountChangedKey
;
80 else if(CFStringHasPrefix(key
, sDebugInfoPrefix
)) retval
= kDebugInfoKey
;
81 else if(CFStringHasPrefix(key
, sLastCirclePushedPrefix
)) retval
= kLastCircleKey
;
82 else if(CFStringHasPrefix(key
, sLastKeyParametersPushedPrefix
)) retval
= kLastKeyParameterKey
;
83 else retval
= kMessageKey
;
88 bool SOSKVSKeyParse(SOSKVSKeyType keyType
, CFStringRef key
, CFStringRef
*circle
, CFStringRef
*peerInfo
, CFStringRef
*ring
, CFStringRef
*backupName
, CFStringRef
*from
, CFStringRef
*to
) {
94 CFRange fromRange
= CFRangeMake(1, CFStringGetLength(key
)-1);
95 *circle
= CFStringCreateWithSubstring(NULL
, key
, fromRange
);
99 CFStringRef mCircle
= NULL
;
100 CFStringRef mFrom
= NULL
;
101 CFStringRef mTo
= NULL
;
102 CFMutableStringRef keycopy
= CFStringCreateMutableCopy(NULL
, 128, key
);
104 if( ((mCircle
= copyStringEndingIn(keycopy
, sCircleSeparator
)) != NULL
) &&
105 ((mFrom
= copyStringEndingIn(keycopy
, sFromToSeparator
)) != NULL
) &&
106 (CFStringGetLength(mFrom
) > 0) ) {
107 mTo
= copyStringEndingIn(keycopy
, NULL
);
108 if (circle
&& mCircle
) *circle
= CFStringCreateCopy(NULL
, mCircle
);
109 if (from
&& mFrom
) *from
= CFStringCreateCopy(NULL
, mFrom
);
110 if (to
&& mTo
) *to
= CFStringCreateCopy(NULL
, mTo
);
114 CFReleaseNull(mCircle
);
115 CFReleaseNull(mFrom
);
117 CFReleaseNull(keycopy
);
120 case kRetirementKey
: {
121 CFStringRef mCircle
= NULL
;
122 CFStringRef mPeer
= NULL
;
123 CFMutableStringRef keycopy
= CFStringCreateMutableCopy(NULL
, 128, key
);
124 CFStringDelete(keycopy
, CFRangeMake(0, 1));
125 if( ((mCircle
= copyStringEndingIn(keycopy
, sCircleSeparator
)) != NULL
) &&
126 ((mPeer
= copyStringEndingIn(keycopy
, NULL
)) != NULL
)) {
127 if (circle
) *circle
= CFStringCreateCopy(NULL
, mCircle
);
128 if (from
) *from
= CFStringCreateCopy(NULL
, mPeer
);
132 CFReleaseNull(mCircle
);
133 CFReleaseNull(mPeer
);
134 CFReleaseNull(keycopy
);
139 CFRange fromRange
= CFRangeMake(1, CFStringGetLength(key
)-1);
140 *ring
= CFStringCreateWithSubstring(NULL
, key
, fromRange
);
145 CFRange fromRange
= CFRangeMake(1, CFStringGetLength(key
)-1);
146 *peerInfo
= CFStringCreateWithSubstring(NULL
, key
, fromRange
);
150 /* piggybacking on peerinfo */
152 CFRange dbgRange
= CFRangeMake(CFStringGetLength(sDebugInfoPrefix
),
153 CFStringGetLength(key
)-CFStringGetLength(sDebugInfoPrefix
));
154 *peerInfo
= CFStringCreateWithSubstring(NULL
, key
, dbgRange
);
157 case kAccountChangedKey
:
159 case kInitialSyncKey
:
162 case kLastKeyParameterKey
:
164 CFStringRef mPrefix
= NULL
;
165 CFStringRef mFrom
= NULL
;
166 CFMutableStringRef keycopy
= CFStringCreateMutableCopy(NULL
, 128, key
);
168 if( ((mPrefix
= copyStringEndingIn(keycopy
, sCircleSeparator
)) != NULL
) &&
169 ((mFrom
= copyStringEndingIn(keycopy
, NULL
)) != NULL
)) {
170 if (from
&& mFrom
) *from
= CFStringCreateCopy(NULL
, mFrom
);
174 CFReleaseNull(mPrefix
);
175 CFReleaseNull(mFrom
);
176 CFReleaseNull(keycopy
);
180 if (circle
&& from
) {
181 CFStringRef mCircle
= NULL
;
182 CFStringRef mFrom
= NULL
;
183 CFMutableStringRef keycopy
= CFStringCreateMutableCopy(NULL
, 128, key
);
185 if( ((mCircle
= copyStringEndingIn(keycopy
, sCircleSeparator
)) != NULL
) &&
186 ((mFrom
= copyStringEndingIn(keycopy
, NULL
)) != NULL
)) {
187 if (circle
&& mCircle
) *circle
= CFStringCreateCopy(NULL
, mCircle
);
188 if (from
&& mFrom
) *from
= CFStringCreateCopy(NULL
, mFrom
);
192 CFReleaseNull(mCircle
);
193 CFReleaseNull(mFrom
);
194 CFReleaseNull(keycopy
);
202 SOSKVSKeyType
SOSKVSKeyGetKeyTypeAndParse(CFStringRef key
, CFStringRef
*circle
, CFStringRef
*peerInfo
, CFStringRef
*ring
, CFStringRef
*backupName
, CFStringRef
*from
, CFStringRef
*to
)
204 SOSKVSKeyType retval
= SOSKVSKeyGetKeyType(key
);
205 bool parsed
= SOSKVSKeyParse(retval
, key
, circle
, peerInfo
, ring
, backupName
, from
, to
);
206 if(!parsed
) retval
= kUnknownKey
;
212 CFStringRef
SOSCircleKeyCreateWithCircle(SOSCircleRef circle
, CFErrorRef
*error
)
214 return SOSCircleKeyCreateWithName(SOSCircleGetName(circle
), error
);
218 CFStringRef
SOSCircleKeyCreateWithName(CFStringRef circleName
, CFErrorRef
*error
)
220 if(!circleName
) return NULL
;
221 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), sCirclePrefix
, circleName
);
224 CFStringRef
SOSPeerInfoKeyCreateWithName(CFStringRef peer_info_name
, CFErrorRef
*error
)
226 if(!peer_info_name
) return NULL
;
227 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), sPeerInfoPrefix
, peer_info_name
);
230 CFStringRef
SOSRingKeyCreateWithName(CFStringRef ring_name
, CFErrorRef
*error
)
232 if(!ring_name
) return NULL
;
233 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), sRingPrefix
, ring_name
);
236 CFStringRef
SOSCircleKeyCopyCircleName(CFStringRef key
, CFErrorRef
*error
)
238 CFStringRef circleName
= NULL
;
240 if (kCircleKey
!= SOSKVSKeyGetKeyTypeAndParse(key
, &circleName
, NULL
, NULL
, NULL
, NULL
, NULL
)) {
241 SOSCreateErrorWithFormat(kSOSErrorNoCircleName
, NULL
, error
, NULL
, CFSTR("Couldn't find circle name in key '%@'"), key
);
243 CFReleaseNull(circleName
);
249 CFStringRef
SOSMessageKeyCopyCircleName(CFStringRef key
, CFErrorRef
*error
)
251 CFStringRef circleName
= NULL
;
253 if (SOSKVSKeyGetKeyTypeAndParse(key
, &circleName
, NULL
, NULL
, NULL
, NULL
, NULL
) != kMessageKey
) {
254 SOSCreateErrorWithFormat(kSOSErrorNoCircleName
, NULL
, error
, NULL
, CFSTR("Couldn't find circle name in key '%@'"), key
);
256 CFReleaseNull(circleName
);
261 CFStringRef
SOSMessageKeyCopyFromPeerName(CFStringRef messageKey
, CFErrorRef
*error
)
263 CFStringRef fromPeer
= NULL
;
265 if (SOSKVSKeyGetKeyTypeAndParse(messageKey
, NULL
, NULL
, NULL
, NULL
, &fromPeer
, NULL
) != kMessageKey
) {
266 SOSCreateErrorWithFormat(kSOSErrorNoCircleName
, NULL
, error
, NULL
, CFSTR("Couldn't find from peer in key '%@'"), messageKey
);
268 CFReleaseNull(fromPeer
);
273 CFStringRef
SOSMessageKeyCreateWithCircleNameAndPeerNames(CFStringRef circleName
, CFStringRef from_peer_name
, CFStringRef to_peer_name
)
275 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@%@%@"),
276 circleName
, sCircleSeparator
, from_peer_name
, sFromToSeparator
, to_peer_name
);
279 CFStringRef
SOSMessageKeyCreateWithCircleNameAndTransportType(CFStringRef circleName
, CFStringRef transportType
)
281 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@%@%@"),
282 circleName
, sCircleSeparator
, transportType
, sFromToSeparator
, SOSTransportMessageTypeIDSV2
);
285 CFStringRef
SOSMessageKeyCreateWithCircleAndPeerNames(SOSCircleRef circle
, CFStringRef from_peer_name
, CFStringRef to_peer_name
)
287 return SOSMessageKeyCreateWithCircleNameAndPeerNames(SOSCircleGetName(circle
), from_peer_name
, to_peer_name
);
290 CFStringRef
SOSMessageKeyCreateWithCircleAndPeerInfos(SOSCircleRef circle
, SOSPeerInfoRef from_peer
, SOSPeerInfoRef to_peer
)
292 return SOSMessageKeyCreateWithCircleAndPeerNames(circle
, SOSPeerInfoGetPeerID(from_peer
), SOSPeerInfoGetPeerID(to_peer
));
295 CFStringRef
SOSMessageKeyCreateFromPeerToTransport(SOSTransportMessageRef transport
, CFStringRef peer_name
) {
296 CFErrorRef error
= NULL
;
297 SOSEngineRef engine
= SOSTransportMessageGetEngine((SOSTransportMessageRef
)transport
);
299 CFStringRef circleName
= SOSTransportMessageGetCircleName((SOSTransportMessageRef
)transport
);
300 CFStringRef my_id
= SOSEngineGetMyID(engine
);
303 secerror("cannot create message keys, SOSEngineGetMyID returned NULL");
306 CFStringRef result
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName
, peer_name
, my_id
);
307 CFReleaseSafe(error
);
311 CFStringRef
SOSMessageKeyCreateFromTransportToPeer(SOSTransportMessageRef transport
, CFStringRef peer_name
) {
312 CFErrorRef error
= NULL
;
313 SOSEngineRef engine
= SOSTransportMessageGetEngine((SOSTransportMessageRef
)transport
);
315 CFStringRef circleName
= SOSTransportMessageGetCircleName((SOSTransportMessageRef
)transport
);
316 CFStringRef my_id
= SOSEngineGetMyID(engine
);
318 CFStringRef result
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName
, my_id
, peer_name
);
319 CFReleaseSafe(error
);
323 CFStringRef
SOSRetirementKeyCreateWithCircleNameAndPeer(CFStringRef circle_name
, CFStringRef retirement_peer_name
)
325 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@%@"),
326 sRetirementPrefix
, circle_name
, sCircleSeparator
, retirement_peer_name
);
329 CFStringRef
SOSPeerInfoV2KeyCreateWithPeerName(CFStringRef peer_name
)
331 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"),
332 sPeerInfoPrefix
, peer_name
);
335 CFStringRef
SOSRingKeyCreateWithRingName(CFStringRef ring_name
)
337 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"),
338 sRingPrefix
, ring_name
);
341 CFStringRef
SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle
, CFStringRef retirement_peer_name
)
343 return SOSRetirementKeyCreateWithCircleNameAndPeer(SOSCircleGetName(circle
), retirement_peer_name
);
346 //should be poak|ourPeerID
347 CFStringRef
SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(CFStringRef circleName
, CFStringRef peerID
){
349 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@%@%@"),
350 sLastCirclePushedPrefix
, sCirclePrefix
, circleName
, sCircleSeparator
, peerID
);
353 CFStringRef
SOSLastCirclePushedKeyCreateWithAccountGestalt(SOSAccountRef account
){
354 CFStringRef gestaltInfo
= SOSAccountCreateCompactDescription(account
);
355 CFStringRef key
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"),
356 sLastCirclePushedPrefix
, sCirclePrefix
, gestaltInfo
);
357 CFReleaseNull(gestaltInfo
);
361 //should be >KeyParameters|ourPeerID
362 CFStringRef
SOSLastKeyParametersPushedKeyCreateWithPeerID(CFStringRef peerID
){
364 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@%@"),
365 sLastKeyParametersPushedPrefix
,kSOSKVSKeyParametersKey
, sCircleSeparator
, peerID
);
369 //should be >KeyParameters|ourPeerID
370 CFStringRef
SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccountRef account
){
372 CFStringRef gestaltInfo
= SOSAccountCreateCompactDescription(account
);
373 CFStringRef key
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@%@"),
374 sLastKeyParametersPushedPrefix
, kSOSKVSKeyParametersKey
, sCircleSeparator
, gestaltInfo
);
375 CFReleaseNull(gestaltInfo
);
379 CFStringRef
SOSDebugInfoKeyCreateWithTypeName(CFStringRef type_name
)
381 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"),
382 sDebugInfoPrefix
, type_name
);