]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslRecord.cpp
Security-179.tar.gz
[apple/security.git] / SecureTransport / sslRecord.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 /*
20 File: sslRecord.cpp
21
22 Contains: Encryption, decryption and MACing of data
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29
30 #include "ssl.h"
31
32 #include "sslRecord.h"
33 #include "sslMemory.h"
34 #include "cryptType.h"
35 #include "sslContext.h"
36 #include "sslAlertMessage.h"
37 #include "sslDebug.h"
38 #include "ssl2.h"
39 #include "sslUtils.h"
40 #include "sslDigests.h"
41
42 #include <string.h>
43 #include <assert.h>
44
45 /*
46 * Lots of servers fail to provide closure alerts when they disconnect.
47 * For now we'll just accept it as long as it occurs on a clean record boundary
48 * (and the handshake is complete).
49 */
50 #define SSL_ALLOW_UNNOTICED_DISCONNECT 1
51
52 /* ReadSSLRecord
53 * Attempt to read & decrypt an SSL record.
54 */
55 OSStatus
56 SSLReadRecord(SSLRecord &rec, SSLContext *ctx)
57 { OSStatus err;
58 UInt32 len, contentLen;
59 UInt8 *charPtr;
60 SSLBuffer readData, cipherFragment;
61
62 if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < 5)
63 { if (ctx->partialReadBuffer.data)
64 if ((err = SSLFreeBuffer(ctx->partialReadBuffer, ctx)) != 0)
65 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
66 return err;
67 }
68 if ((err = SSLAllocBuffer(ctx->partialReadBuffer,
69 DEFAULT_BUFFER_SIZE, ctx)) != 0)
70 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
71 return err;
72 }
73 }
74
75 if (ctx->negProtocolVersion == SSL_Version_Undetermined) {
76 if (ctx->amountRead < 1)
77 { readData.length = 1 - ctx->amountRead;
78 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
79 len = readData.length;
80 err = sslIoRead(readData, &len, ctx);
81 if(err != 0)
82 { if (err == errSSLWouldBlock) {
83 ctx->amountRead += len;
84 return err;
85 }
86 else {
87 /* abort */
88 SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
89 return errSSLClosedAbort;
90 }
91 }
92 ctx->amountRead += len;
93 }
94 }
95
96 /*
97 * In undetermined cases, if the first byte isn't in the range of SSL 3.0
98 * record types, this is an SSL 2.0 record
99 */
100 switch (ctx->negProtocolVersion)
101 { case SSL_Version_Undetermined:
102 if (ctx->partialReadBuffer.data[0] < SSL_RecordTypeV3_Smallest ||
103 ctx->partialReadBuffer.data[0] > SSL_RecordTypeV3_Largest)
104 return SSL2ReadRecord(rec, ctx);
105 else
106 break;
107 case SSL_Version_2_0:
108 return SSL2ReadRecord(rec, ctx);
109 default:
110 break;
111 }
112
113 if (ctx->amountRead < 5)
114 { readData.length = 5 - ctx->amountRead;
115 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
116 len = readData.length;
117 err = sslIoRead(readData, &len, ctx);
118 if(err != 0)
119 {
120 switch(err) {
121 case errSSLWouldBlock:
122 ctx->amountRead += len;
123 break;
124 #if SSL_ALLOW_UNNOTICED_DISCONNECT
125 case errSSLClosedGraceful:
126 /* legal if we're on record boundary and we've gotten past
127 * the handshake */
128 if((ctx->amountRead == 0) && /* nothing pending */
129 (len == 0) && /* nothing new */
130 (ctx->state == SSL_HdskStateClientReady)) { /* handshake done */
131 /*
132 * This means that the server has disconnected without
133 * sending a closure alert notice. This is technically
134 * illegal per the SSL3 spec, but about half of the
135 * servers out there do it, so we report it as a separate
136 * error which most clients - including (currently)
137 * URLAccess - ignore by treating it the same as
138 * a errSSLClosedGraceful error. Paranoid
139 * clients can detect it and handle it however they
140 * want to.
141 */
142 SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose);
143 err = errSSLClosedNoNotify;
144 break;
145 }
146 else {
147 /* illegal disconnect */
148 err = errSSLClosedAbort;
149 /* and drop thru to default: fatal alert */
150 }
151 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
152 default:
153 SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
154 break;
155 }
156 return err;
157 }
158 ctx->amountRead += len;
159 }
160
161 assert(ctx->amountRead >= 5);
162
163 charPtr = ctx->partialReadBuffer.data;
164 rec.contentType = *charPtr++;
165 if (rec.contentType < SSL_RecordTypeV3_Smallest ||
166 rec.contentType > SSL_RecordTypeV3_Largest)
167 return errSSLProtocol;
168
169 rec.protocolVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
170 charPtr += 2;
171 contentLen = SSLDecodeInt(charPtr, 2);
172 charPtr += 2;
173 if (contentLen > (16384 + 2048)) /* Maximum legal length of an
174 * SSLCipherText payload */
175 { SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx);
176 return errSSLProtocol;
177 }
178
179 if (ctx->partialReadBuffer.length < 5 + contentLen)
180 { if ((err = SSLReallocBuffer(ctx->partialReadBuffer, 5 + contentLen, ctx)) != 0)
181 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
182 return err;
183 }
184 }
185
186 if (ctx->amountRead < 5 + contentLen)
187 { readData.length = 5 + contentLen - ctx->amountRead;
188 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
189 len = readData.length;
190 err = sslIoRead(readData, &len, ctx);
191 if(err != 0)
192 { if (err == errSSLWouldBlock)
193 ctx->amountRead += len;
194 else
195 SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
196 return err;
197 }
198 ctx->amountRead += len;
199 }
200
201 assert(ctx->amountRead >= 5 + contentLen);
202
203 cipherFragment.data = ctx->partialReadBuffer.data + 5;
204 cipherFragment.length = contentLen;
205
206 /*
207 * Decrypt the payload & check the MAC, modifying the length of the
208 * buffer to indicate the amount of plaintext data after adjusting
209 * for the block size and removing the MAC (this function generates
210 * its own alerts).
211 */
212 assert(ctx->sslTslCalls != NULL);
213 if ((err = ctx->sslTslCalls->decryptRecord(rec.contentType,
214 &cipherFragment, ctx)) != 0)
215 return err;
216
217 /*
218 * We appear to have sucessfully received a record; increment the
219 * sequence number
220 */
221 IncrementUInt64(&ctx->readCipher.sequenceNum);
222
223 /* Allocate a buffer to return the plaintext in and return it */
224 if ((err = SSLAllocBuffer(rec.contents, cipherFragment.length, ctx)) != 0)
225 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
226 return err;
227 }
228 memcpy(rec.contents.data, cipherFragment.data, cipherFragment.length);
229
230 ctx->amountRead = 0; /* We've used all the data in the cache */
231
232 return noErr;
233 }
234
235 /* common for sslv3 and tlsv1, except for the computeMac callout */
236 OSStatus SSLVerifyMac(
237 UInt8 type,
238 SSLBuffer &data,
239 UInt8 *compareMAC,
240 SSLContext *ctx)
241 {
242 OSStatus err;
243 UInt8 macData[SSL_MAX_DIGEST_LEN];
244 SSLBuffer secret, mac;
245
246 secret.data = ctx->readCipher.macSecret;
247 secret.length = ctx->readCipher.macRef->hash->digestSize;
248 mac.data = macData;
249 mac.length = ctx->readCipher.macRef->hash->digestSize;
250
251 assert(ctx->sslTslCalls != NULL);
252 if ((err = ctx->sslTslCalls->computeMac(type,
253 data,
254 mac,
255 &ctx->readCipher,
256 ctx->readCipher.sequenceNum,
257 ctx)) != 0)
258 return err;
259
260 if ((memcmp(mac.data, compareMAC, mac.length)) != 0) {
261 sslErrorLog("ssl3VerifyMac: Mac verify failure\n");
262 return errSSLProtocol;
263 }
264 return noErr;
265 }
266
267