]> git.saurik.com Git - apple/security.git/blame - SecureTransport/sslHandshakeHello.cpp
Security-163.tar.gz
[apple/security.git] / SecureTransport / sslHandshakeHello.cpp
CommitLineData
5a719ac8
A
1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 File: sslHandshakeHello.c
21
22 Contains: Support for client hello and server hello messages.
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28*/
29
30#include "sslContext.h"
31#include "sslHandshake.h"
32#include "sslMemory.h"
33#include "sslSession.h"
34#include "sslUtils.h"
35#include "sslDebug.h"
36#include "appleCdsa.h"
37#include "sslDigests.h"
38#include "cipherSpecs.h"
39
40#include <string.h>
41
42static OSStatus SSLEncodeRandom(unsigned char *p, SSLContext *ctx);
43
44/* IE treats null session id as valid; two consecutive sessions with NULL ID
45 * are considered a match. Workaround: when resumable sessions are disabled,
46 * send a random session ID. */
47#define SSL_IE_NULL_RESUME_BUG 1
48#if SSL_IE_NULL_RESUME_BUG
49#define SSL_NULL_ID_LEN 32 /* length of bogus session ID */
50#endif
51
52OSStatus
53SSLEncodeServerHello(SSLRecord &serverHello, SSLContext *ctx)
54{ OSStatus err;
55 UInt8 *charPtr;
56 int sessionIDLen;
57
58 sessionIDLen = 0;
59 if (ctx->sessionID.data != 0)
60 sessionIDLen = (UInt8)ctx->sessionID.length;
61 #if SSL_IE_NULL_RESUME_BUG
62 if(sessionIDLen == 0) {
63 sessionIDLen = SSL_NULL_ID_LEN;
64 }
65 #endif /* SSL_IE_NULL_RESUME_BUG */
66
df0e469f
A
67 /* this was set to a known quantity in SSLProcessClientHello */
68 assert(ctx->negProtocolVersion != SSL_Version_Undetermined);
69 /* should not be here in this case */
70 assert(ctx->negProtocolVersion != SSL_Version_2_0);
5a719ac8
A
71 sslLogNegotiateDebug("===SSL3 server: sending version %d_%d",
72 ctx->negProtocolVersion >> 8, ctx->negProtocolVersion & 0xff);
73 sslLogNegotiateDebug("...sessionIDLen = %d", sessionIDLen);
74 serverHello.protocolVersion = ctx->negProtocolVersion;
75 serverHello.contentType = SSL_RecordTypeHandshake;
76 if ((err = SSLAllocBuffer(serverHello.contents, 42 + sessionIDLen, ctx)) != 0)
77 return err;
78
79 charPtr = serverHello.contents.data;
80 *charPtr++ = SSL_HdskServerHello;
81 charPtr = SSLEncodeInt(charPtr, 38 + sessionIDLen, 3);
82 charPtr = SSLEncodeInt(charPtr, serverHello.protocolVersion, 2);
83 if ((err = SSLEncodeRandom(charPtr, ctx)) != 0)
84 return err;
85 memcpy(ctx->serverRandom, charPtr, SSL_CLIENT_SRVR_RAND_SIZE);
86 charPtr += SSL_CLIENT_SRVR_RAND_SIZE;
87 *(charPtr++) = (UInt8)sessionIDLen;
88 #if SSL_IE_NULL_RESUME_BUG
89 if(ctx->sessionID.data != NULL) {
90 /* normal path for enabled resumable session */
91 memcpy(charPtr, ctx->sessionID.data, sessionIDLen);
92 }
93 else {
94 /* IE workaround */
95 SSLBuffer rb;
96 rb.data = charPtr;
97 rb.length = SSL_NULL_ID_LEN;
98 sslRand(ctx, &rb);
99 }
100 #else
101 if (sessionIDLen > 0)
102 memcpy(charPtr, ctx->sessionID.data, sessionIDLen);
103 #endif /* SSL_IE_NULL_RESUME_BUG */
104 charPtr += sessionIDLen;
105 charPtr = SSLEncodeInt(charPtr, ctx->selectedCipher, 2);
106 *(charPtr++) = 0; /* Null compression */
107
108 sslLogNegotiateDebug("ssl3: server specifying cipherSuite 0x%lx",
109 (UInt32)ctx->selectedCipher);
110
111 assert(charPtr == serverHello.contents.data + serverHello.contents.length);
112
113 return noErr;
114}
115
116OSStatus
117SSLProcessServerHello(SSLBuffer message, SSLContext *ctx)
118{ OSStatus err;
df0e469f 119 SSLProtocolVersion protocolVersion, negVersion;
5a719ac8
A
120 unsigned int sessionIDLen;
121 UInt8 *p;
122
123 assert(ctx->protocolSide == SSL_ClientSide);
124
125 if (message.length < 38 || message.length > 70) {
126 sslErrorLog("SSLProcessServerHello: msg len error\n");
127 return errSSLProtocol;
128 }
129 p = message.data;
130
131 protocolVersion = (SSLProtocolVersion)SSLDecodeInt(p, 2);
132 p += 2;
df0e469f
A
133 /* FIXME this should probably send appropriate alerts */
134 err = sslVerifyProtVersion(ctx, protocolVersion, &negVersion);
135 if(err) {
136 return err;
5a719ac8 137 }
df0e469f
A
138 ctx->negProtocolVersion = negVersion;
139 switch(negVersion) {
5a719ac8
A
140 case SSL_Version_3_0:
141 ctx->sslTslCalls = &Ssl3Callouts;
142 break;
143 case TLS_Version_1_0:
144 ctx->sslTslCalls = &Tls1Callouts;
145 break;
146 default:
147 return errSSLNegotiation;
148 }
149 sslLogNegotiateDebug("===SSL3 client: negVersion is %d_%d",
df0e469f 150 (negVersion >> 8) & 0xff, negVersion & 0xff);
5a719ac8
A
151
152 memcpy(ctx->serverRandom, p, 32);
153 p += 32;
154
155 sessionIDLen = *p++;
156 if (message.length != 38 + sessionIDLen) {
157 sslErrorLog("SSLProcessServerHello: msg len error 2\n");
158 return errSSLProtocol;
159 }
160 if (sessionIDLen > 0 && ctx->peerID.data != 0)
161 { /* Don't die on error; just treat it as an uncached session */
162 err = SSLAllocBuffer(ctx->sessionID, sessionIDLen, ctx);
163 if (err == 0)
164 memcpy(ctx->sessionID.data, p, sessionIDLen);
165 }
166 p += sessionIDLen;
167
168 ctx->selectedCipher = (UInt16)SSLDecodeInt(p,2);
169 sslLogNegotiateDebug("===ssl3: server requests cipherKind %d",
170 (unsigned)ctx->selectedCipher);
171 p += 2;
172 if ((err = FindCipherSpec(ctx)) != 0) {
173 return err;
174 }
175
176 if (*p++ != 0) /* Compression */
177 return unimpErr;
178
179 assert(p == message.data + message.length);
180 return noErr;
181}
182
183OSStatus
184SSLEncodeClientHello(SSLRecord &clientHello, SSLContext *ctx)
185{
186 unsigned length, i;
187 OSStatus err;
188 unsigned char *p;
189 SSLBuffer sessionIdentifier;
190 UInt16 sessionIDLen;
191
192 assert(ctx->protocolSide == SSL_ClientSide);
df0e469f 193
5a719ac8
A
194 sessionIDLen = 0;
195 if (ctx->resumableSession.data != 0)
196 { if ((err = SSLRetrieveSessionID(ctx->resumableSession,
197 &sessionIdentifier, ctx)) != 0)
198 { return err;
199 }
200 sessionIDLen = sessionIdentifier.length;
201 }
202
203 length = 39 + 2*(ctx->numValidCipherSpecs) + sessionIDLen;
204
df0e469f
A
205 err = sslGetMaxProtVersion(ctx, &clientHello.protocolVersion);
206 if(err) {
207 /* we don't have a protocol enabled */
208 return err;
209 }
5a719ac8
A
210 clientHello.contentType = SSL_RecordTypeHandshake;
211 if ((err = SSLAllocBuffer(clientHello.contents, length + 4, ctx)) != 0)
212 return err;
213
214 p = clientHello.contents.data;
215 *p++ = SSL_HdskClientHello;
216 p = SSLEncodeInt(p, length, 3);
df0e469f 217 p = SSLEncodeInt(p, clientHello.protocolVersion, 2);
5a719ac8
A
218 sslLogNegotiateDebug("===SSL3 client: proclaiming max protocol "
219 "%d_%d capable ONLY",
df0e469f 220 clientHello.protocolVersion >> 8, clientHello.protocolVersion & 0xff);
5a719ac8
A
221 if ((err = SSLEncodeRandom(p, ctx)) != 0)
222 { SSLFreeBuffer(clientHello.contents, ctx);
223 return err;
224 }
225 memcpy(ctx->clientRandom, p, SSL_CLIENT_SRVR_RAND_SIZE);
226 p += 32;
227 *p++ = sessionIDLen; /* 1 byte vector length */
228 if (sessionIDLen > 0)
229 { memcpy(p, sessionIdentifier.data, sessionIDLen);
230 if ((err = SSLFreeBuffer(sessionIdentifier, ctx)) != 0)
231 return err;
232 }
233 p += sessionIDLen;
234 p = SSLEncodeInt(p, 2*(ctx->numValidCipherSpecs), 2);
235 /* 2 byte long vector length */
236 for (i = 0; i<ctx->numValidCipherSpecs; ++i)
237 p = SSLEncodeInt(p, ctx->validCipherSpecs[i].cipherSpec, 2);
238 *p++ = 1; /* 1 byte long vector */
239 *p++ = 0; /* null compression */
240
241 assert(p == clientHello.contents.data + clientHello.contents.length);
242
243 if ((err = SSLInitMessageHashes(ctx)) != 0)
244 return err;
245
246 return noErr;
247}
248
249OSStatus
250SSLProcessClientHello(SSLBuffer message, SSLContext *ctx)
251{ OSStatus err;
df0e469f 252 SSLProtocolVersion negVersion;
5a719ac8
A
253 UInt16 cipherListLen, cipherCount, desiredSpec, cipherSpec;
254 UInt8 sessionIDLen, compressionCount;
255 UInt8 *charPtr;
256 unsigned i;
257
258 if (message.length < 41) {
259 sslErrorLog("SSLProcessClientHello: msg len error 1\n");
260 return errSSLProtocol;
261 }
262 charPtr = message.data;
df0e469f 263 ctx->clientReqProtocol = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
5a719ac8 264 charPtr += 2;
df0e469f
A
265 err = sslVerifyProtVersion(ctx, ctx->clientReqProtocol, &negVersion);
266 if(err) {
267 return err;
5a719ac8 268 }
df0e469f 269 switch(negVersion) {
5a719ac8
A
270 case SSL_Version_3_0:
271 ctx->sslTslCalls = &Ssl3Callouts;
272 break;
273 case TLS_Version_1_0:
274 ctx->sslTslCalls = &Tls1Callouts;
275 break;
276 default:
277 return errSSLNegotiation;
278 }
df0e469f 279 ctx->negProtocolVersion = negVersion;
5a719ac8 280 sslLogNegotiateDebug("===SSL3 server: negVersion is %d_%d",
df0e469f 281 negVersion >> 8, negVersion & 0xff);
5a719ac8
A
282
283 memcpy(ctx->clientRandom, charPtr, SSL_CLIENT_SRVR_RAND_SIZE);
284 charPtr += 32;
285 sessionIDLen = *(charPtr++);
286 if (message.length < (unsigned)(41 + sessionIDLen)) {
287 sslErrorLog("SSLProcessClientHello: msg len error 2\n");
288 return errSSLProtocol;
289 }
df0e469f
A
290 /* FIXME peerID is never set on server side.... */
291 if (sessionIDLen > 0 && ctx->peerID.data != 0)
5a719ac8
A
292 { /* Don't die on error; just treat it as an uncacheable session */
293 err = SSLAllocBuffer(ctx->sessionID, sessionIDLen, ctx);
294 if (err == 0)
295 memcpy(ctx->sessionID.data, charPtr, sessionIDLen);
296 }
297 charPtr += sessionIDLen;
298
299 cipherListLen = (UInt16)SSLDecodeInt(charPtr, 2);
300 /* Count of cipherSpecs, must be even & >= 2 */
301 charPtr += 2;
302 if ((cipherListLen & 1) ||
303 (cipherListLen < 2) ||
304 (message.length < (unsigned)(39 + sessionIDLen + cipherListLen))) {
305 sslErrorLog("SSLProcessClientHello: msg len error 3\n");
306 return errSSLProtocol;
307 }
308 cipherCount = cipherListLen/2;
309 cipherSpec = 0xFFFF; /* No match marker */
310 while (cipherSpec == 0xFFFF && cipherCount--)
311 { desiredSpec = (UInt16)SSLDecodeInt(charPtr, 2);
312 charPtr += 2;
313 for (i = 0; i <ctx->numValidCipherSpecs; i++)
314 { if (ctx->validCipherSpecs[i].cipherSpec == desiredSpec)
315 { cipherSpec = desiredSpec;
316 break;
317 }
318 }
319 }
320
321 if (cipherSpec == 0xFFFF)
322 return errSSLNegotiation;
323 charPtr += 2 * cipherCount; /* Advance past unchecked cipherCounts */
324 ctx->selectedCipher = cipherSpec;
325 if ((err = FindCipherSpec(ctx)) != 0) {
326 return err;
327 }
328 sslLogNegotiateDebug("ssl3 server: selecting cipherKind 0x%x", (unsigned)ctx->selectedCipher);
329
330 compressionCount = *(charPtr++);
331 if ((compressionCount < 1) ||
332 (message.length <
333 (unsigned)(38 + sessionIDLen + cipherListLen + compressionCount))) {
334 sslErrorLog("SSLProcessClientHello: msg len error 4\n");
335 return errSSLProtocol;
336 }
337 /* Ignore list; we're doing null */
338
339 if ((err = SSLInitMessageHashes(ctx)) != 0)
340 return err;
341
342 return noErr;
343}
344
345static OSStatus
346SSLEncodeRandom(unsigned char *p, SSLContext *ctx)
347{ SSLBuffer randomData;
348 OSStatus err;
349 UInt32 time;
350
351 if ((err = sslTime(&time)) != 0)
352 return err;
353 SSLEncodeInt(p, time, 4);
354 randomData.data = p+4;
355 randomData.length = 28;
356 if((err = sslRand(ctx, &randomData)) != 0)
357 return err;
358 return noErr;
359}
360
361OSStatus
362SSLInitMessageHashes(SSLContext *ctx)
363{ OSStatus err;
364
365 if ((err = CloseHash(SSLHashSHA1, ctx->shaState, ctx)) != 0)
366 return err;
367 if ((err = CloseHash(SSLHashMD5, ctx->md5State, ctx)) != 0)
368 return err;
369 if ((err = ReadyHash(SSLHashSHA1, ctx->shaState, ctx)) != 0)
370 return err;
371 if ((err = ReadyHash(SSLHashMD5, ctx->md5State, ctx)) != 0)
372 return err;
373 return noErr;
374}