2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "SecOTRSessionPriv.h"
26 #include "SecOTRPackets.h"
29 #include "SecOTRIdentityPriv.h"
31 //*****************************************#include "SecCFWrappers.h"
32 #include "SecOTRPacketData.h"
33 #include "SecOTRDHKey.h"
35 #include <utilities/SecCFWrappers.h>
37 #include <corecrypto/ccn.h>
38 #include <corecrypto/ccdigest.h>
40 #include <corecrypto/ccaes.h>
41 #include <corecrypto/ccmode.h>
42 #include <corecrypto/ccmode_factory.h>
43 #include <corecrypto/cchmac.h>
44 #include <corecrypto/ccsha2.h>
50 static inline void AppendSHA256HMAC(CFMutableDataRef appendTo
,
56 uint8_t *to
= CFDataIncreaseLengthAndGetMutableBytes(appendTo
, CCSHA256_OUTPUT_SIZE
);
58 cchmac(ccsha256_di(), keybytes
, key
, howMuch
, from
, to
);
61 // First 160 bits of the HMAC
62 static inline void AppendSHA256HMAC_160(CFMutableDataRef appendTo
,
68 AppendSHA256HMAC(appendTo
, keySize
, key
, howMuch
, from
);
69 const CFIndex bytesToRemove
= CCSHA256_OUTPUT_SIZE
- kSHA256HMAC160Bytes
;
70 const CFRange rangeToDelete
= CFRangeMake(CFDataGetLength(appendTo
) - bytesToRemove
, bytesToRemove
);
72 CFDataDeleteBytes(appendTo
, rangeToDelete
);
75 static inline void DeriveAndAppendSHA256HMAC(CFMutableDataRef appendTo
,
82 size_t localKeySize
= CCSHA256_OUTPUT_SIZE
;
83 uint8_t localKey
[localKeySize
];
85 DeriveOTR256BitsFromS(whichKey
, sN
, s
, localKeySize
, localKey
);
87 AppendSHA256HMAC(appendTo
, localKeySize
, localKey
, howMuch
, from
);
89 bzero(localKey
, localKeySize
);
92 static inline void DeriveAndAppendSHA256HMAC_160(CFMutableDataRef appendTo
,
99 size_t localKeySize
= CCSHA256_OUTPUT_SIZE
;
100 uint8_t localKey
[localKeySize
];
102 DeriveOTR256BitsFromS(whichKey
, sN
, s
, localKeySize
, localKey
);
104 AppendSHA256HMAC_160(appendTo
, localKeySize
, localKey
, howMuch
, from
);
106 bzero(localKey
, sizeof(localKey
));
113 void SecOTRAppendDHMessage(SecOTRSessionRef session
,
114 CFMutableDataRef appendTo
)
117 // Message Type: kDHMessage (0x02)
118 // AES_CTR(r, 0) of G^X MPI
123 CFMutableDataRef gxmpi
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
126 AppendHeader(appendTo
, kDHMessage
);
128 SecFDHKAppendPublicSerialization(session
->_myKey
, gxmpi
);
130 size_t gxmpiSize
= (size_t)CFDataGetLength(gxmpi
);
132 CFReleaseNull(gxmpi
);
135 const uint8_t* gxmpiLocation
= CFDataGetBytePtr(gxmpi
);
137 /* 64 bits cast: gxmpiSize is the size of the EC public key, which is hardcoded and never more than 2^32 bytes. */
138 assert(gxmpiSize
<UINT32_MAX
); /* debug check only */
139 AppendLong(appendTo
, (uint32_t)gxmpiSize
);
140 assert(gxmpiSize
<INT32_MAX
);
141 uint8_t* encGxmpiLocation
= CFDataIncreaseLengthAndGetMutableBytes(appendTo
, (CFIndex
)gxmpiSize
);
142 AES_CTR_IV0_Transform(sizeof(session
->_r
), session
->_r
, gxmpiSize
, gxmpiLocation
, encGxmpiLocation
);
144 AppendLong(appendTo
, CCSHA256_OUTPUT_SIZE
);
145 uint8_t* hashLocation
= CFDataIncreaseLengthAndGetMutableBytes(appendTo
, CCSHA256_OUTPUT_SIZE
);
147 ccdigest(ccsha256_di(), gxmpiSize
, gxmpiLocation
, hashLocation
);
149 CFReleaseNull(gxmpi
);
152 void SecOTRAppendDHKeyMessage(SecOTRSessionRef session
,
153 CFMutableDataRef appendTo
)
156 // Message Type: kDHKeyMessage (0x0A)
160 AppendHeader(appendTo
, kDHKeyMessage
);
161 SecFDHKAppendPublicSerialization(session
->_myKey
, appendTo
);
164 static uint8_t* AppendEncryptedSignature(SecOTRSessionRef session
,
167 CFMutableDataRef appendTo
)
169 CFMutableDataRef signature
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
170 CFMutableDataRef mbData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
171 CFMutableDataRef mb
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
173 SecFDHKAppendPublicSerialization(session
->_myKey
, mbData
);
174 SecPDHKAppendSerialization(session
->_theirKey
, mbData
);
176 CFIndex publicKeyOffset
= CFDataGetLength(mbData
);
178 SecOTRPublicIdentityRef myPublic
= SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault
, session
->_me
, NULL
);
179 AppendPublicKey(mbData
, myPublic
);
180 CFReleaseNull(myPublic
);
182 AppendLong(mbData
, session
->_keyID
);
184 DeriveAndAppendSHA256HMAC(mb
,
185 kExponentiationUnits
, s
,
186 usePrime
? kM1Prime
: kM1
,
187 (size_t)CFDataGetLength(mbData
), CFDataGetBytePtr(mbData
));
189 CFDataDeleteBytes(mbData
, CFRangeMake(0, publicKeyOffset
));
191 CFMutableDataRef xb
= mbData
; mbData
= NULL
;
192 SecOTRFIAppendSignature(session
->_me
, mb
, signature
, NULL
);
195 AppendCFDataAsDATA(xb
, signature
);
196 CFReleaseNull(signature
);
198 CFIndex dataLength
= CFDataGetLength(xb
);
200 CFIndex signatureStartIndex
= CFDataGetLength(appendTo
);
201 /* 64 bits cast: We are appending the signature we just generated, which is never bigger than 2^32 bytes. */
202 assert(((unsigned long)dataLength
)<=UINT32_MAX
); /* debug check, correct as long as CFIndex is a signed long */
203 AppendLong(appendTo
, (uint32_t)dataLength
);
204 uint8_t *destination
= CFDataIncreaseLengthAndGetMutableBytes(appendTo
, dataLength
);
206 uint8_t c
[kOTRAuthKeyBytes
];
207 DeriveOTR128BitPairFromS(kCs
, kExponentiationUnits
, s
,
208 sizeof(c
), usePrime
? NULL
: c
,
209 sizeof(c
), usePrime
? c
: NULL
);
211 AES_CTR_IV0_Transform(sizeof(c
), c
,
212 (size_t)dataLength
, CFDataGetBytePtr(xb
),
217 return CFDataGetMutableBytePtr(appendTo
) + signatureStartIndex
;
221 static void AppendMACedEncryptedSignature(SecOTRSessionRef session
,
223 CFMutableDataRef appendTo
)
226 cc_unit s
[kExponentiationUnits
];
228 SecPDHKeyGenerateS(session
->_myKey
, session
->_theirKey
, s
);
230 CFIndex signatureStartOffset
= CFDataGetLength(appendTo
);
231 const uint8_t *signatureStart
= AppendEncryptedSignature(session
, s
, usePrime
, appendTo
);
232 size_t signatureSize
= (size_t)CFDataGetLength(appendTo
) - (size_t)signatureStartOffset
;
235 DeriveAndAppendSHA256HMAC_160(appendTo
,
236 kExponentiationUnits
, s
,
237 usePrime
? kM2Prime
: kM2
,
238 signatureSize
, signatureStart
);
243 void SecOTRAppendRevealSignatureMessage(SecOTRSessionRef session
,
244 CFMutableDataRef appendTo
)
247 // Message Type: kRevealSignatureMessage (0x11)
251 AppendHeader(appendTo
, kRevealSignatureMessage
);
253 AppendLong(appendTo
, kOTRAuthKeyBytes
);
254 uint8_t* keyPosition
= CFDataIncreaseLengthAndGetMutableBytes(appendTo
, kOTRAuthKeyBytes
);
255 memcpy(keyPosition
, session
->_r
, kOTRAuthKeyBytes
);
257 AppendMACedEncryptedSignature(session
, false, appendTo
);
260 void SecOTRAppendSignatureMessage(SecOTRSessionRef session
,
261 CFMutableDataRef appendTo
)
264 // Message Type: kSignatureMessage (0x12)
268 AppendHeader(appendTo
, kSignatureMessage
);
269 AppendMACedEncryptedSignature(session
, true, appendTo
);