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 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)
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)
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
);
93 rb
.length
= SSL_NULL_ID_LEN
;
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 */
104 sslLogNegotiateDebug("ssl3: server specifying cipherSuite 0x%lx",
105 (UInt32
)ctx
->selectedCipher
);
107 assert(charPtr
== serverHello
.contents
.data
+ serverHello
.contents
.length
);
113 SSLProcessServerHello(SSLBuffer message
, SSLContext
*ctx
)
115 SSLProtocolVersion protocolVersion
;
116 unsigned int sessionIDLen
;
119 assert(ctx
->protocolSide
== SSL_ClientSide
);
121 if (message
.length
< 38 || message
.length
> 70) {
122 sslErrorLog("SSLProcessServerHello: msg len error\n");
123 return errSSLProtocol
;
127 protocolVersion
= (SSLProtocolVersion
)SSLDecodeInt(p
, 2);
129 if (protocolVersion
> ctx
->maxProtocolVersion
) {
130 return errSSLNegotiation
;
132 ctx
->negProtocolVersion
= protocolVersion
;
133 switch(protocolVersion
) {
134 case SSL_Version_3_0
:
135 ctx
->sslTslCalls
= &Ssl3Callouts
;
137 case TLS_Version_1_0
:
138 ctx
->sslTslCalls
= &Tls1Callouts
;
141 return errSSLNegotiation
;
143 sslLogNegotiateDebug("===SSL3 client: negVersion is %d_%d",
144 (protocolVersion
>> 8) & 0xff, protocolVersion
& 0xff);
146 memcpy(ctx
->serverRandom
, p
, 32);
150 if (message
.length
!= 38 + sessionIDLen
) {
151 sslErrorLog("SSLProcessServerHello: msg len error 2\n");
152 return errSSLProtocol
;
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
);
158 memcpy(ctx
->sessionID
.data
, p
, sessionIDLen
);
162 ctx
->selectedCipher
= (UInt16
)SSLDecodeInt(p
,2);
163 sslLogNegotiateDebug("===ssl3: server requests cipherKind %d",
164 (unsigned)ctx
->selectedCipher
);
166 if ((err
= FindCipherSpec(ctx
)) != 0) {
170 if (*p
++ != 0) /* Compression */
173 assert(p
== message
.data
+ message
.length
);
178 SSLEncodeClientHello(SSLRecord
&clientHello
, SSLContext
*ctx
)
183 SSLBuffer sessionIdentifier
;
186 assert(ctx
->protocolSide
== SSL_ClientSide
);
189 if (ctx
->resumableSession
.data
!= 0)
190 { if ((err
= SSLRetrieveSessionID(ctx
->resumableSession
,
191 &sessionIdentifier
, ctx
)) != 0)
194 sessionIDLen
= sessionIdentifier
.length
;
197 length
= 39 + 2*(ctx
->numValidCipherSpecs
) + sessionIDLen
;
199 clientHello
.protocolVersion
= ctx
->maxProtocolVersion
;
200 clientHello
.contentType
= SSL_RecordTypeHandshake
;
201 if ((err
= SSLAllocBuffer(clientHello
.contents
, length
+ 4, ctx
)) != 0)
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
);
215 memcpy(ctx
->clientRandom
, p
, SSL_CLIENT_SRVR_RAND_SIZE
);
217 *p
++ = sessionIDLen
; /* 1 byte vector length */
218 if (sessionIDLen
> 0)
219 { memcpy(p
, sessionIdentifier
.data
, sessionIDLen
);
220 if ((err
= SSLFreeBuffer(sessionIdentifier
, ctx
)) != 0)
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 */
231 assert(p
== clientHello
.contents
.data
+ clientHello
.contents
.length
);
233 if ((err
= SSLInitMessageHashes(ctx
)) != 0)
240 SSLProcessClientHello(SSLBuffer message
, SSLContext
*ctx
)
242 SSLProtocolVersion clientVersion
;
243 UInt16 cipherListLen
, cipherCount
, desiredSpec
, cipherSpec
;
244 UInt8 sessionIDLen
, compressionCount
;
248 if (message
.length
< 41) {
249 sslErrorLog("SSLProcessClientHello: msg len error 1\n");
250 return errSSLProtocol
;
252 charPtr
= message
.data
;
253 clientVersion
= (SSLProtocolVersion
)SSLDecodeInt(charPtr
, 2);
255 if(clientVersion
> ctx
->maxProtocolVersion
) {
256 clientVersion
= ctx
->maxProtocolVersion
;
258 switch(clientVersion
) {
259 case SSL_Version_3_0
:
260 ctx
->sslTslCalls
= &Ssl3Callouts
;
262 case TLS_Version_1_0
:
263 ctx
->sslTslCalls
= &Tls1Callouts
;
266 return errSSLNegotiation
;
268 ctx
->negProtocolVersion
= clientVersion
;
269 sslLogNegotiateDebug("===SSL3 server: negVersion is %d_%d",
270 clientVersion
>> 8, clientVersion
& 0xff);
272 memcpy(ctx
->clientRandom
, charPtr
, SSL_CLIENT_SRVR_RAND_SIZE
);
274 sessionIDLen
= *(charPtr
++);
275 if (message
.length
< (unsigned)(41 + sessionIDLen
)) {
276 sslErrorLog("SSLProcessClientHello: msg len error 2\n");
277 return errSSLProtocol
;
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
);
283 memcpy(ctx
->sessionID
.data
, charPtr
, sessionIDLen
);
285 charPtr
+= sessionIDLen
;
287 cipherListLen
= (UInt16
)SSLDecodeInt(charPtr
, 2);
288 /* Count of cipherSpecs, must be even & >= 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
;
296 cipherCount
= cipherListLen
/2;
297 cipherSpec
= 0xFFFF; /* No match marker */
298 while (cipherSpec
== 0xFFFF && cipherCount
--)
299 { desiredSpec
= (UInt16
)SSLDecodeInt(charPtr
, 2);
301 for (i
= 0; i
<ctx
->numValidCipherSpecs
; i
++)
302 { if (ctx
->validCipherSpecs
[i
].cipherSpec
== desiredSpec
)
303 { cipherSpec
= desiredSpec
;
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) {
316 sslLogNegotiateDebug("ssl3 server: selecting cipherKind 0x%x", (unsigned)ctx
->selectedCipher
);
318 compressionCount
= *(charPtr
++);
319 if ((compressionCount
< 1) ||
321 (unsigned)(38 + sessionIDLen
+ cipherListLen
+ compressionCount
))) {
322 sslErrorLog("SSLProcessClientHello: msg len error 4\n");
323 return errSSLProtocol
;
325 /* Ignore list; we're doing null */
327 if ((err
= SSLInitMessageHashes(ctx
)) != 0)
334 SSLEncodeRandom(unsigned char *p
, SSLContext
*ctx
)
335 { SSLBuffer randomData
;
339 if ((err
= sslTime(&time
)) != 0)
341 SSLEncodeInt(p
, time
, 4);
342 randomData
.data
= p
+4;
343 randomData
.length
= 28;
344 if((err
= sslRand(ctx
, &randomData
)) != 0)
350 SSLInitMessageHashes(SSLContext
*ctx
)
353 if ((err
= CloseHash(SSLHashSHA1
, ctx
->shaState
, ctx
)) != 0)
355 if ((err
= CloseHash(SSLHashMD5
, ctx
->md5State
, ctx
)) != 0)
357 if ((err
= ReadyHash(SSLHashSHA1
, ctx
->shaState
, ctx
)) != 0)
359 if ((err
= ReadyHash(SSLHashMD5
, ctx
->md5State
, ctx
)) != 0)