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.
19 /* *********************************************************************
22 SSLRef 3.0 Final -- 11/19/96
24 Copyright (c)1996 by Netscape Communications Corp.
26 By retrieving this software you are bound by the licensing terms
27 disclosed in the file "LICENSE.txt". Please read it, and if you don't
28 accept the terms, delete this software.
30 SSLRef 3.0 was developed by Netscape Communications Corp. of Mountain
31 View, California <http://home.netscape.com/> and Consensus Development
32 Corporation of Berkeley, California <http://www.consensus.com/>.
34 *********************************************************************
36 File: sslsess.c SSL Session DB interface
38 This file contains functions which interact with the session database
39 to store and restore sessions and retrieve information from packed
42 ****************************************************************** */
68 #ifndef _CIPHER_SPECS_H_
69 #include "cipherSpecs.h"
72 #include "appleSession.h"
80 SSLProtocolVersion protocolVersion
;
82 UInt16 padding
; /* so remainder is word aligned */
83 UInt8 masterSecret
[48];
85 UInt8 certs
[1]; /* Actually, variable length */
89 * Cook up a (private) resumable session blob, based on the
90 * specified ctx, store it with ctx->peerID as the key.
91 * NOTE: This is contrary to the SSLRef3 spec, which claims that
92 * servers store resumable sessions using ctx->sessionID as the key.
93 * I don' think this is an issue...is it?
96 SSLAddSessionData(const SSLContext
*ctx
)
100 ResumableSession
*session
;
102 SSLCertificate
*cert
;
105 /* If we don't know who the peer is, we can't store a session */
106 if (ctx
->peerID
.data
== 0)
107 return SSLSessionNotFoundErr
;
109 sessionIDLen
= offsetof(ResumableSession
, certs
);
110 cert
= ctx
->peerCert
;
114 sessionIDLen
+= 4 + cert
->derCert
.length
;
118 if ((err
= SSLAllocBuffer(&sessionID
, sessionIDLen
, &ctx
->sysCtx
)) != 0)
121 session
= (ResumableSession
*)sessionID
.data
;
123 session
->sessionIDLen
= ctx
->sessionID
.length
;
124 memcpy(session
->sessionID
, ctx
->sessionID
.data
, session
->sessionIDLen
);
125 session
->protocolVersion
= ctx
->negProtocolVersion
;
126 session
->cipherSuite
= ctx
->selectedCipher
;
127 memcpy(session
->masterSecret
, ctx
->masterSecret
, 48);
128 session
->certCount
= certCount
;
129 session
->padding
= 0;
131 certDest
= session
->certs
;
132 cert
= ctx
->peerCert
;
134 { certDest
= SSLEncodeInt(certDest
, cert
->derCert
.length
, 4);
135 memcpy(certDest
, cert
->derCert
.data
, cert
->derCert
.length
);
136 certDest
+= cert
->derCert
.length
;
140 err
= sslAddSession(ctx
->peerID
, sessionID
);
141 SSLFreeBuffer(&sessionID
, &ctx
->sysCtx
);
147 * Retrieve resumable session data, from key ctx->peerID.
150 SSLGetSessionData(SSLBuffer
*sessionData
, const SSLContext
*ctx
)
153 if (ctx
->peerID
.data
== 0)
154 return ERR(SSLSessionNotFoundErr
);
156 sessionData
->data
= 0;
158 err
= sslGetSession(ctx
->peerID
, sessionData
);
159 if (sessionData
->data
== 0)
160 return ERR(SSLSessionNotFoundErr
);
166 SSLDeleteSessionData(const SSLContext
*ctx
)
169 if (ctx
->peerID
.data
== 0)
170 return SSLSessionNotFoundErr
;
172 err
= sslDeleteSession(ctx
->peerID
);
177 * Given a sessionData blob, obtain the associated sessionID (NOT the key...).
180 SSLRetrieveSessionID(
181 const SSLBuffer sessionData
,
182 SSLBuffer
*identifier
,
183 const SSLContext
*ctx
)
185 ResumableSession
*session
;
187 session
= (ResumableSession
*) sessionData
.data
;
188 if ((err
= SSLAllocBuffer(identifier
, session
->sessionIDLen
, &ctx
->sysCtx
)) != 0)
190 memcpy(identifier
->data
, session
->sessionID
, session
->sessionIDLen
);
195 * Obtain the protocol version associated with a specified resumable session blob.
198 SSLRetrieveSessionProtocolVersion(
199 const SSLBuffer sessionData
,
200 SSLProtocolVersion
*version
,
201 const SSLContext
*ctx
)
202 { ResumableSession
*session
;
204 session
= (ResumableSession
*) sessionData
.data
;
205 *version
= session
->protocolVersion
;
210 * Retrieve session state from specified sessionData blob, install into
211 * ctx. Presumably, ctx->sessionID and
212 * ctx->negProtocolVersion are already init'd (from the above two functions).
216 * Netscape Enterprise Server is known to change cipherspecs upon session resumption.
217 * For example, connecting to cdnow.com with all ciphersuites enabled results in
218 * CipherSuite 4 (SSL_RSA_WITH_RC4_128_MD5) being selected on the first session,
219 * and CipherSuite 10 (SSL_RSA_WITH_3DES_EDE_CBC_SHA) being selected on subsequent
220 * sessions. This is contrary to the SSL3.0 spec, sesion 7.6.1.3, describing the
221 * Server Hello message.
223 * This anomaly does not occur if only RC4 ciphers are enabled in the Client Hello
224 * message. It also does not happen in SSL V2.
226 #define ALLOW_CIPHERSPEC_CHANGE 1
229 SSLInstallSessionFromData(const SSLBuffer sessionData
, SSLContext
*ctx
)
231 ResumableSession
*session
;
232 uint8
*storedCertProgress
;
233 SSLCertificate
*cert
, *lastCert
;
237 session
= (ResumableSession
*)sessionData
.data
;
239 CASSERT(ctx
->negProtocolVersion
== session
->protocolVersion
);
242 * For SSLv3 and TLSv1, we know that selectedCipher has already been specified in
243 * SSLProcessServerHello(). An SSLv2 server hello message with a session
244 * ID hit contains no CipherKind field so we set it here.
246 if(ctx
->negProtocolVersion
== SSL_Version_2_0
) {
247 if(ctx
->protocolSide
== SSL_ClientSide
) {
248 assert(ctx
->selectedCipher
== 0);
249 ctx
->selectedCipher
= session
->cipherSuite
;
253 * Else...what if they don't match? Could never happen, right?
254 * Wouldn't that mean the client is trying to switch ciphers on us?
256 if(ctx
->selectedCipher
!= session
->cipherSuite
) {
257 errorLog2("+++SSL2: CipherSpec change from %d to %d on session "
259 session
->cipherSuite
, ctx
->selectedCipher
);
260 return SSLProtocolErr
;
265 assert(ctx
->selectedCipher
!= 0);
266 if(ctx
->selectedCipher
!= session
->cipherSuite
) {
267 #if ALLOW_CIPHERSPEC_CHANGE
268 dprintf2("+++WARNING: CipherSpec change from %d to %d on session resume\n",
269 session
->cipherSuite
, ctx
->selectedCipher
);
271 errorLog2("+++SSL: CipherSpec change from %d to %d on session resume\n",
272 session
->cipherSuite
, ctx
->selectedCipher
);
273 return SSLProtocolErr
;
277 if ((err
= FindCipherSpec(ctx
)) != 0) {
280 memcpy(ctx
->masterSecret
, session
->masterSecret
, 48);
283 storedCertProgress
= session
->certs
;
284 certCount
= session
->certCount
;
288 cert
= (SSLCertificate
*)sslMalloc(sizeof(SSLCertificate
));
293 certLen
= SSLDecodeInt(storedCertProgress
, 4);
294 storedCertProgress
+= 4;
295 if ((err
= SSLAllocBuffer(&cert
->derCert
, certLen
, &ctx
->sysCtx
)) != 0)
300 memcpy(cert
->derCert
.data
, storedCertProgress
, certLen
);
301 storedCertProgress
+= certLen
;
303 ctx
->peerCert
= cert
;
305 lastCert
->next
= cert
;