1/*
2 * Copyright (c) 1999-2001,2005-2007,2010-2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * sslRecord.c - Encryption, decryption and MACing of data
26*/
27
28#include <SecureTransport.h>
29#include "ssl.h"
30#include "sslRecord.h"
31#include "sslMemory.h"
32#include "sslContext.h"
33#include "sslAlertMessage.h"
34#include "sslDebug.h"
35#include "sslUtils.h"
36#include "sslDigests.h"
37#include "SSLRecordInternal.h"
38
39#include <string.h>
40#include <assert.h>
41
42#include <utilities/SecIOFormat.h>
43
44/*
45 * Lots of servers fail to provide closure alerts when they disconnect.
46 * For now we'll just accept it as long as it occurs on a clean record boundary
47 * (and the handshake is complete).
48 */
49#define SSL_ALLOW_UNNOTICED_DISCONNECT	1
50
51
52static OSStatus errorTranslate(int recordErr)
53{
54    switch(recordErr) {
55        case errSecSuccess:
56            return errSecSuccess;
57        case errSSLRecordInternal:
58            return errSSLInternal;
59        case errSSLRecordWouldBlock:
60            return errSSLWouldBlock;
61        case errSSLRecordProtocol:
62            return errSSLProtocol;
63        case errSSLRecordNegotiation:
64            return errSSLNegotiation;
65        case errSSLRecordClosedAbort:
66            return errSSLClosedAbort;
67        case errSSLRecordConnectionRefused:
68            return errSSLConnectionRefused;
69        case errSSLRecordDecryptionFail:
70            return errSSLDecryptionFail;
71        case errSSLRecordBadRecordMac:
72            return errSSLBadRecordMac;
73        case errSSLRecordRecordOverflow:
74            return errSSLRecordOverflow;
75        case errSSLRecordUnexpectedRecord:
76            return errSSLUnexpectedRecord;
77        default:
78            sslErrorLog("unknown error code returned in sslErrorTranslate: %d\n", recordErr);
79            return recordErr;
80    }
81}
82
83/* SSLWriteRecord
84 *  Attempt to encrypt and queue an SSL record.
85 */
86OSStatus
87SSLWriteRecord(SSLRecord rec, SSLContext *ctx)
88{
89    OSStatus    err;
90
91    err=errorTranslate(ctx->recFuncs->write(ctx->recCtx, rec));
92
93    switch(err) {
94        case errSecSuccess:
95            break;
96        default:
97            sslErrorLog("unexpected error code returned in SSLWriteRecord: %d\n", (int)err);
98            break;
99    }
100
101    return err;
102}
103
104/* SSLFreeRecord
105 *  Free a record returned by SSLReadRecord.
106 */
107OSStatus
108SSLFreeRecord(SSLRecord rec, SSLContext *ctx)
109{
110    return ctx->recFuncs->free(ctx->recCtx, rec);
111}
112
113/* SSLReadRecord
114 *  Attempt to read & decrypt an SSL record.
115 *  Record content should be freed using SSLFreeRecord
116 */
117OSStatus
118SSLReadRecord(SSLRecord *rec, SSLContext *ctx)
119{   OSStatus        err;
120
121    err=errorTranslate(ctx->recFuncs->read(ctx->recCtx, rec));
122
123    switch(err) {
124        case errSecSuccess:
125        case errSSLWouldBlock:
126            break;
127        case errSSLUnexpectedRecord:
128            DTLSRetransmit(ctx);
129            break;
130        case errSSLDecryptionFail:
131        case errSSLBadRecordMac:
132            /* We never send a Decryption Failed alert, instead we send the BadRecordMac alert */
133            /* This is TLS 1.1 compliant - Do it for all protocols versions. */
134            /* Except for DTLS where we do not send any alert. */
135            if(ctx->isDTLS) {
136                /* This will ensure we try to read again before returning to the caller
137                   We do NOT want to use errSSLWouldBlock here, as this should only indicate
138                   the IO read callback status */
139                err=errSSLUnexpectedRecord;
140            } else {
141                SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
142            }
143            break;
144        case errSSLInternal:
145            SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
146            break;
147        case errSSLRecordOverflow:
148            SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx);
149            break;
150        case errSSLClosedAbort:
151        case errSSLConnectionRefused:
152            SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
153            break;
154        default:
155            sslErrorLog("unknown error code returned in SSLReadRecord: %d\n", (int)err);
156            SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
157            break;
158    }
159
160    return err;
161}
162
163OSStatus SSLServiceWriteQueue(SSLContext *ctx)
164{
165    return errorTranslate(ctx->recFuncs->serviceWriteQueue(ctx->recCtx));
166}
167