/ OSX / sec / Security / SecOTRUtils.c
SecOTRUtils.c
  1  /*
  2   * Copyright (c) 2012,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  
 25  #include "SecOTR.h"
 26  #include "SecOTRIdentityPriv.h"
 27  #include "SecOTRSessionPriv.h"
 28  #include <utilities/SecCFWrappers.h>
 29  #include <utilities/SecBuffer.h>
 30  #include <stdlib.h>
 31  
 32  #include <AssertMacros.h>
 33  
 34  #include <Security/SecBase.h>
 35  #include <Security/SecItem.h>
 36  #include <Security/SecKey.h>
 37  #include <Security/SecKeyPriv.h>
 38  #include <Security/SecBase64.h>
 39  
 40  #include <TargetConditionals.h>
 41  
 42  CFStringRef sLocalErrorDomain = CFSTR("com.apple.security.otr.error");
 43  
 44  bool SecOTRCreateError(enum SecOTRError family, CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) {
 45      if (newError && !(*newError)) {
 46          const void* keys[2] = {kCFErrorDescriptionKey, kCFErrorUnderlyingErrorKey};
 47          const void* values[2] = {descriptionString, previousError};
 48          *newError = CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, (family == secOTRErrorLocal) ? sLocalErrorDomain : kCFErrorDomainOSStatus, errorCode, keys, values, (previousError != NULL) ? 2 : 1);
 49      } else {
 50          CFReleaseSafe(previousError);
 51      }
 52  
 53      return false;
 54  }
 55  
 56  OSStatus insertSize(CFIndex size, uint8_t* here)
 57  {
 58      require(size < 0xFFFF, fail);
 59      
 60      uint8_t bytes[] = { (size >> 8) & 0xFF, size & 0xFF };
 61      memcpy(here, bytes, sizeof(bytes));
 62      
 63      return errSecSuccess;
 64      
 65  fail:
 66      return errSecParam;
 67  }
 68  
 69  OSStatus appendSize(CFIndex size, CFMutableDataRef into)
 70  {
 71      require(size < 0xFFFF, fail);
 72      
 73      uint8_t bytes[] = { (size >> 8) & 0xFF, size & 0xFF };
 74      CFDataAppendBytes(into, bytes, sizeof(bytes));
 75      
 76      return errSecSuccess;
 77      
 78  fail:
 79      return errSecParam;
 80  }
 81  
 82  OSStatus readSize(const uint8_t** data, size_t* limit, uint16_t* size)
 83  {
 84      require(limit != NULL, fail);
 85      require(data != NULL, fail);
 86      require(size != NULL, fail);
 87      require(*limit > 1, fail);
 88      
 89      *size = ((uint16_t)(*data)[0]) << 8 | ((uint16_t) (*data)[1]) << 0;
 90      
 91      *limit -= 2;
 92      *data += 2;
 93      
 94      return errSecSuccess;
 95  fail:
 96      return errSecParam;
 97  }
 98  
 99  OSStatus appendSizeAndData(CFDataRef data, CFMutableDataRef appendTo)
100  {
101      OSStatus status = errSecNotAvailable;
102      
103      require_noerr(appendSize(CFDataGetLength(data), appendTo), exit);
104      CFDataAppend(appendTo, data);
105      
106      status = errSecSuccess;
107      
108  exit:
109      return status;
110  }
111  
112  OSStatus appendPublicOctetsAndSize(SecKeyRef fromKey, CFMutableDataRef appendTo)
113  {
114      OSStatus status = errSecDecode;
115      CFDataRef serializedKey = NULL;
116      
117      require_noerr(SecKeyCopyPublicBytes(fromKey, &serializedKey), exit);
118      require(serializedKey, exit);
119      
120      status = appendSizeAndData(serializedKey, appendTo);
121      
122  exit:
123      CFReleaseNull(serializedKey);
124      return status;
125  }
126  
127  OSStatus appendPublicOctets(SecKeyRef fromKey, CFMutableDataRef appendTo)
128  {
129      OSStatus status = errSecDecode;
130      CFDataRef serializedKey = NULL;
131      
132      require_noerr(SecKeyCopyPublicBytes(fromKey, &serializedKey), exit);
133      require(serializedKey, exit);
134      
135      CFDataAppend(appendTo, serializedKey);
136      
137      status = errSecSuccess;
138      
139  exit:
140      CFReleaseNull(serializedKey);
141      return status;
142  }
143  
144  
145  /* Given an EC public key in encoded form return a SecKeyRef representing
146   that key. Supported encodings are kSecKeyEncodingPkcs1. */
147  static SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator,
148                                    const uint8_t *keyData, CFIndex keyDataLength) {
149      CFDataRef tempData = CFDataCreate(kCFAllocatorDefault, keyData, keyDataLength);
150      SecKeyRef newPublicKey = SecKeyCreateFromPublicData(kCFAllocatorDefault, kSecECDSAAlgorithmID, tempData);
151  
152      CFRelease(tempData);
153      return newPublicKey;
154  }
155  
156  typedef SecKeyRef (*createFunction_t)(CFAllocatorRef allocator,
157                                        const uint8_t *keyData, CFIndex keyDataLength);
158  
159  static SecKeyRef CallCreateFunctionFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit, createFunction_t create)
160  {
161      uint16_t foundLength = 0;
162      const uint8_t* foundData = NULL;
163      
164      require(limit != NULL, fail);
165      require(data != NULL, fail);
166      
167      require_noerr(readSize(data, limit, &foundLength), fail);
168      require(foundLength <= *limit, fail);
169      
170      foundData = *data;
171      
172      *limit -= foundLength;
173      *data += foundLength;
174      
175  fail:
176      
177      return create(allocator, foundData, foundLength);
178  }
179  
180  SecKeyRef CreateECPublicKeyFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit)
181  {
182      return CallCreateFunctionFrom(allocator, data, limit, &SecKeyCreateECPublicKey);
183  }
184  
185  CFDataRef SecOTRCopyIncomingBytes(CFDataRef incomingMessage)
186  {
187      __block CFDataRef result = NULL;
188  
189      CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?');
190      CFRange headerLoc = CFDataFind(incomingMessage, header, CFRangeMake(0, CFDataGetLength(header)), 0);
191  
192      if (kCFNotFound == headerLoc.location) {
193          CFRetainAssign(result, incomingMessage);
194      } else {
195          CFDataRef footer = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("."), kCFStringEncodingUTF8, '?');
196          CFRange footerLoc = CFDataFind(incomingMessage, footer, CFRangeMake(0, CFDataGetLength(incomingMessage)), 0);
197  
198          CFDataRef bodyData = CFDataCreateReferenceFromRange(kCFAllocatorDefault, incomingMessage, CFRangeMake(headerLoc.length, footerLoc.location - headerLoc.length));
199  
200          size_t expectedSize = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), NULL, 0);
201          PerformWithBuffer(expectedSize, ^(size_t size, uint8_t *decodedByteArray) {
202              size_t usedSize = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), decodedByteArray, size);
203              if (usedSize > 0 && usedSize <= size ) {
204                  result = CFDataCreate(kCFAllocatorDefault, decodedByteArray, usedSize);
205              }
206          });
207  
208          CFRelease(bodyData);
209          CFRelease(footer);
210      }
211      CFRelease(header);
212  
213      return result;
214  }
215  
216  void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage, CFMutableDataRef protectedMessage)
217  {
218      CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?');
219      CFDataRef footer = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("."), kCFStringEncodingUTF8, '?');
220      size_t base64Len = SecBase64Encode(CFDataGetBytePtr(destinationMessage), CFDataGetLength(destinationMessage), NULL, 0);
221      char base64Message [base64Len];
222      SecBase64Encode(CFDataGetBytePtr(destinationMessage), CFDataGetLength(destinationMessage), base64Message, base64Len);
223      CFDataRef base64Data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (uint8_t*)base64Message, base64Len, kCFAllocatorNull);
224      
225      CFDataAppend(protectedMessage, header);
226      CFDataAppend(protectedMessage, base64Data);
227      CFDataAppend(protectedMessage, footer);
228      
229      CFRelease(header);
230      CFRelease(footer);
231      CFRelease(base64Data);
232  }
233  
234