]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslHandshakeHello.cpp
Security-54.1.3.tar.gz
[apple/security.git] / SecureTransport / sslHandshakeHello.cpp
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
42 static 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
52 OSStatus
53 SSLEncodeServerHello(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
67 sslLogNegotiateDebug("===SSL3 server: sending version %d_%d",
68 ctx->negProtocolVersion >> 8, ctx->negProtocolVersion & 0xff);
69 sslLogNegotiateDebug("...sessionIDLen = %d", sessionIDLen);
70 serverHello.protocolVersion = ctx->negProtocolVersion;
71 serverHello.contentType = SSL_RecordTypeHandshake;
72 if ((err = SSLAllocBuffer(serverHello.contents, 42 + sessionIDLen, ctx)) != 0)
73 return err;
74
75 charPtr = serverHello.contents.data;
76 *charPtr++ = SSL_HdskServerHello;
77 charPtr = SSLEncodeInt(charPtr, 38 + sessionIDLen, 3);
78 charPtr = SSLEncodeInt(charPtr, serverHello.protocolVersion, 2);
79 if ((err = SSLEncodeRandom(charPtr, ctx)) != 0)
80 return err;
81 memcpy(ctx->serverRandom, charPtr, SSL_CLIENT_SRVR_RAND_SIZE);
82 charPtr += SSL_CLIENT_SRVR_RAND_SIZE;
83 *(charPtr++) = (UInt8)sessionIDLen;
84 #if SSL_IE_NULL_RESUME_BUG
85 if(ctx->sessionID.data != NULL) {
86 /* normal path for enabled resumable session */
87 memcpy(charPtr, ctx->sessionID.data, sessionIDLen);
88 }
89 else {
90 /* IE workaround */
91 SSLBuffer rb;
92 rb.data = charPtr;
93 rb.length = SSL_NULL_ID_LEN;
94 sslRand(ctx, &rb);
95 }
96 #else
97 if (sessionIDLen > 0)
98 memcpy(charPtr, ctx->sessionID.data, sessionIDLen);
99 #endif /* SSL_IE_NULL_RESUME_BUG */
100 charPtr += sessionIDLen;
101 charPtr = SSLEncodeInt(charPtr, ctx->selectedCipher, 2);
102 *(charPtr++) = 0; /* Null compression */
103
104 sslLogNegotiateDebug("ssl3: server specifying cipherSuite 0x%lx",
105 (UInt32)ctx->selectedCipher);
106
107 assert(charPtr == serverHello.contents.data + serverHello.contents.length);
108
109 return noErr;
110 }
111
112 OSStatus
113 SSLProcessServerHello(SSLBuffer message, SSLContext *ctx)
114 { OSStatus err;
115 SSLProtocolVersion protocolVersion;
116 unsigned int sessionIDLen;
117 UInt8 *p;
118
119 assert(ctx->protocolSide == SSL_ClientSide);
120
121 if (message.length < 38 || message.length > 70) {
122 sslErrorLog("SSLProcessServerHello: msg len error\n");
123 return errSSLProtocol;
124 }
125 p = message.data;
126
127 protocolVersion = (SSLProtocolVersion)SSLDecodeInt(p, 2);
128 p += 2;
129 if (protocolVersion > ctx->maxProtocolVersion) {
130 return errSSLNegotiation;
131 }
132 ctx->negProtocolVersion = protocolVersion;
133 switch(protocolVersion) {
134 case SSL_Version_3_0:
135 ctx->sslTslCalls = &Ssl3Callouts;
136 break;
137 case TLS_Version_1_0:
138 ctx->sslTslCalls = &Tls1Callouts;
139 break;
140 default:
141 return errSSLNegotiation;
142 }
143 sslLogNegotiateDebug("===SSL3 client: negVersion is %d_%d",
144 (protocolVersion >> 8) & 0xff, protocolVersion & 0xff);
145
146 memcpy(ctx->serverRandom, p, 32);
147 p += 32;
148
149 sessionIDLen = *p++;
150 if (message.length != 38 + sessionIDLen) {
151 sslErrorLog("SSLProcessServerHello: msg len error 2\n");
152 return errSSLProtocol;
153 }
154 if (sessionIDLen > 0 && ctx->peerID.data != 0)
155 { /* Don't die on error; just treat it as an uncached session */
156 err = SSLAllocBuffer(ctx->sessionID, sessionIDLen, ctx);
157 if (err == 0)
158 memcpy(ctx->sessionID.data, p, sessionIDLen);
159 }
160 p += sessionIDLen;
161
162 ctx->selectedCipher = (UInt16)SSLDecodeInt(p,2);
163 sslLogNegotiateDebug("===ssl3: server requests cipherKind %d",
164 (unsigned)ctx->selectedCipher);
165 p += 2;
166 if ((err = FindCipherSpec(ctx)) != 0) {
167 return err;
168 }
169
170 if (*p++ != 0) /* Compression */
171 return unimpErr;
172
173 assert(p == message.data + message.length);
174 return noErr;
175 }
176
177 OSStatus
178 SSLEncodeClientHello(SSLRecord &clientHello, SSLContext *ctx)
179 {
180 unsigned length, i;
181 OSStatus err;
182 unsigned char *p;
183 SSLBuffer sessionIdentifier;
184 UInt16 sessionIDLen;
185
186 assert(ctx->protocolSide == SSL_ClientSide);
187
188 sessionIDLen = 0;
189 if (ctx->resumableSession.data != 0)
190 { if ((err = SSLRetrieveSessionID(ctx->resumableSession,
191 &sessionIdentifier, ctx)) != 0)
192 { return err;
193 }
194 sessionIDLen = sessionIdentifier.length;
195 }
196
197 length = 39 + 2*(ctx->numValidCipherSpecs) + sessionIDLen;
198
199 clientHello.protocolVersion = ctx->maxProtocolVersion;
200 clientHello.contentType = SSL_RecordTypeHandshake;
201 if ((err = SSLAllocBuffer(clientHello.contents, length + 4, ctx)) != 0)
202 return err;
203
204 p = clientHello.contents.data;
205 *p++ = SSL_HdskClientHello;
206 p = SSLEncodeInt(p, length, 3);
207 p = SSLEncodeInt(p, ctx->maxProtocolVersion, 2);
208 sslLogNegotiateDebug("===SSL3 client: proclaiming max protocol "
209 "%d_%d capable ONLY",
210 ctx->maxProtocolVersion >> 8, ctx->maxProtocolVersion & 0xff);
211 if ((err = SSLEncodeRandom(p, ctx)) != 0)
212 { SSLFreeBuffer(clientHello.contents, ctx);
213 return err;
214 }
215 memcpy(ctx->clientRandom, p, SSL_CLIENT_SRVR_RAND_SIZE);
216 p += 32;
217 *p++ = sessionIDLen; /* 1 byte vector length */
218 if (sessionIDLen > 0)
219 { memcpy(p, sessionIdentifier.data, sessionIDLen);
220 if ((err = SSLFreeBuffer(sessionIdentifier, ctx)) != 0)
221 return err;
222 }
223 p += sessionIDLen;
224 p = SSLEncodeInt(p, 2*(ctx->numValidCipherSpecs), 2);
225 /* 2 byte long vector length */
226 for (i = 0; i<ctx->numValidCipherSpecs; ++i)
227 p = SSLEncodeInt(p, ctx->validCipherSpecs[i].cipherSpec, 2);
228 *p++ = 1; /* 1 byte long vector */
229 *p++ = 0; /* null compression */
230
231 assert(p == clientHello.contents.data + clientHello.contents.length);
232
233 if ((err = SSLInitMessageHashes(ctx)) != 0)
234 return err;
235
236 return noErr;
237 }
238
239 OSStatus
240 SSLProcessClientHello(SSLBuffer message, SSLContext *ctx)
241 { OSStatus err;
242 SSLProtocolVersion clientVersion;
243 UInt16 cipherListLen, cipherCount, desiredSpec, cipherSpec;
244 UInt8 sessionIDLen, compressionCount;
245 UInt8 *charPtr;
246 unsigned i;
247
248 if (message.length < 41) {
249 sslErrorLog("SSLProcessClientHello: msg len error 1\n");
250 return errSSLProtocol;
251 }
252 charPtr = message.data;
253 clientVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
254 charPtr += 2;
255 if(clientVersion > ctx->maxProtocolVersion) {
256 clientVersion = ctx->maxProtocolVersion;
257 }
258 switch(clientVersion) {
259 case SSL_Version_3_0:
260 ctx->sslTslCalls = &Ssl3Callouts;
261 break;
262 case TLS_Version_1_0:
263 ctx->sslTslCalls = &Tls1Callouts;
264 break;
265 default:
266 return errSSLNegotiation;
267 }
268 ctx->negProtocolVersion = clientVersion;
269 sslLogNegotiateDebug("===SSL3 server: negVersion is %d_%d",
270 clientVersion >> 8, clientVersion & 0xff);
271
272 memcpy(ctx->clientRandom, charPtr, SSL_CLIENT_SRVR_RAND_SIZE);
273 charPtr += 32;
274 sessionIDLen = *(charPtr++);
275 if (message.length < (unsigned)(41 + sessionIDLen)) {
276 sslErrorLog("SSLProcessClientHello: msg len error 2\n");
277 return errSSLProtocol;
278 }
279 if (sessionIDLen > 0 && ctx->peerID.data != 0)
280 { /* Don't die on error; just treat it as an uncacheable session */
281 err = SSLAllocBuffer(ctx->sessionID, sessionIDLen, ctx);
282 if (err == 0)
283 memcpy(ctx->sessionID.data, charPtr, sessionIDLen);
284 }
285 charPtr += sessionIDLen;
286
287 cipherListLen = (UInt16)SSLDecodeInt(charPtr, 2);
288 /* Count of cipherSpecs, must be even & >= 2 */
289 charPtr += 2;
290 if ((cipherListLen & 1) ||
291 (cipherListLen < 2) ||
292 (message.length < (unsigned)(39 + sessionIDLen + cipherListLen))) {
293 sslErrorLog("SSLProcessClientHello: msg len error 3\n");
294 return errSSLProtocol;
295 }
296 cipherCount = cipherListLen/2;
297 cipherSpec = 0xFFFF; /* No match marker */
298 while (cipherSpec == 0xFFFF && cipherCount--)
299 { desiredSpec = (UInt16)SSLDecodeInt(charPtr, 2);
300 charPtr += 2;
301 for (i = 0; i <ctx->numValidCipherSpecs; i++)
302 { if (ctx->validCipherSpecs[i].cipherSpec == desiredSpec)
303 { cipherSpec = desiredSpec;
304 break;
305 }
306 }
307 }
308
309 if (cipherSpec == 0xFFFF)
310 return errSSLNegotiation;
311 charPtr += 2 * cipherCount; /* Advance past unchecked cipherCounts */
312 ctx->selectedCipher = cipherSpec;
313 if ((err = FindCipherSpec(ctx)) != 0) {
314 return err;
315 }
316 sslLogNegotiateDebug("ssl3 server: selecting cipherKind 0x%x", (unsigned)ctx->selectedCipher);
317
318 compressionCount = *(charPtr++);
319 if ((compressionCount < 1) ||
320 (message.length <
321 (unsigned)(38 + sessionIDLen + cipherListLen + compressionCount))) {
322 sslErrorLog("SSLProcessClientHello: msg len error 4\n");
323 return errSSLProtocol;
324 }
325 /* Ignore list; we're doing null */
326
327 if ((err = SSLInitMessageHashes(ctx)) != 0)
328 return err;
329
330 return noErr;
331 }
332
333 static OSStatus
334 SSLEncodeRandom(unsigned char *p, SSLContext *ctx)
335 { SSLBuffer randomData;
336 OSStatus err;
337 UInt32 time;
338
339 if ((err = sslTime(&time)) != 0)
340 return err;
341 SSLEncodeInt(p, time, 4);
342 randomData.data = p+4;
343 randomData.length = 28;
344 if((err = sslRand(ctx, &randomData)) != 0)
345 return err;
346 return noErr;
347 }
348
349 OSStatus
350 SSLInitMessageHashes(SSLContext *ctx)
351 { OSStatus err;
352
353 if ((err = CloseHash(SSLHashSHA1, ctx->shaState, ctx)) != 0)
354 return err;
355 if ((err = CloseHash(SSLHashMD5, ctx->md5State, ctx)) != 0)
356 return err;
357 if ((err = ReadyHash(SSLHashSHA1, ctx->shaState, ctx)) != 0)
358 return err;
359 if ((err = ReadyHash(SSLHashMD5, ctx->md5State, ctx)) != 0)
360 return err;
361 return noErr;
362 }