]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslsess.c
a4f5b7aff28235ae850c2e67ef559d1e4013bb53
[apple/security.git] / SecureTransport / sslsess.c
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: sslsess.c
21
22 SSLRef 3.0 Final -- 11/19/96
23
24 Copyright (c)1996 by Netscape Communications Corp.
25
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.
29
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/>.
33
34 *********************************************************************
35
36 File: sslsess.c SSL Session DB interface
37
38 This file contains functions which interact with the session database
39 to store and restore sessions and retrieve information from packed
40 session records.
41
42 ****************************************************************** */
43
44 #ifndef _SSL_H_
45 #include "ssl.h"
46 #endif
47
48 #ifndef _SSLCTX_H_
49 #include "sslctx.h"
50 #endif
51
52 #ifndef _SSLSESS_H_
53 #include "sslsess.h"
54 #endif
55
56 #ifndef _SSLALLOC_H_
57 #include "sslalloc.h"
58 #endif
59
60 #ifndef _SSLUTIL_H_
61 #include "sslutil.h"
62 #endif
63
64 #ifndef _SSL_DEBUG_H_
65 #include "sslDebug.h"
66 #endif
67
68 #ifndef _CIPHER_SPECS_H_
69 #include "cipherSpecs.h"
70 #endif
71
72 #include "appleSession.h"
73 #include <assert.h>
74 #include <string.h>
75 #include <stddef.h>
76
77 typedef struct
78 { int sessionIDLen;
79 UInt8 sessionID[32];
80 SSLProtocolVersion protocolVersion;
81 UInt16 cipherSuite;
82 UInt16 padding; /* so remainder is word aligned */
83 UInt8 masterSecret[48];
84 int certCount;
85 UInt8 certs[1]; /* Actually, variable length */
86 } ResumableSession;
87
88 /*
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?
94 */
95 SSLErr
96 SSLAddSessionData(const SSLContext *ctx)
97 { SSLErr err;
98 uint32 sessionIDLen;
99 SSLBuffer sessionID;
100 ResumableSession *session;
101 int certCount;
102 SSLCertificate *cert;
103 uint8 *certDest;
104
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;
108
109 sessionIDLen = offsetof(ResumableSession, certs);
110 cert = ctx->peerCert;
111 certCount = 0;
112 while (cert)
113 { ++certCount;
114 sessionIDLen += 4 + cert->derCert.length;
115 cert = cert->next;
116 }
117
118 if ((err = SSLAllocBuffer(&sessionID, sessionIDLen, &ctx->sysCtx)) != 0)
119 return err;
120
121 session = (ResumableSession*)sessionID.data;
122
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;
130
131 certDest = session->certs;
132 cert = ctx->peerCert;
133 while (cert)
134 { certDest = SSLEncodeInt(certDest, cert->derCert.length, 4);
135 memcpy(certDest, cert->derCert.data, cert->derCert.length);
136 certDest += cert->derCert.length;
137 cert = cert->next;
138 }
139
140 err = sslAddSession(ctx->peerID, sessionID);
141 SSLFreeBuffer(&sessionID, &ctx->sysCtx);
142
143 return err;
144 }
145
146 /*
147 * Retrieve resumable session data, from key ctx->peerID.
148 */
149 SSLErr
150 SSLGetSessionData(SSLBuffer *sessionData, const SSLContext *ctx)
151 { SSLErr err;
152
153 if (ctx->peerID.data == 0)
154 return ERR(SSLSessionNotFoundErr);
155
156 sessionData->data = 0;
157
158 err = sslGetSession(ctx->peerID, sessionData);
159 if (sessionData->data == 0)
160 return ERR(SSLSessionNotFoundErr);
161
162 return err;
163 }
164
165 SSLErr
166 SSLDeleteSessionData(const SSLContext *ctx)
167 { SSLErr err;
168
169 if (ctx->peerID.data == 0)
170 return SSLSessionNotFoundErr;
171
172 err = sslDeleteSession(ctx->peerID);
173 return err;
174 }
175
176 /*
177 * Given a sessionData blob, obtain the associated sessionID (NOT the key...).
178 */
179 SSLErr
180 SSLRetrieveSessionID(
181 const SSLBuffer sessionData,
182 SSLBuffer *identifier,
183 const SSLContext *ctx)
184 { SSLErr err;
185 ResumableSession *session;
186
187 session = (ResumableSession*) sessionData.data;
188 if ((err = SSLAllocBuffer(identifier, session->sessionIDLen, &ctx->sysCtx)) != 0)
189 return err;
190 memcpy(identifier->data, session->sessionID, session->sessionIDLen);
191 return SSLNoErr;
192 }
193
194 /*
195 * Obtain the protocol version associated with a specified resumable session blob.
196 */
197 SSLErr
198 SSLRetrieveSessionProtocolVersion(
199 const SSLBuffer sessionData,
200 SSLProtocolVersion *version,
201 const SSLContext *ctx)
202 { ResumableSession *session;
203
204 session = (ResumableSession*) sessionData.data;
205 *version = session->protocolVersion;
206 return SSLNoErr;
207 }
208
209 /*
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).
213 */
214
215 /*
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.
222 *
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.
225 */
226 #define ALLOW_CIPHERSPEC_CHANGE 1
227
228 SSLErr
229 SSLInstallSessionFromData(const SSLBuffer sessionData, SSLContext *ctx)
230 { SSLErr err;
231 ResumableSession *session;
232 uint8 *storedCertProgress;
233 SSLCertificate *cert, *lastCert;
234 int certCount;
235 uint32 certLen;
236
237 session = (ResumableSession*)sessionData.data;
238
239 CASSERT(ctx->negProtocolVersion == session->protocolVersion);
240
241 /*
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.
245 */
246 if(ctx->negProtocolVersion == SSL_Version_2_0) {
247 if(ctx->protocolSide == SSL_ClientSide) {
248 assert(ctx->selectedCipher == 0);
249 ctx->selectedCipher = session->cipherSuite;
250 }
251 else {
252 /*
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?
255 */
256 if(ctx->selectedCipher != session->cipherSuite) {
257 errorLog2("+++SSL2: CipherSpec change from %d to %d on session "
258 "resume\n",
259 session->cipherSuite, ctx->selectedCipher);
260 return SSLProtocolErr;
261 }
262 }
263 }
264 else {
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);
270 #else
271 errorLog2("+++SSL: CipherSpec change from %d to %d on session resume\n",
272 session->cipherSuite, ctx->selectedCipher);
273 return SSLProtocolErr;
274 #endif
275 }
276 }
277 if ((err = FindCipherSpec(ctx)) != 0) {
278 return err;
279 }
280 memcpy(ctx->masterSecret, session->masterSecret, 48);
281
282 lastCert = 0;
283 storedCertProgress = session->certs;
284 certCount = session->certCount;
285
286 while (certCount--)
287 {
288 cert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
289 if(cert == NULL) {
290 return SSLMemoryErr;
291 }
292 cert->next = 0;
293 certLen = SSLDecodeInt(storedCertProgress, 4);
294 storedCertProgress += 4;
295 if ((err = SSLAllocBuffer(&cert->derCert, certLen, &ctx->sysCtx)) != 0)
296 {
297 sslFree(cert);
298 return err;
299 }
300 memcpy(cert->derCert.data, storedCertProgress, certLen);
301 storedCertProgress += certLen;
302 if (lastCert == 0)
303 ctx->peerCert = cert;
304 else
305 lastCert->next = cert;
306 lastCert = cert;
307 }
308
309 return SSLNoErr;
310 }