/ keychain / SecureObjectSync / SOSKVSKeys.m
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