]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/sslRecord.c
Security-55179.1.tar.gz
[apple/security.git] / libsecurity_ssl / lib / sslRecord.c
1 /*
2 * Copyright (c) 1999-2001,2005-2007,2010-2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * sslRecord.c - Encryption, decryption and MACing of data
26 */
27
28 #include "ssl.h"
29
30 #include "sslRecord.h"
31 #include "sslMemory.h"
32 #include "cryptType.h"
33 #include "sslContext.h"
34 #include "sslAlertMessage.h"
35 #include "sslDebug.h"
36 #include "sslUtils.h"
37 #include "sslDigests.h"
38
39 #include <string.h>
40 #include <assert.h>
41
42 /*
43 * Lots of servers fail to provide closure alerts when they disconnect.
44 * For now we'll just accept it as long as it occurs on a clean record boundary
45 * (and the handshake is complete).
46 */
47 #define SSL_ALLOW_UNNOTICED_DISCONNECT 1
48
49 /* ReadSSLRecord
50 * Attempt to read & decrypt an SSL record.
51 */
52 OSStatus
53 SSLReadRecord(SSLRecord *rec, SSLContext *ctx)
54 { OSStatus err;
55 size_t len, contentLen;
56 UInt8 *charPtr;
57 SSLBuffer readData, cipherFragment;
58 size_t head=5;
59 int skipit=0;
60
61 #if ENABLE_DTLS
62 if(ctx->isDTLS)
63 head+=8;
64 #endif
65
66 if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < head)
67 { if (ctx->partialReadBuffer.data)
68 if ((err = SSLFreeBuffer(&ctx->partialReadBuffer, ctx)) != 0)
69 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
70 return err;
71 }
72 if ((err = SSLAllocBuffer(&ctx->partialReadBuffer,
73 DEFAULT_BUFFER_SIZE, ctx)) != 0)
74 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
75 return err;
76 }
77 }
78
79 if (ctx->negProtocolVersion == SSL_Version_Undetermined) {
80 if (ctx->amountRead < 1)
81 { readData.length = 1 - ctx->amountRead;
82 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
83 len = readData.length;
84 err = sslIoRead(readData, &len, ctx);
85 if(err != 0)
86 { if (err == errSSLWouldBlock) {
87 ctx->amountRead += len;
88 return err;
89 }
90 else {
91 /* abort */
92 err = errSSLClosedAbort;
93 if((ctx->protocolSide == kSSLClientSide) &&
94 (ctx->amountRead == 0) &&
95 (len == 0)) {
96 /*
97 * Detect "server refused to even try to negotiate"
98 * error, when the server drops the connection before
99 * sending a single byte.
100 */
101 switch(ctx->state) {
102 case SSL_HdskStateServerHello:
103 case SSL_HdskStateServerHelloUnknownVersion:
104 sslHdskStateDebug("Server dropped initial connection\n");
105 err = errSSLConnectionRefused;
106 break;
107 default:
108 break;
109 }
110 }
111 SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
112 return err;
113 }
114 }
115 ctx->amountRead += len;
116 }
117 }
118
119 if (ctx->amountRead < head)
120 { readData.length = head - ctx->amountRead;
121 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
122 len = readData.length;
123 err = sslIoRead(readData, &len, ctx);
124 if(err != 0)
125 {
126 switch(err) {
127 case errSSLWouldBlock:
128 ctx->amountRead += len;
129 break;
130 #if SSL_ALLOW_UNNOTICED_DISCONNECT
131 case errSSLClosedGraceful:
132 /* legal if we're on record boundary and we've gotten past
133 * the handshake */
134 if((ctx->amountRead == 0) && /* nothing pending */
135 (len == 0) && /* nothing new */
136 (ctx->state == SSL_HdskStateClientReady)) { /* handshake done */
137 /*
138 * This means that the server has disconnected without
139 * sending a closure alert notice. This is technically
140 * illegal per the SSL3 spec, but about half of the
141 * servers out there do it, so we report it as a separate
142 * error which most clients - including (currently)
143 * URLAccess - ignore by treating it the same as
144 * a errSSLClosedGraceful error. Paranoid
145 * clients can detect it and handle it however they
146 * want to.
147 */
148 SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose);
149 err = errSSLClosedNoNotify;
150 break;
151 }
152 else {
153 /* illegal disconnect */
154 err = errSSLClosedAbort;
155 /* and drop thru to default: fatal alert */
156 }
157 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
158 default:
159 SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
160 break;
161 }
162 return err;
163 }
164 ctx->amountRead += len;
165 }
166
167 assert(ctx->amountRead >= head);
168
169 charPtr = ctx->partialReadBuffer.data;
170 rec->contentType = *charPtr++;
171 if (rec->contentType < SSL_RecordTypeV3_Smallest ||
172 rec->contentType > SSL_RecordTypeV3_Largest)
173 return errSSLProtocol;
174
175 rec->protocolVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
176 charPtr += 2;
177
178 #if ENABLE_DTLS
179 if(rec->protocolVersion == DTLS_Version_1_0)
180 {
181 sslUint64 seqNum;
182 SSLDecodeUInt64(charPtr, 8, &seqNum);
183 charPtr += 8;
184 sslLogRecordIo("Read DTLS Record %08x_%08x (seq is: %08x_%08x)",
185 seqNum.high, seqNum.low,
186 ctx->readCipher.sequenceNum.high,ctx->readCipher.sequenceNum.low);
187
188 /* if the epoch of the record is different of current read cipher, just drop it */
189 if((seqNum.high>>8)!=(ctx->readCipher.sequenceNum.high>>8)) {
190 skipit=1;
191 } else {
192 ctx->readCipher.sequenceNum.high=seqNum.high;
193 ctx->readCipher.sequenceNum.low=seqNum.low;
194 }
195 }
196 #endif
197
198 contentLen = SSLDecodeInt(charPtr, 2);
199 charPtr += 2;
200 if (contentLen > (16384 + 2048)) /* Maximum legal length of an
201 * SSLCipherText payload */
202 { SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx);
203 return errSSLProtocol;
204 }
205
206 /* Dont check this if we are going to drop an old packet:
207 we dont know if the digestSize is the correct one */
208 if (!skipit && contentLen < ctx->readCipher.macRef->hash->digestSize)
209 {
210 SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
211 return errSSLClosedAbort;
212 }
213
214 if (ctx->partialReadBuffer.length < head + contentLen)
215 { if ((err = SSLReallocBuffer(&ctx->partialReadBuffer, head + contentLen, ctx)) != 0)
216 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
217 return err;
218 }
219 }
220
221 if (ctx->amountRead < head + contentLen)
222 { readData.length = head + contentLen - ctx->amountRead;
223 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
224 len = readData.length;
225 err = sslIoRead(readData, &len, ctx);
226 if(err != 0)
227 { if (err == errSSLWouldBlock)
228 ctx->amountRead += len;
229 else
230 SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
231 return err;
232 }
233 ctx->amountRead += len;
234 }
235
236 assert(ctx->amountRead >= head + contentLen);
237
238 cipherFragment.data = ctx->partialReadBuffer.data + head;
239 cipherFragment.length = contentLen;
240
241 ctx->amountRead = 0; /* We've used all the data in the cache */
242
243 /* We dont decrypt if we were told to skip this record */
244 if(skipit) {
245 DTLSRetransmit(ctx);
246 return errSSLWouldBlock;
247 }
248 /*
249 * Decrypt the payload & check the MAC, modifying the length of the
250 * buffer to indicate the amount of plaintext data after adjusting
251 * for the block size and removing the MAC (this function generates
252 * its own alerts).
253 */
254 assert(ctx->sslTslCalls != NULL);
255 if ((err = ctx->sslTslCalls->decryptRecord(rec->contentType,
256 &cipherFragment, ctx)) != 0)
257 return err;
258
259 /*
260 * We appear to have sucessfully received a record; increment the
261 * sequence number
262 */
263 IncrementUInt64(&ctx->readCipher.sequenceNum);
264
265 /* Allocate a buffer to return the plaintext in and return it */
266 if ((err = SSLAllocBuffer(&rec->contents, cipherFragment.length, ctx)) != 0)
267 { SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
268 return err;
269 }
270 memcpy(rec->contents.data, cipherFragment.data, cipherFragment.length);
271
272
273 return noErr;
274 }
275
276 /* common for sslv3 and tlsv1, except for the computeMac callout */
277 OSStatus SSLVerifyMac(
278 UInt8 type,
279 SSLBuffer *data,
280 UInt8 *compareMAC,
281 SSLContext *ctx)
282 {
283 OSStatus err;
284 UInt8 macData[SSL_MAX_DIGEST_LEN];
285 SSLBuffer secret, mac;
286
287 secret.data = ctx->readCipher.macSecret;
288 secret.length = ctx->readCipher.macRef->hash->digestSize;
289 mac.data = macData;
290 mac.length = ctx->readCipher.macRef->hash->digestSize;
291
292 assert(ctx->sslTslCalls != NULL);
293 if ((err = ctx->sslTslCalls->computeMac(type,
294 *data,
295 mac,
296 &ctx->readCipher,
297 ctx->readCipher.sequenceNum,
298 ctx)) != 0)
299 return err;
300
301 if ((memcmp(mac.data, compareMAC, mac.length)) != 0) {
302 sslErrorLog("ssl3VerifyMac: Mac verify failure\n");
303 return errSSLProtocol;
304 }
305 return noErr;
306 }
307
308