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>
31 #include <AssertMacros.h>
33 #include <Security/SecBase.h>
34 #include <Security/SecItem.h>
35 #include <Security/SecKey.h>
36 #include <Security/SecKeyPriv.h>
37 #include <Security/SecBase64.h>
39 #include <TargetConditionals.h>
41 CFStringRef sLocalErrorDomain
= CFSTR("com.apple.security.otr.error");
43 bool SecOTRCreateError(enum SecOTRError family
, CFIndex errorCode
, CFStringRef descriptionString
, CFErrorRef previousError
, CFErrorRef
*newError
) {
44 if (newError
&& !(*newError
)) {
45 const void* keys
[2] = {kCFErrorDescriptionKey
, kCFErrorUnderlyingErrorKey
};
46 const void* values
[2] = {descriptionString
, previousError
};
47 *newError
= CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
, (family
== secOTRErrorLocal
) ? sLocalErrorDomain
: kCFErrorDomainOSStatus
, errorCode
, keys
, values
, (previousError
!= NULL
) ? 2 : 1);
49 CFReleaseSafe(previousError
);
55 OSStatus
insertSize(CFIndex size
, uint8_t* here
)
57 require(size
< 0xFFFF, fail
);
59 uint8_t bytes
[] = { (size
>> 8) & 0xFF, size
& 0xFF };
60 memcpy(here
, bytes
, sizeof(bytes
));
68 OSStatus
appendSize(CFIndex size
, CFMutableDataRef into
)
70 require(size
< 0xFFFF, fail
);
72 uint8_t bytes
[] = { (size
>> 8) & 0xFF, size
& 0xFF };
73 CFDataAppendBytes(into
, bytes
, sizeof(bytes
));
81 OSStatus
readSize(const uint8_t** data
, size_t* limit
, uint16_t* size
)
83 require(limit
!= NULL
, fail
);
84 require(data
!= NULL
, fail
);
85 require(size
!= NULL
, fail
);
86 require(*limit
> 1, fail
);
88 *size
= ((uint16_t)(*data
)[0]) << 8 | ((uint16_t) (*data
)[1]) << 0;
98 OSStatus
appendSizeAndData(CFDataRef data
, CFMutableDataRef appendTo
)
100 OSStatus status
= errSecNotAvailable
;
102 require_noerr(appendSize(CFDataGetLength(data
), appendTo
), exit
);
103 CFDataAppend(appendTo
, data
);
105 status
= errSecSuccess
;
111 OSStatus
appendPublicOctetsAndSize(SecKeyRef fromKey
, CFMutableDataRef appendTo
)
113 OSStatus status
= errSecDecode
;
114 CFDataRef serializedKey
= NULL
;
116 require_noerr(SecKeyCopyPublicBytes(fromKey
, &serializedKey
), exit
);
117 require(serializedKey
, exit
);
119 status
= appendSizeAndData(serializedKey
, appendTo
);
122 CFReleaseNull(serializedKey
);
126 OSStatus
appendPublicOctets(SecKeyRef fromKey
, CFMutableDataRef appendTo
)
128 OSStatus status
= errSecDecode
;
129 CFDataRef serializedKey
= NULL
;
131 require_noerr(SecKeyCopyPublicBytes(fromKey
, &serializedKey
), exit
);
132 require(serializedKey
, exit
);
134 CFDataAppend(appendTo
, serializedKey
);
136 status
= errSecSuccess
;
139 CFReleaseNull(serializedKey
);
144 /* Given an EC public key in encoded form return a SecKeyRef representing
145 that key. Supported encodings are kSecKeyEncodingPkcs1. */
146 static SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
147 const uint8_t *keyData
, CFIndex keyDataLength
) {
148 CFDataRef tempData
= CFDataCreate(kCFAllocatorDefault
, keyData
, keyDataLength
);
149 SecKeyRef newPublicKey
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, tempData
);
155 typedef SecKeyRef (*createFunction_t
)(CFAllocatorRef allocator
,
156 const uint8_t *keyData
, CFIndex keyDataLength
);
158 static SecKeyRef
CallCreateFunctionFrom(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
, createFunction_t create
)
160 uint16_t foundLength
= 0;
161 const uint8_t* foundData
= NULL
;
163 require(limit
!= NULL
, fail
);
164 require(data
!= NULL
, fail
);
166 require_noerr(readSize(data
, limit
, &foundLength
), fail
);
167 require(foundLength
<= *limit
, fail
);
171 *limit
-= foundLength
;
172 *data
+= foundLength
;
176 return create(allocator
, foundData
, foundLength
);
179 SecKeyRef
CreateECPublicKeyFrom(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
)
181 return CallCreateFunctionFrom(allocator
, data
, limit
, &SecKeyCreateECPublicKey
);
184 CFDataRef
SecOTRCopyIncomingBytes(CFDataRef incomingMessage
)
186 CFDataRef result
= NULL
;
188 CFDataRef header
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("?OTR:"), kCFStringEncodingUTF8
, '?');
189 CFRange headerLoc
= CFDataFind(incomingMessage
, header
, CFRangeMake(0, CFDataGetLength(header
)), 0);
191 if (kCFNotFound
== headerLoc
.location
) {
192 CFRetainAssign(result
, incomingMessage
);
194 CFDataRef footer
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("."), kCFStringEncodingUTF8
, '?');
195 CFRange footerLoc
= CFDataFind(incomingMessage
, footer
, CFRangeMake(0, CFDataGetLength(incomingMessage
)), 0);
197 CFDataRef bodyData
= CFDataCreateReferenceFromRange(kCFAllocatorDefault
, incomingMessage
, CFRangeMake(headerLoc
.length
, footerLoc
.location
- headerLoc
.length
));
198 size_t size
= SecBase64Decode((char*)CFDataGetBytePtr(bodyData
), CFDataGetLength(bodyData
), NULL
, 0);
199 uint8_t decodedByteArray
[size
];
200 SecBase64Decode((char*)CFDataGetBytePtr(bodyData
), CFDataGetLength(bodyData
), decodedByteArray
, size
);
201 result
= CFDataCreate(kCFAllocatorDefault
, decodedByteArray
, size
);
211 void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage
, CFMutableDataRef protectedMessage
)
213 CFDataRef header
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("?OTR:"), kCFStringEncodingUTF8
, '?');
214 CFDataRef footer
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("."), kCFStringEncodingUTF8
, '?');
215 size_t base64Len
= SecBase64Encode(CFDataGetBytePtr(destinationMessage
), CFDataGetLength(destinationMessage
), NULL
, 0);
216 char base64Message
[base64Len
];
217 SecBase64Encode(CFDataGetBytePtr(destinationMessage
), CFDataGetLength(destinationMessage
), base64Message
, base64Len
);
218 CFDataRef base64Data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (uint8_t*)base64Message
, base64Len
, kCFAllocatorNull
);
220 CFDataAppend(protectedMessage
, header
);
221 CFDataAppend(protectedMessage
, base64Data
);
222 CFDataAppend(protectedMessage
, footer
);
226 CFRelease(base64Data
);