]>
Commit | Line | Data |
---|---|---|
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 | ||
19 | /* | |
5a719ac8 | 20 | File: sslRecord.cpp |
bac41a7b A |
21 | |
22 | Contains: Encryption, decryption and MACing of data | |
23 | ||
5a719ac8 | 24 | Written by: Doug Mitchell |
bac41a7b A |
25 | |
26 | Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved. | |
27 | ||
28 | */ | |
bac41a7b A |
29 | |
30 | #include "ssl.h" | |
31 | ||
5a719ac8 A |
32 | #include "sslRecord.h" |
33 | #include "sslMemory.h" | |
bac41a7b | 34 | #include "cryptType.h" |
5a719ac8 A |
35 | #include "sslContext.h" |
36 | #include "sslAlertMessage.h" | |
bac41a7b | 37 | #include "sslDebug.h" |
bac41a7b | 38 | #include "ssl2.h" |
5a719ac8 A |
39 | #include "sslUtils.h" |
40 | #include "sslDigests.h" | |
bac41a7b | 41 | |
bac41a7b | 42 | #include <string.h> |
29654253 | 43 | #include <assert.h> |
bac41a7b A |
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 | ||
bac41a7b A |
52 | /* ReadSSLRecord |
53 | * Attempt to read & decrypt an SSL record. | |
54 | */ | |
5a719ac8 A |
55 | OSStatus |
56 | SSLReadRecord(SSLRecord &rec, SSLContext *ctx) | |
57 | { OSStatus err; | |
bac41a7b | 58 | UInt32 len, contentLen; |
5a719ac8 | 59 | UInt8 *charPtr; |
bac41a7b A |
60 | SSLBuffer readData, cipherFragment; |
61 | ||
62 | if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < 5) | |
63 | { if (ctx->partialReadBuffer.data) | |
5a719ac8 | 64 | if ((err = SSLFreeBuffer(ctx->partialReadBuffer, ctx)) != 0) |
df0e469f | 65 | { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); |
5a719ac8 | 66 | return err; |
bac41a7b | 67 | } |
5a719ac8 A |
68 | if ((err = SSLAllocBuffer(ctx->partialReadBuffer, |
69 | DEFAULT_BUFFER_SIZE, ctx)) != 0) | |
df0e469f | 70 | { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); |
5a719ac8 | 71 | return err; |
bac41a7b A |
72 | } |
73 | } | |
74 | ||
df0e469f | 75 | if (ctx->negProtocolVersion == SSL_Version_Undetermined) { |
bac41a7b A |
76 | if (ctx->amountRead < 1) |
77 | { readData.length = 1 - ctx->amountRead; | |
78 | readData.data = ctx->partialReadBuffer.data + ctx->amountRead; | |
79 | len = readData.length; | |
bac41a7b A |
80 | err = sslIoRead(readData, &len, ctx); |
81 | if(err != 0) | |
df0e469f A |
82 | { if (err == errSSLWouldBlock) { |
83 | ctx->amountRead += len; | |
84 | return err; | |
85 | } | |
86 | else { | |
87 | /* abort */ | |
5a719ac8 | 88 | SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); |
df0e469f A |
89 | return errSSLClosedAbort; |
90 | } | |
bac41a7b A |
91 | } |
92 | ctx->amountRead += len; | |
93 | } | |
df0e469f A |
94 | } |
95 | ||
5a719ac8 A |
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 | */ | |
bac41a7b A |
100 | switch (ctx->negProtocolVersion) |
101 | { case SSL_Version_Undetermined: | |
5a719ac8 A |
102 | if (ctx->partialReadBuffer.data[0] < SSL_RecordTypeV3_Smallest || |
103 | ctx->partialReadBuffer.data[0] > SSL_RecordTypeV3_Largest) | |
bac41a7b A |
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; | |
bac41a7b A |
117 | err = sslIoRead(readData, &len, ctx); |
118 | if(err != 0) | |
bac41a7b A |
119 | { |
120 | switch(err) { | |
5a719ac8 | 121 | case errSSLWouldBlock: |
bac41a7b A |
122 | ctx->amountRead += len; |
123 | break; | |
124 | #if SSL_ALLOW_UNNOTICED_DISCONNECT | |
5a719ac8 | 125 | case errSSLClosedGraceful: |
bac41a7b A |
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 */ | |
df0e469f | 130 | (ctx->state == SSL_HdskStateClientReady)) { /* handshake done */ |
bac41a7b | 131 | /* |
29654253 | 132 | * This means that the server has disconnected without |
bac41a7b A |
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 | |
5a719ac8 | 138 | * a errSSLClosedGraceful error. Paranoid |
bac41a7b A |
139 | * clients can detect it and handle it however they |
140 | * want to. | |
141 | */ | |
5a719ac8 A |
142 | SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose); |
143 | err = errSSLClosedNoNotify; | |
bac41a7b A |
144 | break; |
145 | } | |
146 | else { | |
147 | /* illegal disconnect */ | |
5a719ac8 | 148 | err = errSSLClosedAbort; |
bac41a7b A |
149 | /* and drop thru to default: fatal alert */ |
150 | } | |
151 | #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */ | |
152 | default: | |
5a719ac8 | 153 | SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); |
bac41a7b A |
154 | break; |
155 | } | |
156 | return err; | |
157 | } | |
158 | ctx->amountRead += len; | |
159 | } | |
160 | ||
5a719ac8 | 161 | assert(ctx->amountRead >= 5); |
bac41a7b | 162 | |
5a719ac8 A |
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; | |
bac41a7b | 168 | |
5a719ac8 A |
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 */ | |
df0e469f | 175 | { SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx); |
5a719ac8 | 176 | return errSSLProtocol; |
bac41a7b A |
177 | } |
178 | ||
179 | if (ctx->partialReadBuffer.length < 5 + contentLen) | |
5a719ac8 | 180 | { if ((err = SSLReallocBuffer(ctx->partialReadBuffer, 5 + contentLen, ctx)) != 0) |
df0e469f | 181 | { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); |
5a719ac8 | 182 | return err; |
bac41a7b A |
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; | |
bac41a7b A |
190 | err = sslIoRead(readData, &len, ctx); |
191 | if(err != 0) | |
5a719ac8 | 192 | { if (err == errSSLWouldBlock) |
bac41a7b A |
193 | ctx->amountRead += len; |
194 | else | |
5a719ac8 | 195 | SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); |
bac41a7b A |
196 | return err; |
197 | } | |
198 | ctx->amountRead += len; | |
199 | } | |
200 | ||
5a719ac8 | 201 | assert(ctx->amountRead >= 5 + contentLen); |
bac41a7b A |
202 | |
203 | cipherFragment.data = ctx->partialReadBuffer.data + 5; | |
204 | cipherFragment.length = contentLen; | |
205 | ||
5a719ac8 A |
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 | */ | |
29654253 | 212 | assert(ctx->sslTslCalls != NULL); |
5a719ac8 | 213 | if ((err = ctx->sslTslCalls->decryptRecord(rec.contentType, |
29654253 | 214 | &cipherFragment, ctx)) != 0) |
bac41a7b A |
215 | return err; |
216 | ||
5a719ac8 A |
217 | /* |
218 | * We appear to have sucessfully received a record; increment the | |
219 | * sequence number | |
220 | */ | |
bac41a7b A |
221 | IncrementUInt64(&ctx->readCipher.sequenceNum); |
222 | ||
5a719ac8 A |
223 | /* Allocate a buffer to return the plaintext in and return it */ |
224 | if ((err = SSLAllocBuffer(rec.contents, cipherFragment.length, ctx)) != 0) | |
df0e469f | 225 | { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); |
5a719ac8 | 226 | return err; |
bac41a7b | 227 | } |
5a719ac8 | 228 | memcpy(rec.contents.data, cipherFragment.data, cipherFragment.length); |
bac41a7b A |
229 | |
230 | ctx->amountRead = 0; /* We've used all the data in the cache */ | |
231 | ||
5a719ac8 | 232 | return noErr; |
bac41a7b A |
233 | } |
234 | ||
29654253 | 235 | /* common for sslv3 and tlsv1, except for the computeMac callout */ |
5a719ac8 | 236 | OSStatus SSLVerifyMac( |
29654253 | 237 | UInt8 type, |
5a719ac8 | 238 | SSLBuffer &data, |
29654253 A |
239 | UInt8 *compareMAC, |
240 | SSLContext *ctx) | |
241 | { | |
5a719ac8 A |
242 | OSStatus err; |
243 | UInt8 macData[SSL_MAX_DIGEST_LEN]; | |
bac41a7b A |
244 | SSLBuffer secret, mac; |
245 | ||
246 | secret.data = ctx->readCipher.macSecret; | |
29654253 | 247 | secret.length = ctx->readCipher.macRef->hash->digestSize; |
bac41a7b | 248 | mac.data = macData; |
29654253 A |
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) | |
5a719ac8 | 258 | return err; |
bac41a7b A |
259 | |
260 | if ((memcmp(mac.data, compareMAC, mac.length)) != 0) { | |
5a719ac8 A |
261 | sslErrorLog("ssl3VerifyMac: Mac verify failure\n"); |
262 | return errSSLProtocol; | |
bac41a7b | 263 | } |
5a719ac8 | 264 | return noErr; |
bac41a7b A |
265 | } |
266 | ||
29654253 | 267 |