2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Contains: Encryption, decryption and MACing of data
24 Written by: Doug Mitchell, based on Netscape SSLRef 3.0
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
29 /* *********************************************************************
32 SSLRef 3.0 Final -- 11/19/96
34 Copyright (c)1996 by Netscape Communications Corp.
36 By retrieving this software you are bound by the licensing terms
37 disclosed in the file "LICENSE.txt". Please read it, and if you don't
38 accept the terms, delete this software.
40 SSLRef 3.0 was developed by Netscape Communications Corp. of Mountain
41 View, California <http://home.netscape.com/> and Consensus Development
42 Corporation of Berkeley, California <http://www.consensus.com/>.
44 *********************************************************************
46 File: sslrec.c Encryption, decryption and MACing of data
48 All the transformations which occur between plaintext and the
49 secured, authenticated data that goes out over the wire. Also,
50 detects incoming SSL 2 hello messages and hands them off to the SSL 2
51 record layer (and hands all SSL 2 reading & writing off to the SSL 2
54 ****************************************************************** */
68 #include "cryptType.h"
91 #include "appleGlue.h"
96 * Lots of servers fail to provide closure alerts when they disconnect.
97 * For now we'll just accept it as long as it occurs on a clean record boundary
98 * (and the handshake is complete).
100 #define SSL_ALLOW_UNNOTICED_DISCONNECT 1
103 * Attempt to read & decrypt an SSL record.
106 SSLReadRecord(SSLRecord
*rec
, SSLContext
*ctx
)
108 UInt32 len
, contentLen
;
110 SSLBuffer readData
, cipherFragment
;
112 if (!ctx
->partialReadBuffer
.data
|| ctx
->partialReadBuffer
.length
< 5)
113 { if (ctx
->partialReadBuffer
.data
)
114 if ((err
= SSLFreeBuffer(&ctx
->partialReadBuffer
, &ctx
->sysCtx
)) != 0)
115 { SSLFatalSessionAlert(alert_close_notify
, ctx
);
118 if ((err
= SSLAllocBuffer(&ctx
->partialReadBuffer
, DEFAULT_BUFFER_SIZE
, &ctx
->sysCtx
)) != 0)
119 { SSLFatalSessionAlert(alert_close_notify
, ctx
);
124 if (ctx
->negProtocolVersion
== SSL_Version_Undetermined
||
125 ctx
->negProtocolVersion
== SSL_Version_3_0_With_2_0_Hello
)
126 if (ctx
->amountRead
< 1)
127 { readData
.length
= 1 - ctx
->amountRead
;
128 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
129 len
= readData
.length
;
130 err
= sslIoRead(readData
, &len
, ctx
);
132 { if (err
== SSLWouldBlockErr
)
133 ctx
->amountRead
+= len
;
135 SSLFatalSessionAlert(alert_close_notify
, ctx
);
138 ctx
->amountRead
+= len
;
141 /* In undetermined cases, if the first byte isn't in the range of SSL 3.0
142 * record types, this is an SSL 2.0 record
144 switch (ctx
->negProtocolVersion
)
145 { case SSL_Version_Undetermined
:
146 case SSL_Version_3_0_With_2_0_Hello
:
147 if (ctx
->partialReadBuffer
.data
[0] < SSL_smallest_3_0_type
||
148 ctx
->partialReadBuffer
.data
[0] > SSL_largest_3_0_type
)
149 return SSL2ReadRecord(rec
, ctx
);
152 case SSL_Version_2_0
:
153 return SSL2ReadRecord(rec
, ctx
);
158 if (ctx
->amountRead
< 5)
159 { readData
.length
= 5 - ctx
->amountRead
;
160 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
161 len
= readData
.length
;
162 err
= sslIoRead(readData
, &len
, ctx
);
166 case SSLWouldBlockErr
:
167 ctx
->amountRead
+= len
;
169 #if SSL_ALLOW_UNNOTICED_DISCONNECT
170 case SSLConnectionClosedGraceful
:
171 /* legal if we're on record boundary and we've gotten past
173 if((ctx
->amountRead
== 0) && /* nothing pending */
174 (len
== 0) && /* nothing new */
175 (ctx
->state
== HandshakeClientReady
)) { /* handshake done */
177 * This means that the server has disconnected without
178 * sending a closure alert notice. This is technically
179 * illegal per the SSL3 spec, but about half of the
180 * servers out there do it, so we report it as a separate
181 * error which most clients - including (currently)
182 * URLAccess - ignore by treating it the same as
183 * a SSLConnectionClosedGraceful error. Paranoid
184 * clients can detect it and handle it however they
187 SSLChangeHdskState(ctx
, SSLNoNotifyClose
);
188 err
= SSLConnectionClosedNoNotify
;
192 /* illegal disconnect */
193 err
= SSLConnectionClosedError
;
194 /* and drop thru to default: fatal alert */
196 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
198 SSLFatalSessionAlert(alert_close_notify
, ctx
);
203 ctx
->amountRead
+= len
;
206 CASSERT(ctx
->amountRead
>= 5);
208 progress
= ctx
->partialReadBuffer
.data
;
209 rec
->contentType
= *progress
++;
210 if (rec
->contentType
< SSL_smallest_3_0_type
||
211 rec
->contentType
> SSL_largest_3_0_type
)
212 return ERR(SSLProtocolErr
);
214 rec
->protocolVersion
= (SSLProtocolVersion
)SSLDecodeInt(progress
, 2);
216 contentLen
= SSLDecodeInt(progress
, 2);
218 if (contentLen
> (16384 + 2048)) /* Maximum legal length of an SSLCipherText payload */
219 { SSLFatalSessionAlert(alert_unexpected_message
, ctx
);
220 return ERR(SSLProtocolErr
);
223 if (ctx
->partialReadBuffer
.length
< 5 + contentLen
)
224 { if ((err
= SSLReallocBuffer(&ctx
->partialReadBuffer
, 5 + contentLen
, &ctx
->sysCtx
)) != 0)
225 { SSLFatalSessionAlert(alert_close_notify
, ctx
);
230 if (ctx
->amountRead
< 5 + contentLen
)
231 { readData
.length
= 5 + contentLen
- ctx
->amountRead
;
232 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
233 len
= readData
.length
;
234 err
= sslIoRead(readData
, &len
, ctx
);
236 { if (err
== SSLWouldBlockErr
)
237 ctx
->amountRead
+= len
;
239 SSLFatalSessionAlert(alert_close_notify
, ctx
);
242 ctx
->amountRead
+= len
;
245 CASSERT(ctx
->amountRead
>= 5 + contentLen
);
247 cipherFragment
.data
= ctx
->partialReadBuffer
.data
+ 5;
248 cipherFragment
.length
= contentLen
;
250 /* Decrypt the payload & check the MAC, modifying the length of the buffer to indicate the
251 * amount of plaintext data after adjusting for the block size and removing the MAC
252 * (this function generates its own alerts)
254 assert(ctx
->sslTslCalls
!= NULL
);
255 if ((err
= ctx
->sslTslCalls
->decryptRecord(rec
->contentType
,
256 &cipherFragment
, ctx
)) != 0)
259 /* We appear to have sucessfully received a record; increment the sequence number */
260 IncrementUInt64(&ctx
->readCipher
.sequenceNum
);
262 /* Allocate a buffer to return the plaintext in and return it */
263 if ((err
= SSLAllocBuffer(&rec
->contents
, cipherFragment
.length
, &ctx
->sysCtx
)) != 0)
264 { SSLFatalSessionAlert(alert_close_notify
, ctx
);
267 memcpy(rec
->contents
.data
, cipherFragment
.data
, cipherFragment
.length
);
269 ctx
->amountRead
= 0; /* We've used all the data in the cache */
274 /* common for sslv3 and tlsv1, except for the computeMac callout */
282 UInt8 macData
[MAX_DIGEST_SIZE
];
283 SSLBuffer secret
, mac
;
285 secret
.data
= ctx
->readCipher
.macSecret
;
286 secret
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
288 mac
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
290 assert(ctx
->sslTslCalls
!= NULL
);
291 if ((err
= ctx
->sslTslCalls
->computeMac(type
,
295 ctx
->readCipher
.sequenceNum
,
299 if ((memcmp(mac
.data
, compareMAC
, mac
.length
)) != 0) {
300 errorLog0("ssl3VerifyMac: Mac verify failure\n");
301 return ERR(SSLProtocolErr
);