2 * Copyright (c) 2012,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@
26 #include "SecOTRIdentityPriv.h"
27 #include "SecOTRSessionPriv.h"
28 #include <utilities/SecCFWrappers.h>
29 #include <utilities/SecBuffer.h>
32 #include <AssertMacros.h>
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>
40 #include <TargetConditionals.h>
42 CFStringRef sLocalErrorDomain
= CFSTR("com.apple.security.otr.error");
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);
50 CFReleaseSafe(previousError
);
56 OSStatus
insertSize(CFIndex size
, uint8_t* here
)
58 require(size
< 0xFFFF, fail
);
60 uint8_t bytes
[] = { (size
>> 8) & 0xFF, size
& 0xFF };
61 memcpy(here
, bytes
, sizeof(bytes
));
69 OSStatus
appendSize(CFIndex size
, CFMutableDataRef into
)
71 require(size
< 0xFFFF, fail
);
73 uint8_t bytes
[] = { (size
>> 8) & 0xFF, size
& 0xFF };
74 CFDataAppendBytes(into
, bytes
, sizeof(bytes
));
82 OSStatus
readSize(const uint8_t** data
, size_t* limit
, uint16_t* size
)
84 require(limit
!= NULL
, fail
);
85 require(data
!= NULL
, fail
);
86 require(size
!= NULL
, fail
);
87 require(*limit
> 1, fail
);
89 *size
= ((uint16_t)(*data
)[0]) << 8 | ((uint16_t) (*data
)[1]) << 0;
99 OSStatus
appendSizeAndData(CFDataRef data
, CFMutableDataRef appendTo
)
101 OSStatus status
= errSecNotAvailable
;
103 require_noerr(appendSize(CFDataGetLength(data
), appendTo
), exit
);
104 CFDataAppend(appendTo
, data
);
106 status
= errSecSuccess
;
112 OSStatus
appendPublicOctetsAndSize(SecKeyRef fromKey
, CFMutableDataRef appendTo
)
114 OSStatus status
= errSecDecode
;
115 CFDataRef serializedKey
= NULL
;
117 require_noerr(SecKeyCopyPublicBytes(fromKey
, &serializedKey
), exit
);
118 require(serializedKey
, exit
);
120 status
= appendSizeAndData(serializedKey
, appendTo
);
123 CFReleaseNull(serializedKey
);
127 OSStatus
appendPublicOctets(SecKeyRef fromKey
, CFMutableDataRef appendTo
)
129 OSStatus status
= errSecDecode
;
130 CFDataRef serializedKey
= NULL
;
132 require_noerr(SecKeyCopyPublicBytes(fromKey
, &serializedKey
), exit
);
133 require(serializedKey
, exit
);
135 CFDataAppend(appendTo
, serializedKey
);
137 status
= errSecSuccess
;
140 CFReleaseNull(serializedKey
);
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
);
156 typedef SecKeyRef (*createFunction_t
)(CFAllocatorRef allocator
,
157 const uint8_t *keyData
, CFIndex keyDataLength
);
159 static SecKeyRef
CallCreateFunctionFrom(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
, createFunction_t create
)
161 uint16_t foundLength
= 0;
162 const uint8_t* foundData
= NULL
;
164 require(limit
!= NULL
, fail
);
165 require(data
!= NULL
, fail
);
167 require_noerr(readSize(data
, limit
, &foundLength
), fail
);
168 require(foundLength
<= *limit
, fail
);
172 *limit
-= foundLength
;
173 *data
+= foundLength
;
177 return create(allocator
, foundData
, foundLength
);
180 SecKeyRef
CreateECPublicKeyFrom(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
)
182 return CallCreateFunctionFrom(allocator
, data
, limit
, &SecKeyCreateECPublicKey
);
185 CFDataRef
SecOTRCopyIncomingBytes(CFDataRef incomingMessage
)
187 __block CFDataRef result
= NULL
;
189 CFDataRef header
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("?OTR:"), kCFStringEncodingUTF8
, '?');
190 CFRange headerLoc
= CFDataFind(incomingMessage
, header
, CFRangeMake(0, CFDataGetLength(header
)), 0);
192 if (kCFNotFound
== headerLoc
.location
) {
193 CFRetainAssign(result
, incomingMessage
);
195 CFDataRef footer
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("."), kCFStringEncodingUTF8
, '?');
196 CFRange footerLoc
= CFDataFind(incomingMessage
, footer
, CFRangeMake(0, CFDataGetLength(incomingMessage
)), 0);
198 CFDataRef bodyData
= CFDataCreateReferenceFromRange(kCFAllocatorDefault
, incomingMessage
, CFRangeMake(headerLoc
.length
, footerLoc
.location
- headerLoc
.length
));
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
);
216 void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage
, CFMutableDataRef protectedMessage
)
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
);
225 CFDataAppend(protectedMessage
, header
);
226 CFDataAppend(protectedMessage
, base64Data
);
227 CFDataAppend(protectedMessage
, footer
);
231 CFRelease(base64Data
);