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_AlertInternalError
, ctx
);
68 if ((err
= SSLAllocBuffer(ctx
->partialReadBuffer
,
69 DEFAULT_BUFFER_SIZE
, ctx
)) != 0)
70 { SSLFatalSessionAlert(SSL_AlertInternalError
, ctx
);
75 if (ctx
->negProtocolVersion
== SSL_Version_Undetermined
) {
76 if (ctx
->amountRead
< 1)
77 { readData
.length
= 1 - ctx
->amountRead
;
78 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
79 len
= readData
.length
;
80 err
= sslIoRead(readData
, &len
, ctx
);
82 { if (err
== errSSLWouldBlock
) {
83 ctx
->amountRead
+= len
;
88 SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
89 return errSSLClosedAbort
;
92 ctx
->amountRead
+= len
;
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
100 switch (ctx
->negProtocolVersion
)
101 { case SSL_Version_Undetermined
:
102 if (ctx
->partialReadBuffer
.data
[0] < SSL_RecordTypeV3_Smallest
||
103 ctx
->partialReadBuffer
.data
[0] > SSL_RecordTypeV3_Largest
)
104 return SSL2ReadRecord(rec
, ctx
);
107 case SSL_Version_2_0
:
108 return SSL2ReadRecord(rec
, ctx
);
113 if (ctx
->amountRead
< 5)
114 { readData
.length
= 5 - ctx
->amountRead
;
115 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
116 len
= readData
.length
;
117 err
= sslIoRead(readData
, &len
, ctx
);
121 case errSSLWouldBlock
:
122 ctx
->amountRead
+= len
;
124 #if SSL_ALLOW_UNNOTICED_DISCONNECT
125 case errSSLClosedGraceful
:
126 /* legal if we're on record boundary and we've gotten past
128 if((ctx
->amountRead
== 0) && /* nothing pending */
129 (len
== 0) && /* nothing new */
130 (ctx
->state
== SSL_HdskStateClientReady
)) { /* handshake done */
132 * This means that the server has disconnected without
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
138 * a errSSLClosedGraceful error. Paranoid
139 * clients can detect it and handle it however they
142 SSLChangeHdskState(ctx
, SSL_HdskStateNoNotifyClose
);
143 err
= errSSLClosedNoNotify
;
147 /* illegal disconnect */
148 err
= errSSLClosedAbort
;
149 /* and drop thru to default: fatal alert */
151 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
153 SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
158 ctx
->amountRead
+= len
;
161 assert(ctx
->amountRead
>= 5);
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
;
169 rec
.protocolVersion
= (SSLProtocolVersion
)SSLDecodeInt(charPtr
, 2);
171 contentLen
= SSLDecodeInt(charPtr
, 2);
173 if (contentLen
> (16384 + 2048)) /* Maximum legal length of an
174 * SSLCipherText payload */
175 { SSLFatalSessionAlert(SSL_AlertRecordOverflow
, ctx
);
176 return errSSLProtocol
;
179 if (ctx
->partialReadBuffer
.length
< 5 + contentLen
)
180 { if ((err
= SSLReallocBuffer(ctx
->partialReadBuffer
, 5 + contentLen
, ctx
)) != 0)
181 { SSLFatalSessionAlert(SSL_AlertInternalError
, ctx
);
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
;
190 err
= sslIoRead(readData
, &len
, ctx
);
192 { if (err
== errSSLWouldBlock
)
193 ctx
->amountRead
+= len
;
195 SSLFatalSessionAlert(SSL_AlertCloseNotify
, ctx
);
198 ctx
->amountRead
+= len
;
201 assert(ctx
->amountRead
>= 5 + contentLen
);
203 cipherFragment
.data
= ctx
->partialReadBuffer
.data
+ 5;
204 cipherFragment
.length
= contentLen
;
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
212 assert(ctx
->sslTslCalls
!= NULL
);
213 if ((err
= ctx
->sslTslCalls
->decryptRecord(rec
.contentType
,
214 &cipherFragment
, ctx
)) != 0)
218 * We appear to have sucessfully received a record; increment the
221 IncrementUInt64(&ctx
->readCipher
.sequenceNum
);
223 /* Allocate a buffer to return the plaintext in and return it */
224 if ((err
= SSLAllocBuffer(rec
.contents
, cipherFragment
.length
, ctx
)) != 0)
225 { SSLFatalSessionAlert(SSL_AlertInternalError
, ctx
);
228 memcpy(rec
.contents
.data
, cipherFragment
.data
, cipherFragment
.length
);
230 ctx
->amountRead
= 0; /* We've used all the data in the cache */
235 /* common for sslv3 and tlsv1, except for the computeMac callout */
236 OSStatus
SSLVerifyMac(
243 UInt8 macData
[SSL_MAX_DIGEST_LEN
];
244 SSLBuffer secret
, mac
;
246 secret
.data
= ctx
->readCipher
.macSecret
;
247 secret
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
249 mac
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
251 assert(ctx
->sslTslCalls
!= NULL
);
252 if ((err
= ctx
->sslTslCalls
->computeMac(type
,
256 ctx
->readCipher
.sequenceNum
,
260 if ((memcmp(mac
.data
, compareMAC
, mac
.length
)) != 0) {
261 sslErrorLog("ssl3VerifyMac: Mac verify failure\n");
262 return errSSLProtocol
;