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
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
32 #include "sslRecord.h"
33 #include "sslMemory.h"
34 #include "cryptType.h"
35 #include "sslContext.h"
36 #include "sslAlertMessage.h"
40 #include "sslDigests.h"
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).
50 #define SSL_ALLOW_UNNOTICED_DISCONNECT 1
53 * Attempt to read & decrypt an SSL record.
56 SSLReadRecord(SSLRecord
&rec
, SSLContext
*ctx
)
58 UInt32 len
, contentLen
;
60 SSLBuffer readData
, cipherFragment
;
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
);
68 if ((err
= SSLAllocBuffer(ctx
->partialReadBuffer
,
69 DEFAULT_BUFFER_SIZE
, ctx
)) != 0)
70 { SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
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
);
83 { if (err
== errSSLWouldBlock
)
84 ctx
->amountRead
+= len
;
86 SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
89 ctx
->amountRead
+= len
;
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
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
);
104 case SSL_Version_2_0
:
105 return SSL2ReadRecord(rec
, ctx
);
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
);
118 case errSSLWouldBlock
:
119 ctx
->amountRead
+= len
;
121 #if SSL_ALLOW_UNNOTICED_DISCONNECT
122 case errSSLClosedGraceful
:
123 /* legal if we're on record boundary and we've gotten past
125 if((ctx
->amountRead
== 0) && /* nothing pending */
126 (len
== 0) && /* nothing new */
127 (ctx
->state
== SSL2_HdskStateClientReady
)) { /* handshake done */
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
139 SSLChangeHdskState(ctx
, SSL_HdskStateNoNotifyClose
);
140 err
= errSSLClosedNoNotify
;
144 /* illegal disconnect */
145 err
= errSSLClosedAbort
;
146 /* and drop thru to default: fatal alert */
148 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
150 SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
155 ctx
->amountRead
+= len
;
158 assert(ctx
->amountRead
>= 5);
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
;
166 rec
.protocolVersion
= (SSLProtocolVersion
)SSLDecodeInt(charPtr
, 2);
168 contentLen
= SSLDecodeInt(charPtr
, 2);
170 if (contentLen
> (16384 + 2048)) /* Maximum legal length of an
171 * SSLCipherText payload */
172 { SSLFatalSessionAlert(SSL_AlertUnexpectedMsg
, ctx
);
173 return errSSLProtocol
;
176 if (ctx
->partialReadBuffer
.length
< 5 + contentLen
)
177 { if ((err
= SSLReallocBuffer(ctx
->partialReadBuffer
, 5 + contentLen
, ctx
)) != 0)
178 { SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
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
);
189 { if (err
== errSSLWouldBlock
)
190 ctx
->amountRead
+= len
;
192 SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
195 ctx
->amountRead
+= len
;
198 assert(ctx
->amountRead
>= 5 + contentLen
);
200 cipherFragment
.data
= ctx
->partialReadBuffer
.data
+ 5;
201 cipherFragment
.length
= contentLen
;
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
209 assert(ctx
->sslTslCalls
!= NULL
);
210 if ((err
= ctx
->sslTslCalls
->decryptRecord(rec
.contentType
,
211 &cipherFragment
, ctx
)) != 0)
215 * We appear to have sucessfully received a record; increment the
218 IncrementUInt64(&ctx
->readCipher
.sequenceNum
);
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
);
225 memcpy(rec
.contents
.data
, cipherFragment
.data
, cipherFragment
.length
);
227 ctx
->amountRead
= 0; /* We've used all the data in the cache */
232 /* common for sslv3 and tlsv1, except for the computeMac callout */
233 OSStatus
SSLVerifyMac(
240 UInt8 macData
[SSL_MAX_DIGEST_LEN
];
241 SSLBuffer secret
, mac
;
243 secret
.data
= ctx
->readCipher
.macSecret
;
244 secret
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
246 mac
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
248 assert(ctx
->sslTslCalls
!= NULL
);
249 if ((err
= ctx
->sslTslCalls
->computeMac(type
,
253 ctx
->readCipher
.sequenceNum
,
257 if ((memcmp(mac
.data
, compareMAC
, mac
.length
)) != 0) {
258 sslErrorLog("ssl3VerifyMac: Mac verify failure\n");
259 return errSSLProtocol
;