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