X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/c38e3ce98599a410a47dc10253faa4d5830f13b2..427c49bcad63d042b29ada2ac27e3dfc4845c779:/sec/Security/SecOTRUtils.c diff --git a/sec/Security/SecOTRUtils.c b/sec/Security/SecOTRUtils.c new file mode 100644 index 00000000..76b24042 --- /dev/null +++ b/sec/Security/SecOTRUtils.c @@ -0,0 +1,204 @@ +// +// SecOTRUtils.c +// libSecOTR +// +// Created by Keith Henrickson on 6/11/12. +// +// + +#include "SecOTR.h" +#include "SecOTRIdentityPriv.h" +#include "SecOTRSessionPriv.h" +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +CFStringRef sLocalErrorDomain = CFSTR("com.apple.security.otr.error"); + +void SecOTRCreateError(enum SecOTRError family, CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) { + if (newError && !(*newError)) { + const void* keys[2] = {kCFErrorDescriptionKey, kCFErrorUnderlyingErrorKey}; + const void* values[2] = {descriptionString, previousError}; + *newError = CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, (family == secOTRErrorLocal) ? sLocalErrorDomain : kCFErrorDomainOSStatus, errorCode, keys, values, (previousError != NULL) ? 2 : 1); + } else { + CFReleaseSafe(previousError); + } +} + +OSStatus insertSize(CFIndex size, uint8_t* here) +{ + require(size < 0xFFFF, fail); + + uint8_t bytes[] = { (size >> 8) & 0xFF, size & 0xFF }; + memcpy(here, bytes, sizeof(bytes)); + + return errSecSuccess; + +fail: + return errSecParam; +} + +OSStatus appendSize(CFIndex size, CFMutableDataRef into) +{ + require(size < 0xFFFF, fail); + + uint8_t bytes[] = { (size >> 8) & 0xFF, size & 0xFF }; + CFDataAppendBytes(into, bytes, sizeof(bytes)); + + return errSecSuccess; + +fail: + return errSecParam; +} + +OSStatus readSize(const uint8_t** data, size_t* limit, uint16_t* size) +{ + require(limit != NULL, fail); + require(data != NULL, fail); + require(size != NULL, fail); + require(*limit > 1, fail); + + *size = ((uint16_t)(*data)[0]) << 8 | ((uint16_t) (*data)[1]) << 0; + + *limit -= 2; + *data += 2; + + return errSecSuccess; +fail: + return errSecParam; +} + +OSStatus appendSizeAndData(CFDataRef data, CFMutableDataRef appendTo) +{ + OSStatus status = errSecNotAvailable; + + require_noerr(appendSize(CFDataGetLength(data), appendTo), exit); + CFDataAppend(appendTo, data); + + status = errSecSuccess; + +exit: + return status; +} + +OSStatus appendPublicOctetsAndSize(SecKeyRef fromKey, CFMutableDataRef appendTo) +{ + OSStatus status = errSecDecode; + CFDataRef serializedKey = NULL; + + require_noerr(SecKeyCopyPublicBytes(fromKey, &serializedKey), exit); + require(serializedKey, exit); + + status = appendSizeAndData(serializedKey, appendTo); + +exit: + CFReleaseNull(serializedKey); + return status; +} + +OSStatus appendPublicOctets(SecKeyRef fromKey, CFMutableDataRef appendTo) +{ + OSStatus status = errSecDecode; + CFDataRef serializedKey = NULL; + + require_noerr(SecKeyCopyPublicBytes(fromKey, &serializedKey), exit); + require(serializedKey, exit); + + CFDataAppend(appendTo, serializedKey); + + status = errSecSuccess; + +exit: + CFReleaseNull(serializedKey); + return status; +} + + +/* Given an EC public key in encoded form return a SecKeyRef representing + that key. Supported encodings are kSecKeyEncodingPkcs1. */ +static SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator, + const uint8_t *keyData, CFIndex keyDataLength) { + CFDataRef tempData = CFDataCreate(kCFAllocatorDefault, keyData, keyDataLength); + SecKeyRef newPublicKey = SecKeyCreateFromPublicData(kCFAllocatorDefault, kSecECDSAAlgorithmID, tempData); + + CFRelease(tempData); + return newPublicKey; +} + +typedef SecKeyRef (*createFunction_t)(CFAllocatorRef allocator, + const uint8_t *keyData, CFIndex keyDataLength); + +static SecKeyRef CallCreateFunctionFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit, createFunction_t create) +{ + uint16_t foundLength = 0; + const uint8_t* foundData = NULL; + + require(limit != NULL, fail); + require(data != NULL, fail); + + require_noerr(readSize(data, limit, &foundLength), fail); + require(foundLength <= *limit, fail); + + foundData = *data; + + *limit -= foundLength; + *data += foundLength; + +fail: + + return create(allocator, foundData, foundLength); +} + +SecKeyRef CreateECPublicKeyFrom(CFAllocatorRef allocator, const uint8_t** data, size_t* limit) +{ + return CallCreateFunctionFrom(allocator, data, limit, &SecKeyCreateECPublicKey); +} + +void SecOTRGetIncomingBytes(CFDataRef incomingMessage, CFMutableDataRef decodedBytes) +{ + CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?'); + CFDataRef footer = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("."), kCFStringEncodingUTF8, '?'); + CFRange headerLoc = CFDataFind(incomingMessage, header, CFRangeMake(0, CFDataGetLength(header)), 0); + CFRange footerLoc = CFDataFind(incomingMessage, footer, CFRangeMake(0, CFDataGetLength(incomingMessage)), 0); + if (kCFNotFound == headerLoc.location) { + CFDataAppend(decodedBytes, incomingMessage); + } else { + CFDataRef bodyData = CFDataCreateReferenceFromRange(kCFAllocatorDefault, incomingMessage, CFRangeMake(headerLoc.length, footerLoc.location - headerLoc.length)); + size_t size = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), NULL, 0); + uint8_t decodedByteArray[size]; + SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), decodedByteArray, size); + CFDataAppendBytes(decodedBytes, decodedByteArray, size); + CFRelease(bodyData); + } + CFRelease(header); + CFRelease(footer); +} + +void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage, CFMutableDataRef protectedMessage) +{ + CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?'); + CFDataRef footer = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("."), kCFStringEncodingUTF8, '?'); + size_t base64Len = SecBase64Encode(CFDataGetBytePtr(destinationMessage), CFDataGetLength(destinationMessage), NULL, 0); + char base64Message [base64Len]; + SecBase64Encode(CFDataGetBytePtr(destinationMessage), CFDataGetLength(destinationMessage), base64Message, base64Len); + CFDataRef base64Data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (uint8_t*)base64Message, base64Len, kCFAllocatorNull); + + CFDataAppend(protectedMessage, header); + CFDataAppend(protectedMessage, base64Data); + CFDataAppend(protectedMessage, footer); + + CFRelease(header); + CFRelease(footer); + CFRelease(base64Data); +} + +