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