SOSKVSKeys.m
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 24 #include "keychain/SecureObjectSync/SOSKVSKeys.h" 25 #include <utilities/SecCFWrappers.h> 26 #include "keychain/SecureObjectSync/SOSAccountPriv.h" 27 #include <CoreFoundation/CFDate.h> 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"); 43 const CFStringRef kSOSKVSRequiredKey = CFSTR("^Required"); 44 const CFStringRef kSOSKVSOfficialDSIDKey = CFSTR("^OfficialDSID"); 45 const CFStringRef kSOSKVSLastCleanupTimestampKey = CFSTR("tLastKVSKeyCleanup"); 46 const CFStringRef kSOSKVSOTRConfigVersion = CFSTR("OTRConfigVersion"); 47 const CFStringRef kSOSKVSWroteLastKeyParams = CFSTR("WroteLastKeyParams"); 48 const CFStringRef kSOSKVSDebugScope = CFSTR("^DebugScope"); 49 50 const CFStringRef sRingPrefix = CFSTR("~"); 51 const CFStringRef sDebugInfoPrefix = CFSTR("dbg-"); 52 53 const CFStringRef sWarningPrefix = CFSTR("!"); 54 const CFStringRef sCirclePrefix = CFSTR("o"); 55 const CFStringRef sRetirementPrefix = CFSTR("-"); 56 const CFStringRef sLastKeyParametersPushedPrefix = CFSTR("k"); 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 69 SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key) { 70 SOSKVSKeyType retval = kUnknownKey; 71 72 if(CFStringHasPrefix(key, sCirclePrefix)) retval = kCircleKey; 73 else if (CFStringHasPrefix(key, sRingPrefix)) retval = kRingKey; 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; 78 else if(CFStringHasPrefix(key, sDebugInfoPrefix)) retval = kDebugInfoKey; 79 else if(CFStringHasPrefix(key, sLastKeyParametersPushedPrefix)) retval = kLastKeyParameterKey; 80 else retval = kMessageKey; 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; 87 88 switch(keyType) { 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 { 109 retval = false; 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 { 127 retval = false; 128 } 129 CFReleaseNull(mCircle); 130 CFReleaseNull(mPeer); 131 CFReleaseNull(keycopy); 132 } 133 break; 134 case kRingKey: 135 if (ring) { 136 CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); 137 *ring = CFStringCreateWithSubstring(NULL, key, fromRange); 138 } 139 break; 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; 148 case kAccountChangedKey: 149 case kParametersKey: 150 case kInitialSyncKey: 151 case kUnknownKey: 152 break; 153 case kLastKeyParameterKey: 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; 170 case kLastCircleKey: 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 188 break; 189 } 190 return retval; 191 } 192 193 SOSKVSKeyType SOSKVSKeyGetKeyTypeAndParse(CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to) 194 { 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; 200 } 201 202 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 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 221 CFStringRef SOSCircleKeyCopyCircleName(CFStringRef key, CFErrorRef *error) 222 { 223 CFStringRef circleName = NULL; 224 225 if (kCircleKey != SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL, NULL, NULL, NULL)) { 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 238 if (SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL, NULL, NULL, NULL) != kMessageKey) { 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 250 if (SOSKVSKeyGetKeyTypeAndParse(messageKey, NULL, NULL, NULL, NULL, &fromPeer, NULL) != kMessageKey) { 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 274 CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSMessage* transport, CFStringRef myName, CFStringRef peer_name){ 275 CFErrorRef error = NULL; 276 277 CFStringRef circleName = [transport SOSTransportMessageGetCircleName]; 278 CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, peer_name, myName); 279 CFReleaseSafe(error); 280 return result; 281 } 282 283 CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSMessage* transport, CFStringRef myID, CFStringRef peer_name) { 284 CFErrorRef error = NULL; 285 286 CFStringRef circleName = [transport SOSTransportMessageGetCircleName]; 287 288 CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, myID, peer_name); 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 299 CFStringRef SOSRingKeyCreateWithRingName(CFStringRef ring_name) 300 { 301 return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), 302 sRingPrefix, ring_name); 303 } 304 305 CFStringRef SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle, CFStringRef retirement_peer_name) 306 { 307 return SOSRetirementKeyCreateWithCircleNameAndPeer(SOSCircleGetName(circle), retirement_peer_name); 308 } 309 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 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 330 CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccount* account){ 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