]> git.saurik.com Git - apple/security.git/blame - SecureTransport/sslSession.cpp
Security-176.tar.gz
[apple/security.git] / SecureTransport / sslSession.cpp
CommitLineData
bac41a7b
A
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
bac41a7b 19#include "ssl.h"
5a719ac8
A
20#include "sslContext.h"
21#include "sslSession.h"
22#include "sslMemory.h"
23#include "sslUtils.h"
bac41a7b 24#include "sslDebug.h"
bac41a7b 25#include "cipherSpecs.h"
bac41a7b 26#include "appleSession.h"
5a719ac8 27
29654253 28#include <assert.h>
bac41a7b
A
29#include <string.h>
30#include <stddef.h>
31
32typedef struct
33{ int sessionIDLen;
34 UInt8 sessionID[32];
35 SSLProtocolVersion protocolVersion;
36 UInt16 cipherSuite;
29654253 37 UInt16 padding; /* so remainder is word aligned */
bac41a7b
A
38 UInt8 masterSecret[48];
39 int certCount;
40 UInt8 certs[1]; /* Actually, variable length */
41} ResumableSession;
42
43/*
44 * Cook up a (private) resumable session blob, based on the
45 * specified ctx, store it with ctx->peerID as the key.
5a719ac8 46 * NOTE: This is contrary to the SSL v3 spec, which claims that
bac41a7b
A
47 * servers store resumable sessions using ctx->sessionID as the key.
48 * I don' think this is an issue...is it?
49 */
5a719ac8 50OSStatus
29654253 51SSLAddSessionData(const SSLContext *ctx)
5a719ac8 52{ OSStatus err;
bac41a7b
A
53 uint32 sessionIDLen;
54 SSLBuffer sessionID;
55 ResumableSession *session;
56 int certCount;
57 SSLCertificate *cert;
58 uint8 *certDest;
59
60 /* If we don't know who the peer is, we can't store a session */
61 if (ctx->peerID.data == 0)
5a719ac8 62 return errSSLSessionNotFound;
bac41a7b
A
63
64 sessionIDLen = offsetof(ResumableSession, certs);
65 cert = ctx->peerCert;
66 certCount = 0;
67 while (cert)
68 { ++certCount;
69 sessionIDLen += 4 + cert->derCert.length;
70 cert = cert->next;
71 }
72
5a719ac8 73 if ((err = SSLAllocBuffer(sessionID, sessionIDLen, ctx)) != 0)
bac41a7b
A
74 return err;
75
76 session = (ResumableSession*)sessionID.data;
77
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;
29654253
A
84 session->padding = 0;
85
bac41a7b
A
86 certDest = session->certs;
87 cert = ctx->peerCert;
88 while (cert)
89 { certDest = SSLEncodeInt(certDest, cert->derCert.length, 4);
90 memcpy(certDest, cert->derCert.data, cert->derCert.length);
91 certDest += cert->derCert.length;
92 cert = cert->next;
93 }
94
29654253 95 err = sslAddSession(ctx->peerID, sessionID);
5a719ac8 96 SSLFreeBuffer(sessionID, ctx);
bac41a7b
A
97
98 return err;
99}
100
101/*
102 * Retrieve resumable session data, from key ctx->peerID.
103 */
5a719ac8 104OSStatus
29654253 105SSLGetSessionData(SSLBuffer *sessionData, const SSLContext *ctx)
5a719ac8 106{ OSStatus err;
bac41a7b
A
107
108 if (ctx->peerID.data == 0)
5a719ac8 109 return errSSLSessionNotFound;
bac41a7b
A
110
111 sessionData->data = 0;
112
29654253 113 err = sslGetSession(ctx->peerID, sessionData);
bac41a7b 114 if (sessionData->data == 0)
5a719ac8 115 return errSSLSessionNotFound;
bac41a7b
A
116
117 return err;
118}
119
5a719ac8 120OSStatus
29654253 121SSLDeleteSessionData(const SSLContext *ctx)
5a719ac8 122{ OSStatus err;
bac41a7b
A
123
124 if (ctx->peerID.data == 0)
5a719ac8 125 return errSSLSessionNotFound;
bac41a7b 126
29654253 127 err = sslDeleteSession(ctx->peerID);
bac41a7b
A
128 return err;
129}
130
131/*
132 * Given a sessionData blob, obtain the associated sessionID (NOT the key...).
133 */
5a719ac8 134OSStatus
29654253 135SSLRetrieveSessionID(
bac41a7b
A
136 const SSLBuffer sessionData,
137 SSLBuffer *identifier,
138 const SSLContext *ctx)
5a719ac8 139{ OSStatus err;
bac41a7b
A
140 ResumableSession *session;
141
142 session = (ResumableSession*) sessionData.data;
5a719ac8 143 if ((err = SSLAllocBuffer(*identifier, session->sessionIDLen, ctx)) != 0)
bac41a7b
A
144 return err;
145 memcpy(identifier->data, session->sessionID, session->sessionIDLen);
5a719ac8 146 return noErr;
bac41a7b
A
147}
148
149/*
150 * Obtain the protocol version associated with a specified resumable session blob.
151 */
5a719ac8 152OSStatus
29654253
A
153SSLRetrieveSessionProtocolVersion(
154 const SSLBuffer sessionData,
bac41a7b
A
155 SSLProtocolVersion *version,
156 const SSLContext *ctx)
157{ ResumableSession *session;
158
29654253 159 session = (ResumableSession*) sessionData.data;
bac41a7b 160 *version = session->protocolVersion;
5a719ac8 161 return noErr;
bac41a7b
A
162}
163
164/*
29654253
A
165 * Retrieve session state from specified sessionData blob, install into
166 * ctx. Presumably, ctx->sessionID and
bac41a7b
A
167 * ctx->negProtocolVersion are already init'd (from the above two functions).
168 */
29654253
A
169
170/*
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.
177 *
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.
180 */
181#define ALLOW_CIPHERSPEC_CHANGE 1
182
5a719ac8 183OSStatus
29654253 184SSLInstallSessionFromData(const SSLBuffer sessionData, SSLContext *ctx)
5a719ac8 185{ OSStatus err;
bac41a7b
A
186 ResumableSession *session;
187 uint8 *storedCertProgress;
188 SSLCertificate *cert, *lastCert;
bac41a7b
A
189 int certCount;
190 uint32 certLen;
191
192 session = (ResumableSession*)sessionData.data;
29654253
A
193
194 /*
195 * For SSLv3 and TLSv1, we know that selectedCipher has already been specified in
196 * SSLProcessServerHello(). An SSLv2 server hello message with a session
197 * ID hit contains no CipherKind field so we set it here.
198 */
199 if(ctx->negProtocolVersion == SSL_Version_2_0) {
200 if(ctx->protocolSide == SSL_ClientSide) {
201 assert(ctx->selectedCipher == 0);
202 ctx->selectedCipher = session->cipherSuite;
203 }
204 else {
205 /*
206 * Else...what if they don't match? Could never happen, right?
207 * Wouldn't that mean the client is trying to switch ciphers on us?
208 */
209 if(ctx->selectedCipher != session->cipherSuite) {
5a719ac8 210 sslErrorLog("+++SSL2: CipherSpec change from %d to %d on session "
29654253
A
211 "resume\n",
212 session->cipherSuite, ctx->selectedCipher);
5a719ac8 213 return errSSLProtocol;
29654253
A
214 }
215 }
216 }
217 else {
218 assert(ctx->selectedCipher != 0);
219 if(ctx->selectedCipher != session->cipherSuite) {
220 #if ALLOW_CIPHERSPEC_CHANGE
5a719ac8
A
221 sslErrorLog("+++WARNING: CipherSpec change from %d to %d "
222 "on session resume\n",
29654253
A
223 session->cipherSuite, ctx->selectedCipher);
224 #else
5a719ac8 225 sslErrorLog("+++SSL: CipherSpec change from %d to %d on session resume\n",
29654253 226 session->cipherSuite, ctx->selectedCipher);
5a719ac8 227 return errSSLProtocol;
29654253
A
228 #endif
229 }
230 }
bac41a7b
A
231 if ((err = FindCipherSpec(ctx)) != 0) {
232 return err;
233 }
234 memcpy(ctx->masterSecret, session->masterSecret, 48);
235
236 lastCert = 0;
237 storedCertProgress = session->certs;
238 certCount = session->certCount;
239
240 while (certCount--)
241 {
bac41a7b
A
242 cert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
243 if(cert == NULL) {
5a719ac8 244 return memFullErr;
bac41a7b 245 }
bac41a7b
A
246 cert->next = 0;
247 certLen = SSLDecodeInt(storedCertProgress, 4);
248 storedCertProgress += 4;
5a719ac8 249 if ((err = SSLAllocBuffer(cert->derCert, certLen, ctx)) != 0)
bac41a7b 250 {
bac41a7b 251 sslFree(cert);
bac41a7b
A
252 return err;
253 }
254 memcpy(cert->derCert.data, storedCertProgress, certLen);
255 storedCertProgress += certLen;
bac41a7b
A
256 if (lastCert == 0)
257 ctx->peerCert = cert;
258 else
259 lastCert->next = cert;
260 lastCert = cert;
261 }
262
5a719ac8 263 return noErr;
bac41a7b 264}