2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 File: sslHandshakeHello.c
22 Contains: Support for client hello and server hello messages.
24 Written by: Doug Mitchell
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
30 #include "sslContext.h"
31 #include "sslHandshake.h"
32 #include "sslMemory.h"
33 #include "sslSession.h"
36 #include "appleCdsa.h"
37 #include "sslDigests.h"
38 #include "cipherSpecs.h"
42 static OSStatus
SSLEncodeRandom(unsigned char *p
, SSLContext
*ctx
);
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 */
53 SSLEncodeServerHello(SSLRecord
&serverHello
, SSLContext
*ctx
)
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
;
65 #endif /* SSL_IE_NULL_RESUME_BUG */
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
);
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)
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)
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
);
97 rb
.length
= SSL_NULL_ID_LEN
;
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 */
108 sslLogNegotiateDebug("ssl3: server specifying cipherSuite 0x%lx",
109 (UInt32
)ctx
->selectedCipher
);
111 assert(charPtr
== serverHello
.contents
.data
+ serverHello
.contents
.length
);
117 SSLProcessServerHello(SSLBuffer message
, SSLContext
*ctx
)
119 SSLProtocolVersion protocolVersion
, negVersion
;
120 unsigned int sessionIDLen
;
123 assert(ctx
->protocolSide
== SSL_ClientSide
);
125 if (message
.length
< 38 || message
.length
> 70) {
126 sslErrorLog("SSLProcessServerHello: msg len error\n");
127 return errSSLProtocol
;
131 protocolVersion
= (SSLProtocolVersion
)SSLDecodeInt(p
, 2);
133 /* FIXME this should probably send appropriate alerts */
134 err
= sslVerifyProtVersion(ctx
, protocolVersion
, &negVersion
);
138 ctx
->negProtocolVersion
= negVersion
;
140 case SSL_Version_3_0
:
141 ctx
->sslTslCalls
= &Ssl3Callouts
;
143 case TLS_Version_1_0
:
144 ctx
->sslTslCalls
= &Tls1Callouts
;
147 return errSSLNegotiation
;
149 sslLogNegotiateDebug("===SSL3 client: negVersion is %d_%d",
150 (negVersion
>> 8) & 0xff, negVersion
& 0xff);
152 memcpy(ctx
->serverRandom
, p
, 32);
156 if (message
.length
!= 38 + sessionIDLen
) {
157 sslErrorLog("SSLProcessServerHello: msg len error 2\n");
158 return errSSLProtocol
;
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
);
164 memcpy(ctx
->sessionID
.data
, p
, sessionIDLen
);
168 ctx
->selectedCipher
= (UInt16
)SSLDecodeInt(p
,2);
169 sslLogNegotiateDebug("===ssl3: server requests cipherKind %d",
170 (unsigned)ctx
->selectedCipher
);
172 if ((err
= FindCipherSpec(ctx
)) != 0) {
176 if (*p
++ != 0) /* Compression */
179 assert(p
== message
.data
+ message
.length
);
184 SSLEncodeClientHello(SSLRecord
&clientHello
, SSLContext
*ctx
)
189 SSLBuffer sessionIdentifier
;
192 assert(ctx
->protocolSide
== SSL_ClientSide
);
195 if (ctx
->resumableSession
.data
!= 0)
196 { if ((err
= SSLRetrieveSessionID(ctx
->resumableSession
,
197 &sessionIdentifier
, ctx
)) != 0)
200 sessionIDLen
= sessionIdentifier
.length
;
203 length
= 39 + 2*(ctx
->numValidCipherSpecs
) + sessionIDLen
;
205 err
= sslGetMaxProtVersion(ctx
, &clientHello
.protocolVersion
);
207 /* we don't have a protocol enabled */
210 clientHello
.contentType
= SSL_RecordTypeHandshake
;
211 if ((err
= SSLAllocBuffer(clientHello
.contents
, length
+ 4, ctx
)) != 0)
214 p
= clientHello
.contents
.data
;
215 *p
++ = SSL_HdskClientHello
;
216 p
= SSLEncodeInt(p
, length
, 3);
217 p
= SSLEncodeInt(p
, clientHello
.protocolVersion
, 2);
218 sslLogNegotiateDebug("===SSL3 client: proclaiming max protocol "
219 "%d_%d capable ONLY",
220 clientHello
.protocolVersion
>> 8, clientHello
.protocolVersion
& 0xff);
221 if ((err
= SSLEncodeRandom(p
, ctx
)) != 0)
222 { SSLFreeBuffer(clientHello
.contents
, ctx
);
225 memcpy(ctx
->clientRandom
, p
, SSL_CLIENT_SRVR_RAND_SIZE
);
227 *p
++ = sessionIDLen
; /* 1 byte vector length */
228 if (sessionIDLen
> 0)
229 { memcpy(p
, sessionIdentifier
.data
, sessionIDLen
);
230 if ((err
= SSLFreeBuffer(sessionIdentifier
, ctx
)) != 0)
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 */
241 assert(p
== clientHello
.contents
.data
+ clientHello
.contents
.length
);
243 if ((err
= SSLInitMessageHashes(ctx
)) != 0)
250 SSLProcessClientHello(SSLBuffer message
, SSLContext
*ctx
)
252 SSLProtocolVersion negVersion
;
253 UInt16 cipherListLen
, cipherCount
, desiredSpec
, cipherSpec
;
254 UInt8 sessionIDLen
, compressionCount
;
258 if (message
.length
< 41) {
259 sslErrorLog("SSLProcessClientHello: msg len error 1\n");
260 return errSSLProtocol
;
262 charPtr
= message
.data
;
263 ctx
->clientReqProtocol
= (SSLProtocolVersion
)SSLDecodeInt(charPtr
, 2);
265 err
= sslVerifyProtVersion(ctx
, ctx
->clientReqProtocol
, &negVersion
);
270 case SSL_Version_3_0
:
271 ctx
->sslTslCalls
= &Ssl3Callouts
;
273 case TLS_Version_1_0
:
274 ctx
->sslTslCalls
= &Tls1Callouts
;
277 return errSSLNegotiation
;
279 ctx
->negProtocolVersion
= negVersion
;
280 sslLogNegotiateDebug("===SSL3 server: negVersion is %d_%d",
281 negVersion
>> 8, negVersion
& 0xff);
283 memcpy(ctx
->clientRandom
, charPtr
, SSL_CLIENT_SRVR_RAND_SIZE
);
285 sessionIDLen
= *(charPtr
++);
286 if (message
.length
< (unsigned)(41 + sessionIDLen
)) {
287 sslErrorLog("SSLProcessClientHello: msg len error 2\n");
288 return errSSLProtocol
;
290 /* FIXME peerID is never set on server side.... */
291 if (sessionIDLen
> 0 && ctx
->peerID
.data
!= 0)
292 { /* Don't die on error; just treat it as an uncacheable session */
293 err
= SSLAllocBuffer(ctx
->sessionID
, sessionIDLen
, ctx
);
295 memcpy(ctx
->sessionID
.data
, charPtr
, sessionIDLen
);
297 charPtr
+= sessionIDLen
;
299 cipherListLen
= (UInt16
)SSLDecodeInt(charPtr
, 2);
300 /* Count of cipherSpecs, must be even & >= 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
;
308 cipherCount
= cipherListLen
/2;
309 cipherSpec
= 0xFFFF; /* No match marker */
310 while (cipherSpec
== 0xFFFF && cipherCount
--)
311 { desiredSpec
= (UInt16
)SSLDecodeInt(charPtr
, 2);
313 for (i
= 0; i
<ctx
->numValidCipherSpecs
; i
++)
314 { if (ctx
->validCipherSpecs
[i
].cipherSpec
== desiredSpec
)
315 { cipherSpec
= desiredSpec
;
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) {
328 sslLogNegotiateDebug("ssl3 server: selecting cipherKind 0x%x", (unsigned)ctx
->selectedCipher
);
330 compressionCount
= *(charPtr
++);
331 if ((compressionCount
< 1) ||
333 (unsigned)(38 + sessionIDLen
+ cipherListLen
+ compressionCount
))) {
334 sslErrorLog("SSLProcessClientHello: msg len error 4\n");
335 return errSSLProtocol
;
337 /* Ignore list; we're doing null */
339 if ((err
= SSLInitMessageHashes(ctx
)) != 0)
346 SSLEncodeRandom(unsigned char *p
, SSLContext
*ctx
)
347 { SSLBuffer randomData
;
351 if ((err
= sslTime(&time
)) != 0)
353 SSLEncodeInt(p
, time
, 4);
354 randomData
.data
= p
+4;
355 randomData
.length
= 28;
356 if((err
= sslRand(ctx
, &randomData
)) != 0)
362 SSLInitMessageHashes(SSLContext
*ctx
)
365 if ((err
= CloseHash(SSLHashSHA1
, ctx
->shaState
, ctx
)) != 0)
367 if ((err
= CloseHash(SSLHashMD5
, ctx
->md5State
, ctx
)) != 0)
369 if ((err
= ReadyHash(SSLHashSHA1
, ctx
->shaState
, ctx
)) != 0)
371 if ((err
= ReadyHash(SSLHashMD5
, ctx
->md5State
, ctx
)) != 0)