/ keychain / SecureObjectSync / SOSRingTypes.m
SOSRingTypes.m
  1  /*
  2   * Copyright (c) 2015-2016 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  //
 25  //  SOSRingTypes.c
 26  //
 27  
 28  #include "SOSRing.h"
 29  #include "SOSRingTypes.h"
 30  #include "SOSRingBasic.h"
 31  #include "SOSRingBackup.h"
 32  #include "SOSRingRecovery.h"
 33  #include "keychain/SecureObjectSync/SOSAccountPriv.h"
 34  #include "keychain/SecureObjectSync/SOSInternal.h"
 35  #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
 36  #include <AssertMacros.h>
 37  
 38  // These need to track the ring type enums in SOSRingTypes.h
 39  static ringFuncs ringTypes[] = {
 40      &basic,     // kSOSRingBase
 41      &backup,    // kSOSRingBackup
 42      NULL,       // kSOSRingPeerKeyed
 43      NULL,       // kSOSRingEntropyKeyed
 44      NULL,       // kSOSRingPKKeyed
 45      &recovery,  // kSOSRingRecovery
 46  };
 47  static const size_t typecount = sizeof(ringTypes) / sizeof(ringFuncs);
 48  
 49  static bool SOSRingValidType(SOSRingType type) {
 50      if(type >= typecount || ringTypes[type] == NULL) return false;
 51      return true;
 52  }
 53  
 54  // MARK: Exported Functions
 55  
 56  
 57  SOSRingRef SOSRingCreate(CFStringRef name, CFStringRef myPeerID, SOSRingType type, CFErrorRef *error) {
 58      if(!SOSRingValidType(type)){
 59          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
 60          return NULL;
 61      }
 62      if(!(ringTypes[type]->sosRingCreate)){
 63          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
 64          return NULL;
 65      }
 66      return ringTypes[type]->sosRingCreate(name, myPeerID, error);
 67  }
 68  
 69  bool SOSRingResetToEmpty(SOSRingRef ring, CFStringRef myPeerID, CFErrorRef *error) {
 70      SOSRingAssertStable(ring);
 71      SOSRingType type = SOSRingGetType(ring);
 72      if(!SOSRingValidType(type)){
 73          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
 74          return false;
 75      }
 76      if(!ringTypes[type]->sosRingResetToEmpty){
 77          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
 78          return false;
 79      }
 80      return ringTypes[type]->sosRingResetToEmpty(ring, myPeerID, error);
 81  }
 82  
 83  bool SOSRingGenerationSign(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
 84      SOSRingAssertStable(ring);
 85      SOSRingType type = SOSRingGetType(ring);
 86      if(!(SOSRingValidType(type))){
 87          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
 88          return false;
 89      }
 90      if(!(ringTypes[type]->sosRingGenerationSign)){
 91          return true;
 92      }
 93      return ringTypes[type]->sosRingGenerationSign(ring, user_privkey, requestor, error);
 94  }
 95  
 96  bool SOSRingConcordanceSign(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
 97      SOSRingAssertStable(ring);
 98      SOSRingType type = SOSRingGetType(ring);
 99      if(!(SOSRingValidType(type))){
100          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
101          return false;
102      }
103      if(!(ringTypes[type]->sosRingConcordanceSign)){
104          return true;
105      }
106      return ringTypes[type]->sosRingConcordanceSign(ring, requestor, error);
107  }
108  
109  SOSConcordanceStatus SOSRingConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef peers,
110                                               SOSRingRef knownRing, SOSRingRef proposedRing,
111                                               SecKeyRef knownPubkey, SecKeyRef userPubkey,
112                                               CFStringRef excludePeerID, CFErrorRef *error) {
113      SOSRingAssertStable(knownRing);
114      SOSRingAssertStable(proposedRing);
115      SOSRingType type1 = SOSRingGetType(knownRing);
116      SOSRingType type2 = SOSRingGetType(proposedRing);
117      if(!(SOSRingValidType(type1))){
118          return kSOSConcordanceError;
119      }
120      if(!(SOSRingValidType(type2))){
121          return kSOSConcordanceError;
122      }
123      if((type1 != type2)){
124          return kSOSConcordanceError;
125      }
126  
127      secnotice("ring", "concordance trust (%s)", ringTypes[type1]->typeName);
128      secnotice("ring", "    knownRing: %@", knownRing);
129      secnotice("ring", " proposedRing: %@", proposedRing);
130      CFStringRef knownKeyID = SOSCopyIDOfKeyWithLength(knownPubkey, 8, NULL);
131      CFStringRef userKeyID = SOSCopyIDOfKeyWithLength(userPubkey, 8, NULL);
132      CFStringRef mypeerSPID = CFStringCreateTruncatedCopy(excludePeerID, 8);
133      
134      secnotice("ring", "knownkey: %@ userkey: %@ myPeerID: %@", knownKeyID, userKeyID, mypeerSPID);
135      CFReleaseNull(knownKeyID);
136      CFReleaseNull(userKeyID);
137      CFReleaseNull(mypeerSPID);
138  
139      if(!(ringTypes[type1]->sosRingConcordanceTrust)){
140          return kSOSConcordanceError;
141      }
142      return ringTypes[type1]->sosRingConcordanceTrust(me, peers, knownRing, proposedRing, knownPubkey, userPubkey, excludePeerID, error);
143  }
144  
145  bool SOSRingAccept(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
146      SOSRingAssertStable(ring);
147      SOSRingType type = SOSRingGetType(ring);
148      if(!(SOSRingValidType(type))){
149          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
150          return false;
151      }
152      if(!(ringTypes[type]->sosRingAccept)){
153           return true;
154      }
155      return ringTypes[type]->sosRingAccept(ring, user_privkey, requestor, error);
156  }
157  
158  bool SOSRingReject(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
159      SOSRingAssertStable(ring);
160      SOSRingType type = SOSRingGetType(ring);
161      if(!(SOSRingValidType(type))){
162          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
163          return false;
164      }
165      if(!(ringTypes[type]->sosRingReject)){
166          return true;
167      }
168      return ringTypes[type]->sosRingReject(ring, user_privkey, requestor, error);
169  }
170  
171  bool SOSRingSetPayload(SOSRingRef ring, SecKeyRef user_privkey, CFDataRef payload, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
172      SOSRingAssertStable(ring);
173      SOSRingType type = SOSRingGetType(ring);
174      if(!(SOSRingValidType(type))){
175          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
176          return false;
177      }
178      if(!(ringTypes[type]->sosRingSetPayload)){
179          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
180          return false;
181      }
182      return ringTypes[type]->sosRingSetPayload(ring, user_privkey, payload, requestor, error);
183  }
184  
185  CFDataRef SOSRingGetPayload(SOSRingRef ring, CFErrorRef *error) {
186      SOSRingAssertStable(ring);
187      SOSRingType type = SOSRingGetType(ring);
188      if(!SOSRingValidType(type)){
189          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
190          return NULL;
191      }
192      if(!ringTypes[type]->sosRingGetPayload){
193          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
194          return NULL;
195      };
196      return ringTypes[type]->sosRingGetPayload(ring, error);
197  }
198  
199  CFSetRef SOSRingGetBackupViewset(SOSRingRef ring, CFErrorRef *error) {
200      SOSRingAssertStable(ring);
201      SOSRingType type = SOSRingGetType(ring);
202      if(kSOSRingBackup != type){
203          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error);
204          return NULL;
205      }
206      return SOSRingGetBackupViewset_Internal(ring);
207  }
208  
209  // This returns one string with the view for the ring - we never used multi-view rings
210  CFStringRef SOSRingGetBackupView(SOSRingRef ring, CFErrorRef *error) {
211      __block CFStringRef result = NULL;
212      CFSetRef allTheViews = SOSRingGetBackupViewset(ring, error);
213      if(allTheViews) {
214          if(CFSetGetCount(allTheViews) == 1) {
215              CFSetForEach(allTheViews, ^(const void *value) {
216                  result = asString(value, error);
217              });
218          }
219      } else {
220          SOSCreateError(kSOSErrorParam, CFSTR("Wrong set count for one return"), NULL, error);
221      }
222      return result;
223  }
224  
225  static bool isBackupRing(SOSRingRef ring, CFErrorRef *error) {
226      SOSRingType type = SOSRingGetType(ring);
227      if(kSOSRingBackup != type){
228          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error);
229          return false;
230      }
231      return true;
232  }
233  
234  bool SOSRingSetBackupKeyBag(SOSRingRef ring, SOSFullPeerInfoRef fpi, CFSetRef viewSet, SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
235      SOSRingAssertStable(ring);
236      CFDataRef bskb_as_data = NULL;
237      bool result = false;
238      if(!isBackupRing(ring, error)){
239          CFReleaseNull(bskb_as_data);
240          return result;
241      }
242  
243      bskb_as_data = SOSBSKBCopyEncoded(bskb, error);
244      result = bskb_as_data &&
245               SOSRingSetBackupViewset_Internal(ring, viewSet) &&
246               SOSRingSetPayload(ring, NULL, bskb_as_data, fpi, error);
247      CFReleaseNull(bskb_as_data);
248      return result;
249  }
250  
251  SOSBackupSliceKeyBagRef SOSRingCopyBackupSliceKeyBag(SOSRingRef ring, CFErrorRef *error) {
252      SOSRingAssertStable(ring);
253  
254      CFDataRef bskb_as_data = NULL;
255      SOSBackupSliceKeyBagRef result = NULL;
256      if(!isBackupRing(ring, error)){
257          return result;
258      }
259  
260      bskb_as_data = SOSRingGetPayload(ring, error);
261      if(!bskb_as_data){
262          return result;
263      }
264      result = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, bskb_as_data, error);
265      return result;
266  }
267  
268  bool SOSRingPKTrusted(SOSRingRef ring, SecKeyRef pubkey, CFErrorRef *error) {
269      SOSRingAssertStable(ring);
270      SOSRingType type = SOSRingGetType(ring);
271      if(!(SOSRingValidType(type))){
272          SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
273          return false;
274      };
275      return SOSRingVerify(ring, pubkey, error);
276  }
277  
278  bool SOSRingPeerTrusted(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
279      bool retval = false;
280      SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(requestor);
281      SecKeyRef pubkey = SOSPeerInfoCopyPubKey(pi, error);
282      require_quiet(pubkey, exit);
283      retval = SOSRingPKTrusted(ring, pubkey, error);
284  exit:
285      CFReleaseNull(pubkey);
286      return retval;
287  }