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 #include "sslContext.h"
21 #include "sslSession.h"
22 #include "sslMemory.h"
25 #include "cipherSpecs.h"
26 #include "appleSession.h"
35 SSLProtocolVersion protocolVersion
;
37 UInt16 padding
; /* so remainder is word aligned */
38 UInt8 masterSecret
[48];
40 UInt8 certs
[1]; /* Actually, variable length */
44 * Cook up a (private) resumable session blob, based on the
45 * specified ctx, store it with ctx->peerID as the key.
46 * NOTE: This is contrary to the SSL v3 spec, which claims that
47 * servers store resumable sessions using ctx->sessionID as the key.
48 * I don' think this is an issue...is it?
51 SSLAddSessionData(const SSLContext
*ctx
)
55 ResumableSession
*session
;
60 /* If we don't know who the peer is, we can't store a session */
61 if (ctx
->peerID
.data
== 0)
62 return errSSLSessionNotFound
;
64 sessionIDLen
= offsetof(ResumableSession
, certs
);
69 sessionIDLen
+= 4 + cert
->derCert
.length
;
73 if ((err
= SSLAllocBuffer(sessionID
, sessionIDLen
, ctx
)) != 0)
76 session
= (ResumableSession
*)sessionID
.data
;
78 session
->sessionIDLen
= ctx
->sessionID
.length
;
79 memcpy(session
->sessionID
, ctx
->sessionID
.data
, session
->sessionIDLen
);
80 session
->protocolVersion
= ctx
->negProtocolVersion
;
81 session
->cipherSuite
= ctx
->selectedCipher
;
82 memcpy(session
->masterSecret
, ctx
->masterSecret
, 48);
83 session
->certCount
= certCount
;
86 certDest
= session
->certs
;
89 { certDest
= SSLEncodeInt(certDest
, cert
->derCert
.length
, 4);
90 memcpy(certDest
, cert
->derCert
.data
, cert
->derCert
.length
);
91 certDest
+= cert
->derCert
.length
;
95 err
= sslAddSession(ctx
->peerID
, sessionID
);
96 SSLFreeBuffer(sessionID
, ctx
);
102 * Retrieve resumable session data, from key ctx->peerID.
105 SSLGetSessionData(SSLBuffer
*sessionData
, const SSLContext
*ctx
)
108 if (ctx
->peerID
.data
== 0)
109 return errSSLSessionNotFound
;
111 sessionData
->data
= 0;
113 err
= sslGetSession(ctx
->peerID
, sessionData
);
114 if (sessionData
->data
== 0)
115 return errSSLSessionNotFound
;
121 SSLDeleteSessionData(const SSLContext
*ctx
)
124 if (ctx
->peerID
.data
== 0)
125 return errSSLSessionNotFound
;
127 err
= sslDeleteSession(ctx
->peerID
);
132 * Given a sessionData blob, obtain the associated sessionID (NOT the key...).
135 SSLRetrieveSessionID(
136 const SSLBuffer sessionData
,
137 SSLBuffer
*identifier
,
138 const SSLContext
*ctx
)
140 ResumableSession
*session
;
142 session
= (ResumableSession
*) sessionData
.data
;
143 if ((err
= SSLAllocBuffer(*identifier
, session
->sessionIDLen
, ctx
)) != 0)
145 memcpy(identifier
->data
, session
->sessionID
, session
->sessionIDLen
);
150 * Obtain the protocol version associated with a specified resumable session blob.
153 SSLRetrieveSessionProtocolVersion(
154 const SSLBuffer sessionData
,
155 SSLProtocolVersion
*version
,
156 const SSLContext
*ctx
)
157 { ResumableSession
*session
;
159 session
= (ResumableSession
*) sessionData
.data
;
160 *version
= session
->protocolVersion
;
165 * Retrieve session state from specified sessionData blob, install into
166 * ctx. Presumably, ctx->sessionID and
167 * ctx->negProtocolVersion are already init'd (from the above two functions).
171 * Netscape Enterprise Server is known to change cipherspecs upon session resumption.
172 * For example, connecting to cdnow.com with all ciphersuites enabled results in
173 * CipherSuite 4 (SSL_RSA_WITH_RC4_128_MD5) being selected on the first session,
174 * and CipherSuite 10 (SSL_RSA_WITH_3DES_EDE_CBC_SHA) being selected on subsequent
175 * sessions. This is contrary to the SSL3.0 spec, sesion 7.6.1.3, describing the
176 * Server Hello message.
178 * This anomaly does not occur if only RC4 ciphers are enabled in the Client Hello
179 * message. It also does not happen in SSL V2.
181 #define ALLOW_CIPHERSPEC_CHANGE 1
184 SSLInstallSessionFromData(const SSLBuffer sessionData
, SSLContext
*ctx
)
186 ResumableSession
*session
;
187 uint8
*storedCertProgress
;
188 SSLCertificate
*cert
, *lastCert
;
192 session
= (ResumableSession
*)sessionData
.data
;
194 assert(ctx
->negProtocolVersion
== session
->protocolVersion
);
197 * For SSLv3 and TLSv1, we know that selectedCipher has already been specified in
198 * SSLProcessServerHello(). An SSLv2 server hello message with a session
199 * ID hit contains no CipherKind field so we set it here.
201 if(ctx
->negProtocolVersion
== SSL_Version_2_0
) {
202 if(ctx
->protocolSide
== SSL_ClientSide
) {
203 assert(ctx
->selectedCipher
== 0);
204 ctx
->selectedCipher
= session
->cipherSuite
;
208 * Else...what if they don't match? Could never happen, right?
209 * Wouldn't that mean the client is trying to switch ciphers on us?
211 if(ctx
->selectedCipher
!= session
->cipherSuite
) {
212 sslErrorLog("+++SSL2: CipherSpec change from %d to %d on session "
214 session
->cipherSuite
, ctx
->selectedCipher
);
215 return errSSLProtocol
;
220 assert(ctx
->selectedCipher
!= 0);
221 if(ctx
->selectedCipher
!= session
->cipherSuite
) {
222 #if ALLOW_CIPHERSPEC_CHANGE
223 sslErrorLog("+++WARNING: CipherSpec change from %d to %d "
224 "on session resume\n",
225 session
->cipherSuite
, ctx
->selectedCipher
);
227 sslErrorLog("+++SSL: CipherSpec change from %d to %d on session resume\n",
228 session
->cipherSuite
, ctx
->selectedCipher
);
229 return errSSLProtocol
;
233 if ((err
= FindCipherSpec(ctx
)) != 0) {
236 memcpy(ctx
->masterSecret
, session
->masterSecret
, 48);
239 storedCertProgress
= session
->certs
;
240 certCount
= session
->certCount
;
244 cert
= (SSLCertificate
*)sslMalloc(sizeof(SSLCertificate
));
249 certLen
= SSLDecodeInt(storedCertProgress
, 4);
250 storedCertProgress
+= 4;
251 if ((err
= SSLAllocBuffer(cert
->derCert
, certLen
, ctx
)) != 0)
256 memcpy(cert
->derCert
.data
, storedCertProgress
, certLen
);
257 storedCertProgress
+= certLen
;
259 ctx
->peerCert
= cert
;
261 lastCert
->next
= cert
;