]> git.saurik.com Git - apple/security.git/blobdiff - sec/Security/SecOTRUtils.c
Security-55471.tar.gz
[apple/security.git] / sec / Security / SecOTRUtils.c
diff --git a/sec/Security/SecOTRUtils.c b/sec/Security/SecOTRUtils.c
new file mode 100644 (file)
index 0000000..76b2404
--- /dev/null
@@ -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 <utilities/SecCFWrappers.h>
+#include <stdlib.h>
+
+#include <AssertMacros.h>
+
+#include <Security/SecBase.h>
+#include <Security/SecItem.h>
+#include <Security/SecKey.h>
+#include <Security/SecKeyPriv.h>
+#include <Security/SecBase64.h>
+
+#include <TargetConditionals.h>
+
+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);
+}
+
+