]> git.saurik.com Git - apple/security.git/blobdiff - sec/Security/SecOTRPackets.c
Security-55471.tar.gz
[apple/security.git] / sec / Security / SecOTRPackets.c
diff --git a/sec/Security/SecOTRPackets.c b/sec/Security/SecOTRPackets.c
new file mode 100644 (file)
index 0000000..f13d967
--- /dev/null
@@ -0,0 +1,264 @@
+//
+//  SecOTRPackets.c
+//  libsecurity_libSecOTR
+//
+//  Created by Mitch Adler on 2/23/11.
+//  Copyright 2011 Apple Inc. All rights reserved.
+//
+
+#include "SecOTRSessionPriv.h"
+#include "SecOTRPackets.h"
+
+#include "SecOTR.h"
+#include "SecOTRIdentityPriv.h"
+
+//*****************************************#include "SecCFWrappers.h"
+#include "SecOTRPacketData.h"
+#include "SecOTRDHKey.h"
+
+#ifdef USECOMMONCRYPTO
+#include <CommonCrypto/CommonHMAC.h>
+#endif
+
+#include <corecrypto/ccn.h>
+#include <corecrypto/ccdigest.h>
+
+#include <corecrypto/ccaes.h>
+#include <corecrypto/ccmode.h>
+#include <corecrypto/ccmode_factory.h>
+#include <corecrypto/cchmac.h>
+#include <corecrypto/ccsha2.h>
+
+//
+// Crypto functions
+//
+
+static inline void AppendSHA256HMAC(CFMutableDataRef appendTo,
+                                    size_t keybytes,
+                                    const uint8_t* key,
+                                    size_t howMuch,
+                                    const uint8_t* from)
+{
+    uint8_t *to = CFDataIncreaseLengthAndGetMutableBytes(appendTo, CCSHA256_OUTPUT_SIZE);
+    
+#ifdef USECOMMONCRYPTO
+    CCHmac(kCCHmacAlgSHA256, key, keybytes, from, howMuch, to);
+#else
+    cchmac(ccsha256_di(), keybytes, key, howMuch, from, to);
+#endif
+}
+
+// First 160 bits of the HMAC
+static inline void AppendSHA256HMAC_160(CFMutableDataRef appendTo,
+                                    size_t keySize,
+                                    const uint8_t* key,
+                                    size_t howMuch,
+                                    const uint8_t* from)
+{
+    AppendSHA256HMAC(appendTo, keySize, key, howMuch, from);
+    const CFIndex bytesToRemove = CCSHA256_OUTPUT_SIZE - kSHA256HMAC160Bytes;
+    const CFRange rangeToDelete = CFRangeMake(CFDataGetLength(appendTo) - bytesToRemove, bytesToRemove);
+    
+    CFDataDeleteBytes(appendTo, rangeToDelete);
+}
+
+static inline void DeriveAndAppendSHA256HMAC(CFMutableDataRef appendTo,
+                                             cc_size sN,
+                                             const cc_unit* s,
+                                             KeyType whichKey,
+                                             size_t howMuch,
+                                             const uint8_t* from)
+{
+    size_t localKeySize = CCSHA256_OUTPUT_SIZE;
+    uint8_t localKey[localKeySize];
+    
+    DeriveOTR256BitsFromS(whichKey, sN, s, localKeySize, localKey);
+    
+    AppendSHA256HMAC(appendTo, localKeySize, localKey, howMuch, from);
+    
+    bzero(localKey, localKeySize);
+}
+
+static inline void DeriveAndAppendSHA256HMAC_160(CFMutableDataRef appendTo,
+                                                 cc_size sN,
+                                                 const cc_unit* s,
+                                                 KeyType whichKey,
+                                                 size_t howMuch,
+                                                 const uint8_t* from)
+{
+    size_t localKeySize = CCSHA256_OUTPUT_SIZE;
+    uint8_t localKey[localKeySize];
+    
+    DeriveOTR256BitsFromS(whichKey, sN, s, localKeySize, localKey);
+    
+    AppendSHA256HMAC_160(appendTo, localKeySize, localKey, howMuch, from);
+    
+    bzero(localKey, sizeof(localKey));
+}
+
+//
+// Message creators
+//
+
+void SecOTRAppendDHMessage(SecOTRSessionRef session,
+                           CFMutableDataRef appendTo)
+{
+    //
+    // Message Type: kDHMessage (0x02)
+    // AES_CTR(r, 0) of G^X MPI
+    // SHA256(gxmpi)
+    //
+    
+    if(!session) return;
+    CFMutableDataRef gxmpi = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    if(!gxmpi) return;
+
+    AppendHeader(appendTo, kDHMessage);
+
+    SecFDHKAppendPublicSerialization(session->_myKey, gxmpi);
+
+    size_t gxmpiSize = (size_t)CFDataGetLength(gxmpi);
+    if(gxmpiSize == 0) {
+        CFReleaseNull(gxmpi);
+        return;
+    }
+    const uint8_t* gxmpiLocation = CFDataGetBytePtr(gxmpi);
+
+    /* 64 bits cast: gxmpiSize is the size of the EC public key, which is hardcoded and never more than 2^32 bytes. */
+    assert(gxmpiSize<UINT32_MAX); /* debug check only */
+    AppendLong(appendTo, (uint32_t)gxmpiSize);
+    assert(gxmpiSize<INT32_MAX);
+    uint8_t* encGxmpiLocation = CFDataIncreaseLengthAndGetMutableBytes(appendTo, (CFIndex)gxmpiSize);
+    AES_CTR_IV0_Transform(sizeof(session->_r), session->_r, gxmpiSize, gxmpiLocation, encGxmpiLocation);
+    
+    AppendLong(appendTo, CCSHA256_OUTPUT_SIZE);
+    uint8_t* hashLocation = CFDataIncreaseLengthAndGetMutableBytes(appendTo, CCSHA256_OUTPUT_SIZE);
+
+#ifdef USECOMMONCRYPTO
+    (void) CC_SHA256(gxmpiLocation, (uint32_t)gxmpiSize, hashLocation);
+#else
+    ccdigest(ccsha256_di(), gxmpiSize, gxmpiLocation, hashLocation);
+#endif
+    CFReleaseNull(gxmpi);
+}
+
+void SecOTRAppendDHKeyMessage(SecOTRSessionRef session,
+                              CFMutableDataRef appendTo)
+{
+    //
+    // Message Type: kDHKeyMessage (0x0A)
+    // G^X Data MPI
+    //
+    
+    AppendHeader(appendTo, kDHKeyMessage);
+    SecFDHKAppendPublicSerialization(session->_myKey, appendTo);
+}
+
+static uint8_t* AppendEncryptedSignature(SecOTRSessionRef session,
+                                         const cc_unit* s,
+                                         bool usePrime,
+                                         CFMutableDataRef appendTo)
+{
+    CFMutableDataRef signature = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    CFMutableDataRef mbData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    CFMutableDataRef mb = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    SecFDHKAppendPublicSerialization(session->_myKey, mbData);
+    SecPDHKAppendSerialization(session->_theirKey, mbData);
+    
+    CFIndex publicKeyOffset = CFDataGetLength(mbData);
+
+    SecOTRPublicIdentityRef myPublic = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL);
+    AppendPublicKey(mbData, myPublic);
+    CFReleaseNull(myPublic);
+
+    AppendLong(mbData, session->_keyID);
+    
+    DeriveAndAppendSHA256HMAC(mb,
+                              kExponentiationUnits, s,
+                              usePrime ? kM1Prime : kM1,
+                              (size_t)CFDataGetLength(mbData), CFDataGetBytePtr(mbData));
+    
+    CFDataDeleteBytes(mbData, CFRangeMake(0, publicKeyOffset));
+
+    CFMutableDataRef xb = mbData; mbData = NULL;
+    SecOTRFIAppendSignature(session->_me, mb, signature, NULL);
+    CFReleaseNull(mb);
+
+    AppendCFDataAsDATA(xb, signature);
+    CFReleaseNull(signature);
+
+    CFIndex dataLength = CFDataGetLength(xb);
+
+    CFIndex signatureStartIndex = CFDataGetLength(appendTo);
+    /* 64 bits cast: We are appending the signature we just generated, which is never bigger than 2^32 bytes. */
+    assert(((unsigned long)dataLength)<=UINT32_MAX); /* debug check, correct as long as CFIndex is a signed long */
+    AppendLong(appendTo, (uint32_t)dataLength);
+    uint8_t *destination = CFDataIncreaseLengthAndGetMutableBytes(appendTo, dataLength);
+
+    uint8_t c[kOTRAuthKeyBytes];
+    DeriveOTR128BitPairFromS(kCs, kExponentiationUnits, s,
+                             sizeof(c), usePrime ? NULL : c,
+                             sizeof(c), usePrime ? c : NULL);
+
+    AES_CTR_IV0_Transform(sizeof(c), c,
+                          (size_t)dataLength, CFDataGetBytePtr(xb),
+                          destination);
+    bzero(c, sizeof(c));
+    CFReleaseNull(xb);
+    
+    return CFDataGetMutableBytePtr(appendTo) + signatureStartIndex;
+}
+
+
+static void AppendMACedEncryptedSignature(SecOTRSessionRef session,
+                                          bool usePrime,
+                                          CFMutableDataRef appendTo)
+{
+    
+    cc_unit s[kExponentiationUnits];
+    
+    SecPDHKeyGenerateS(session->_myKey, session->_theirKey, s);
+
+    CFIndex signatureStartOffset = CFDataGetLength(appendTo);
+    const uint8_t *signatureStart = AppendEncryptedSignature(session, s, usePrime, appendTo);
+    size_t signatureSize = (size_t)CFDataGetLength(appendTo) - (size_t)signatureStartOffset;
+    
+    
+    DeriveAndAppendSHA256HMAC_160(appendTo,
+                                  kExponentiationUnits, s,
+                                  usePrime ? kM2Prime : kM2,
+                                  signatureSize, signatureStart);
+    bzero(s, sizeof(s));
+}
+
+
+void SecOTRAppendRevealSignatureMessage(SecOTRSessionRef session,
+                                        CFMutableDataRef appendTo)
+{
+    //
+    // Message Type: kRevealSignatureMessage (0x11)
+    // G^X Data MPI
+    //
+    
+    AppendHeader(appendTo, kRevealSignatureMessage);
+    
+    AppendLong(appendTo, kOTRAuthKeyBytes);
+    uint8_t* keyPosition = CFDataIncreaseLengthAndGetMutableBytes(appendTo, kOTRAuthKeyBytes);
+    memcpy(keyPosition, session->_r, kOTRAuthKeyBytes);
+    
+    AppendMACedEncryptedSignature(session, false, appendTo);
+}
+
+void SecOTRAppendSignatureMessage(SecOTRSessionRef session,
+                                        CFMutableDataRef appendTo)
+{
+    //
+    // Message Type: kSignatureMessage (0x12)
+    // G^X Data MPI
+    //
+    
+    AppendHeader(appendTo, kSignatureMessage);
+    AppendMACedEncryptedSignature(session, true, appendTo);
+}
+