]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslSession.cpp
Security-54.1.3.tar.gz
[apple/security.git] / SecureTransport / sslSession.cpp
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 #include "ssl.h"
20 #include "sslContext.h"
21 #include "sslSession.h"
22 #include "sslMemory.h"
23 #include "sslUtils.h"
24 #include "sslDebug.h"
25 #include "cipherSpecs.h"
26 #include "appleSession.h"
27
28 #include <assert.h>
29 #include <string.h>
30 #include <stddef.h>
31
32 typedef struct
33 { int sessionIDLen;
34 UInt8 sessionID[32];
35 SSLProtocolVersion protocolVersion;
36 UInt16 cipherSuite;
37 UInt16 padding; /* so remainder is word aligned */
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.
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?
49 */
50 OSStatus
51 SSLAddSessionData(const SSLContext *ctx)
52 { OSStatus err;
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)
62 return errSSLSessionNotFound;
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
73 if ((err = SSLAllocBuffer(sessionID, sessionIDLen, ctx)) != 0)
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;
84 session->padding = 0;
85
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
95 err = sslAddSession(ctx->peerID, sessionID);
96 SSLFreeBuffer(sessionID, ctx);
97
98 return err;
99 }
100
101 /*
102 * Retrieve resumable session data, from key ctx->peerID.
103 */
104 OSStatus
105 SSLGetSessionData(SSLBuffer *sessionData, const SSLContext *ctx)
106 { OSStatus err;
107
108 if (ctx->peerID.data == 0)
109 return errSSLSessionNotFound;
110
111 sessionData->data = 0;
112
113 err = sslGetSession(ctx->peerID, sessionData);
114 if (sessionData->data == 0)
115 return errSSLSessionNotFound;
116
117 return err;
118 }
119
120 OSStatus
121 SSLDeleteSessionData(const SSLContext *ctx)
122 { OSStatus err;
123
124 if (ctx->peerID.data == 0)
125 return errSSLSessionNotFound;
126
127 err = sslDeleteSession(ctx->peerID);
128 return err;
129 }
130
131 /*
132 * Given a sessionData blob, obtain the associated sessionID (NOT the key...).
133 */
134 OSStatus
135 SSLRetrieveSessionID(
136 const SSLBuffer sessionData,
137 SSLBuffer *identifier,
138 const SSLContext *ctx)
139 { OSStatus err;
140 ResumableSession *session;
141
142 session = (ResumableSession*) sessionData.data;
143 if ((err = SSLAllocBuffer(*identifier, session->sessionIDLen, ctx)) != 0)
144 return err;
145 memcpy(identifier->data, session->sessionID, session->sessionIDLen);
146 return noErr;
147 }
148
149 /*
150 * Obtain the protocol version associated with a specified resumable session blob.
151 */
152 OSStatus
153 SSLRetrieveSessionProtocolVersion(
154 const SSLBuffer sessionData,
155 SSLProtocolVersion *version,
156 const SSLContext *ctx)
157 { ResumableSession *session;
158
159 session = (ResumableSession*) sessionData.data;
160 *version = session->protocolVersion;
161 return noErr;
162 }
163
164 /*
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).
168 */
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
183 OSStatus
184 SSLInstallSessionFromData(const SSLBuffer sessionData, SSLContext *ctx)
185 { OSStatus err;
186 ResumableSession *session;
187 uint8 *storedCertProgress;
188 SSLCertificate *cert, *lastCert;
189 int certCount;
190 uint32 certLen;
191
192 session = (ResumableSession*)sessionData.data;
193
194 assert(ctx->negProtocolVersion == session->protocolVersion);
195
196 /*
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.
200 */
201 if(ctx->negProtocolVersion == SSL_Version_2_0) {
202 if(ctx->protocolSide == SSL_ClientSide) {
203 assert(ctx->selectedCipher == 0);
204 ctx->selectedCipher = session->cipherSuite;
205 }
206 else {
207 /*
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?
210 */
211 if(ctx->selectedCipher != session->cipherSuite) {
212 sslErrorLog("+++SSL2: CipherSpec change from %d to %d on session "
213 "resume\n",
214 session->cipherSuite, ctx->selectedCipher);
215 return errSSLProtocol;
216 }
217 }
218 }
219 else {
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);
226 #else
227 sslErrorLog("+++SSL: CipherSpec change from %d to %d on session resume\n",
228 session->cipherSuite, ctx->selectedCipher);
229 return errSSLProtocol;
230 #endif
231 }
232 }
233 if ((err = FindCipherSpec(ctx)) != 0) {
234 return err;
235 }
236 memcpy(ctx->masterSecret, session->masterSecret, 48);
237
238 lastCert = 0;
239 storedCertProgress = session->certs;
240 certCount = session->certCount;
241
242 while (certCount--)
243 {
244 cert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
245 if(cert == NULL) {
246 return memFullErr;
247 }
248 cert->next = 0;
249 certLen = SSLDecodeInt(storedCertProgress, 4);
250 storedCertProgress += 4;
251 if ((err = SSLAllocBuffer(cert->derCert, certLen, ctx)) != 0)
252 {
253 sslFree(cert);
254 return err;
255 }
256 memcpy(cert->derCert.data, storedCertProgress, certLen);
257 storedCertProgress += certLen;
258 if (lastCert == 0)
259 ctx->peerCert = cert;
260 else
261 lastCert->next = cert;
262 lastCert = cert;
263 }
264
265 return noErr;
266 }