1/* 2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include "SecOTRSessionPriv.h" 26#include "SecOTRPackets.h" 27 28#include "SecOTR.h" 29#include "SecOTRIdentityPriv.h" 30 31//*****************************************#include "SecCFWrappers.h" 32#include "SecOTRPacketData.h" 33#include "SecOTRDHKey.h" 34 35#include <corecrypto/ccn.h> 36#include <corecrypto/ccdigest.h> 37 38#include <corecrypto/ccaes.h> 39#include <corecrypto/ccmode.h> 40#include <corecrypto/ccmode_factory.h> 41#include <corecrypto/cchmac.h> 42#include <corecrypto/ccsha2.h> 43 44// 45// Crypto functions 46// 47 48static inline void AppendSHA256HMAC(CFMutableDataRef appendTo, 49 size_t keybytes, 50 const uint8_t* key, 51 size_t howMuch, 52 const uint8_t* from) 53{ 54 uint8_t *to = CFDataIncreaseLengthAndGetMutableBytes(appendTo, CCSHA256_OUTPUT_SIZE); 55 56 cchmac(ccsha256_di(), keybytes, key, howMuch, from, to); 57} 58 59// First 160 bits of the HMAC 60static inline void AppendSHA256HMAC_160(CFMutableDataRef appendTo, 61 size_t keySize, 62 const uint8_t* key, 63 size_t howMuch, 64 const uint8_t* from) 65{ 66 AppendSHA256HMAC(appendTo, keySize, key, howMuch, from); 67 const CFIndex bytesToRemove = CCSHA256_OUTPUT_SIZE - kSHA256HMAC160Bytes; 68 const CFRange rangeToDelete = CFRangeMake(CFDataGetLength(appendTo) - bytesToRemove, bytesToRemove); 69 70 CFDataDeleteBytes(appendTo, rangeToDelete); 71} 72 73static inline void DeriveAndAppendSHA256HMAC(CFMutableDataRef appendTo, 74 cc_size sN, 75 const cc_unit* s, 76 KeyType whichKey, 77 size_t howMuch, 78 const uint8_t* from) 79{ 80 size_t localKeySize = CCSHA256_OUTPUT_SIZE; 81 uint8_t localKey[localKeySize]; 82 83 DeriveOTR256BitsFromS(whichKey, sN, s, localKeySize, localKey); 84 85 AppendSHA256HMAC(appendTo, localKeySize, localKey, howMuch, from); 86 87 bzero(localKey, localKeySize); 88} 89 90static inline void DeriveAndAppendSHA256HMAC_160(CFMutableDataRef appendTo, 91 cc_size sN, 92 const cc_unit* s, 93 KeyType whichKey, 94 size_t howMuch, 95 const uint8_t* from) 96{ 97 size_t localKeySize = CCSHA256_OUTPUT_SIZE; 98 uint8_t localKey[localKeySize]; 99 100 DeriveOTR256BitsFromS(whichKey, sN, s, localKeySize, localKey); 101 102 AppendSHA256HMAC_160(appendTo, localKeySize, localKey, howMuch, from); 103 104 bzero(localKey, sizeof(localKey)); 105} 106 107// 108// Message creators 109// 110 111void SecOTRAppendDHMessage(SecOTRSessionRef session, 112 CFMutableDataRef appendTo) 113{ 114 // 115 // Message Type: kDHMessage (0x02) 116 // AES_CTR(r, 0) of G^X MPI 117 // SHA256(gxmpi) 118 // 119 120 if(!session) return; 121 CFMutableDataRef gxmpi = CFDataCreateMutable(kCFAllocatorDefault, 0); 122 if(!gxmpi) return; 123 124 AppendHeader(appendTo, kDHMessage); 125 126 SecFDHKAppendPublicSerialization(session->_myKey, gxmpi); 127 128 size_t gxmpiSize = (size_t)CFDataGetLength(gxmpi); 129 if(gxmpiSize == 0) { 130 CFReleaseNull(gxmpi); 131 return; 132 } 133 const uint8_t* gxmpiLocation = CFDataGetBytePtr(gxmpi); 134 135 /* 64 bits cast: gxmpiSize is the size of the EC public key, which is hardcoded and never more than 2^32 bytes. */ 136 assert(gxmpiSize<UINT32_MAX); /* debug check only */ 137 AppendLong(appendTo, (uint32_t)gxmpiSize); 138 assert(gxmpiSize<INT32_MAX); 139 uint8_t* encGxmpiLocation = CFDataIncreaseLengthAndGetMutableBytes(appendTo, (CFIndex)gxmpiSize); 140 AES_CTR_IV0_Transform(sizeof(session->_r), session->_r, gxmpiSize, gxmpiLocation, encGxmpiLocation); 141 142 AppendLong(appendTo, CCSHA256_OUTPUT_SIZE); 143 uint8_t* hashLocation = CFDataIncreaseLengthAndGetMutableBytes(appendTo, CCSHA256_OUTPUT_SIZE); 144 145 ccdigest(ccsha256_di(), gxmpiSize, gxmpiLocation, hashLocation); 146 147 CFReleaseNull(gxmpi); 148} 149 150void SecOTRAppendDHKeyMessage(SecOTRSessionRef session, 151 CFMutableDataRef appendTo) 152{ 153 // 154 // Message Type: kDHKeyMessage (0x0A) 155 // G^X Data MPI 156 // 157 158 AppendHeader(appendTo, kDHKeyMessage); 159 SecFDHKAppendPublicSerialization(session->_myKey, appendTo); 160} 161 162static uint8_t* AppendEncryptedSignature(SecOTRSessionRef session, 163 const cc_unit* s, 164 bool usePrime, 165 CFMutableDataRef appendTo) 166{ 167 CFMutableDataRef signature = CFDataCreateMutable(kCFAllocatorDefault, 0); 168 CFMutableDataRef mbData = CFDataCreateMutable(kCFAllocatorDefault, 0); 169 CFMutableDataRef mb = CFDataCreateMutable(kCFAllocatorDefault, 0); 170 171 SecFDHKAppendPublicSerialization(session->_myKey, mbData); 172 SecPDHKAppendSerialization(session->_theirKey, mbData); 173 174 CFIndex publicKeyOffset = CFDataGetLength(mbData); 175 176 SecOTRPublicIdentityRef myPublic = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL); 177 AppendPublicKey(mbData, myPublic); 178 CFReleaseNull(myPublic); 179 180 AppendLong(mbData, session->_keyID); 181 182 DeriveAndAppendSHA256HMAC(mb, 183 kExponentiationUnits, s, 184 usePrime ? kM1Prime : kM1, 185 (size_t)CFDataGetLength(mbData), CFDataGetBytePtr(mbData)); 186 187 CFDataDeleteBytes(mbData, CFRangeMake(0, publicKeyOffset)); 188 189 CFMutableDataRef xb = mbData; mbData = NULL; 190 SecOTRFIAppendSignature(session->_me, mb, signature, NULL); 191 CFReleaseNull(mb); 192 193 AppendCFDataAsDATA(xb, signature); 194 CFReleaseNull(signature); 195 196 CFIndex dataLength = CFDataGetLength(xb); 197 198 CFIndex signatureStartIndex = CFDataGetLength(appendTo); 199 /* 64 bits cast: We are appending the signature we just generated, which is never bigger than 2^32 bytes. */ 200 assert(((unsigned long)dataLength)<=UINT32_MAX); /* debug check, correct as long as CFIndex is a signed long */ 201 AppendLong(appendTo, (uint32_t)dataLength); 202 uint8_t *destination = CFDataIncreaseLengthAndGetMutableBytes(appendTo, dataLength); 203 204 uint8_t c[kOTRAuthKeyBytes]; 205 DeriveOTR128BitPairFromS(kCs, kExponentiationUnits, s, 206 sizeof(c), usePrime ? NULL : c, 207 sizeof(c), usePrime ? c : NULL); 208 209 AES_CTR_IV0_Transform(sizeof(c), c, 210 (size_t)dataLength, CFDataGetBytePtr(xb), 211 destination); 212 bzero(c, sizeof(c)); 213 CFReleaseNull(xb); 214 215 return CFDataGetMutableBytePtr(appendTo) + signatureStartIndex; 216} 217 218 219static void AppendMACedEncryptedSignature(SecOTRSessionRef session, 220 bool usePrime, 221 CFMutableDataRef appendTo) 222{ 223 224 cc_unit s[kExponentiationUnits]; 225 226 SecPDHKeyGenerateS(session->_myKey, session->_theirKey, s); 227 228 CFIndex signatureStartOffset = CFDataGetLength(appendTo); 229 const uint8_t *signatureStart = AppendEncryptedSignature(session, s, usePrime, appendTo); 230 size_t signatureSize = (size_t)CFDataGetLength(appendTo) - (size_t)signatureStartOffset; 231 232 233 DeriveAndAppendSHA256HMAC_160(appendTo, 234 kExponentiationUnits, s, 235 usePrime ? kM2Prime : kM2, 236 signatureSize, signatureStart); 237 bzero(s, sizeof(s)); 238} 239 240 241void SecOTRAppendRevealSignatureMessage(SecOTRSessionRef session, 242 CFMutableDataRef appendTo) 243{ 244 // 245 // Message Type: kRevealSignatureMessage (0x11) 246 // G^X Data MPI 247 // 248 249 AppendHeader(appendTo, kRevealSignatureMessage); 250 251 AppendLong(appendTo, kOTRAuthKeyBytes); 252 uint8_t* keyPosition = CFDataIncreaseLengthAndGetMutableBytes(appendTo, kOTRAuthKeyBytes); 253 memcpy(keyPosition, session->_r, kOTRAuthKeyBytes); 254 255 AppendMACedEncryptedSignature(session, false, appendTo); 256} 257 258void SecOTRAppendSignatureMessage(SecOTRSessionRef session, 259 CFMutableDataRef appendTo) 260{ 261 // 262 // Message Type: kSignatureMessage (0x12) 263 // G^X Data MPI 264 // 265 266 AppendHeader(appendTo, kSignatureMessage); 267 AppendMACedEncryptedSignature(session, true, appendTo); 268} 269 270