5 // Created by Keith Henrickson on 6/11/12.
10 #include "SecOTRIdentityPriv.h"
11 #include "SecOTRSessionPriv.h"
12 #include <utilities/SecCFWrappers.h>
15 #include <AssertMacros.h>
17 #include <Security/SecBase.h>
18 #include <Security/SecItem.h>
19 #include <Security/SecKey.h>
20 #include <Security/SecKeyPriv.h>
21 #include <Security/SecBase64.h>
23 #include <TargetConditionals.h>
25 CFStringRef sLocalErrorDomain
= CFSTR("com.apple.security.otr.error");
27 void SecOTRCreateError(enum SecOTRError family
, CFIndex errorCode
, CFStringRef descriptionString
, CFErrorRef previousError
, CFErrorRef
*newError
) {
28 if (newError
&& !(*newError
)) {
29 const void* keys
[2] = {kCFErrorDescriptionKey
, kCFErrorUnderlyingErrorKey
};
30 const void* values
[2] = {descriptionString
, previousError
};
31 *newError
= CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
, (family
== secOTRErrorLocal
) ? sLocalErrorDomain
: kCFErrorDomainOSStatus
, errorCode
, keys
, values
, (previousError
!= NULL
) ? 2 : 1);
33 CFReleaseSafe(previousError
);
37 OSStatus
insertSize(CFIndex size
, uint8_t* here
)
39 require(size
< 0xFFFF, fail
);
41 uint8_t bytes
[] = { (size
>> 8) & 0xFF, size
& 0xFF };
42 memcpy(here
, bytes
, sizeof(bytes
));
50 OSStatus
appendSize(CFIndex size
, CFMutableDataRef into
)
52 require(size
< 0xFFFF, fail
);
54 uint8_t bytes
[] = { (size
>> 8) & 0xFF, size
& 0xFF };
55 CFDataAppendBytes(into
, bytes
, sizeof(bytes
));
63 OSStatus
readSize(const uint8_t** data
, size_t* limit
, uint16_t* size
)
65 require(limit
!= NULL
, fail
);
66 require(data
!= NULL
, fail
);
67 require(size
!= NULL
, fail
);
68 require(*limit
> 1, fail
);
70 *size
= ((uint16_t)(*data
)[0]) << 8 | ((uint16_t) (*data
)[1]) << 0;
80 OSStatus
appendSizeAndData(CFDataRef data
, CFMutableDataRef appendTo
)
82 OSStatus status
= errSecNotAvailable
;
84 require_noerr(appendSize(CFDataGetLength(data
), appendTo
), exit
);
85 CFDataAppend(appendTo
, data
);
87 status
= errSecSuccess
;
93 OSStatus
appendPublicOctetsAndSize(SecKeyRef fromKey
, CFMutableDataRef appendTo
)
95 OSStatus status
= errSecDecode
;
96 CFDataRef serializedKey
= NULL
;
98 require_noerr(SecKeyCopyPublicBytes(fromKey
, &serializedKey
), exit
);
99 require(serializedKey
, exit
);
101 status
= appendSizeAndData(serializedKey
, appendTo
);
104 CFReleaseNull(serializedKey
);
108 OSStatus
appendPublicOctets(SecKeyRef fromKey
, CFMutableDataRef appendTo
)
110 OSStatus status
= errSecDecode
;
111 CFDataRef serializedKey
= NULL
;
113 require_noerr(SecKeyCopyPublicBytes(fromKey
, &serializedKey
), exit
);
114 require(serializedKey
, exit
);
116 CFDataAppend(appendTo
, serializedKey
);
118 status
= errSecSuccess
;
121 CFReleaseNull(serializedKey
);
126 /* Given an EC public key in encoded form return a SecKeyRef representing
127 that key. Supported encodings are kSecKeyEncodingPkcs1. */
128 static SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
129 const uint8_t *keyData
, CFIndex keyDataLength
) {
130 CFDataRef tempData
= CFDataCreate(kCFAllocatorDefault
, keyData
, keyDataLength
);
131 SecKeyRef newPublicKey
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, tempData
);
137 typedef SecKeyRef (*createFunction_t
)(CFAllocatorRef allocator
,
138 const uint8_t *keyData
, CFIndex keyDataLength
);
140 static SecKeyRef
CallCreateFunctionFrom(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
, createFunction_t create
)
142 uint16_t foundLength
= 0;
143 const uint8_t* foundData
= NULL
;
145 require(limit
!= NULL
, fail
);
146 require(data
!= NULL
, fail
);
148 require_noerr(readSize(data
, limit
, &foundLength
), fail
);
149 require(foundLength
<= *limit
, fail
);
153 *limit
-= foundLength
;
154 *data
+= foundLength
;
158 return create(allocator
, foundData
, foundLength
);
161 SecKeyRef
CreateECPublicKeyFrom(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
)
163 return CallCreateFunctionFrom(allocator
, data
, limit
, &SecKeyCreateECPublicKey
);
166 void SecOTRGetIncomingBytes(CFDataRef incomingMessage
, CFMutableDataRef decodedBytes
)
168 CFDataRef header
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("?OTR:"), kCFStringEncodingUTF8
, '?');
169 CFDataRef footer
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("."), kCFStringEncodingUTF8
, '?');
170 CFRange headerLoc
= CFDataFind(incomingMessage
, header
, CFRangeMake(0, CFDataGetLength(header
)), 0);
171 CFRange footerLoc
= CFDataFind(incomingMessage
, footer
, CFRangeMake(0, CFDataGetLength(incomingMessage
)), 0);
172 if (kCFNotFound
== headerLoc
.location
) {
173 CFDataAppend(decodedBytes
, incomingMessage
);
175 CFDataRef bodyData
= CFDataCreateReferenceFromRange(kCFAllocatorDefault
, incomingMessage
, CFRangeMake(headerLoc
.length
, footerLoc
.location
- headerLoc
.length
));
176 size_t size
= SecBase64Decode((char*)CFDataGetBytePtr(bodyData
), CFDataGetLength(bodyData
), NULL
, 0);
177 uint8_t decodedByteArray
[size
];
178 SecBase64Decode((char*)CFDataGetBytePtr(bodyData
), CFDataGetLength(bodyData
), decodedByteArray
, size
);
179 CFDataAppendBytes(decodedBytes
, decodedByteArray
, size
);
186 void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage
, CFMutableDataRef protectedMessage
)
188 CFDataRef header
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("?OTR:"), kCFStringEncodingUTF8
, '?');
189 CFDataRef footer
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("."), kCFStringEncodingUTF8
, '?');
190 size_t base64Len
= SecBase64Encode(CFDataGetBytePtr(destinationMessage
), CFDataGetLength(destinationMessage
), NULL
, 0);
191 char base64Message
[base64Len
];
192 SecBase64Encode(CFDataGetBytePtr(destinationMessage
), CFDataGetLength(destinationMessage
), base64Message
, base64Len
);
193 CFDataRef base64Data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (uint8_t*)base64Message
, base64Len
, kCFAllocatorNull
);
195 CFDataAppend(protectedMessage
, header
);
196 CFDataAppend(protectedMessage
, base64Data
);
197 CFDataAppend(protectedMessage
, footer
);
201 CFRelease(base64Data
);