1/*
2 * Copyright (c) 2002,2005-2007,2010-2011 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 * tls1RecordCallouts.c - TLSv1-specific routines for SslTlsCallouts.
26 */
27
28/* THIS FILE CONTAINS KERNEL CODE */
29
30#include "tls_record.h"
31#include "sslMemory.h"
32#include "sslDebug.h"
33#include "sslUtils.h"
34
35#include <AssertMacros.h>
36#include <string.h>
37
38/* not needed; encrypt/encode is the same for both protocols as long as
39 * we don't use the "variable length padding" feature. */
40#if 0
41static int tls1WriteRecord(
42	SSLRecord rec,
43	SSLContext *ctx)
44{
45	check(0);
46	return errSecUnimplemented;
47}
48#endif
49
50static int tls1DecryptRecord(
51	uint8_t type,
52	SSLBuffer *payload,
53	struct SSLRecordInternalContext *ctx)
54{
55	int    err;
56    SSLBuffer   content;
57
58    if ((ctx->readCipher.symCipher->params->blockSize > 0) &&
59        ((payload->length % ctx->readCipher.symCipher->params->blockSize) != 0)) {
60        return errSSLRecordRecordOverflow;
61    }
62
63    /* Decrypt in place */
64    if ((err = ctx->readCipher.symCipher->c.cipher.decrypt(payload->data,
65		payload->data, payload->length,
66		ctx->readCipher.cipherCtx)) != 0)
67    {
68        return errSSLRecordDecryptionFail;
69    }
70
71    /* Locate content within decrypted payload */
72
73    /* TLS 1.1 and DTLS 1.0 block ciphers */
74    if((ctx->negProtocolVersion>=TLS_Version_1_1) && (ctx->readCipher.symCipher->params->blockSize>0))
75    {
76        content.data = payload->data + ctx->readCipher.symCipher->params->blockSize;
77        content.length = payload->length - (ctx->readCipher.macRef->hash->digestSize + ctx->readCipher.symCipher->params->blockSize);
78    } else {
79        content.data = payload->data;
80        content.length = payload->length - ctx->readCipher.macRef->hash->digestSize;
81    }
82
83    /* Test for underflow - if the record size is smaller than required */
84    if(content.length > payload->length) {
85            return errSSLRecordClosedAbort;
86    }
87
88    err = 0;
89
90    if (ctx->readCipher.symCipher->params->blockSize > 0) {
91		/* for TLSv1, padding can be anywhere from 0 to 255 bytes */
92		uint8_t padSize = payload->data[payload->length - 1];
93
94        /* Padding check sequence:
95            1. Check that the padding size (last byte in padding) is within bound
96            2. Adjust content.length accordingly
97            3. Check every padding byte (except last, already checked)
98           Do not return, just set the error value on failure,
99           to avoid creating a padding oracle with timing.
100        */
101        if(padSize+1<=content.length) {
102            uint8_t *padChars;
103            content.length -= (1 + padSize);
104            padChars = payload->data + payload->length - (padSize+1);
105            while(padChars < (payload->data + payload->length - 1)) {
106                if(*padChars++ != padSize) {
107                    err = errSSLRecordBadRecordMac;
108                }
109            }
110        } else {
111            err = errSSLRecordBadRecordMac;
112        }
113    }
114
115	/* Verify MAC on payload */
116    if (ctx->readCipher.macRef->hash->digestSize > 0)
117    /* Optimize away MAC for null case */
118        if (SSLVerifyMac(type, &content,
119                          content.data + content.length, ctx) != 0)
120        {
121            err = errSSLRecordBadRecordMac;
122        }
123
124    *payload = content;     /* Modify payload buffer to indicate content length */
125
126    return err;
127}
128
129/* initialize a per-CipherContext HashHmacContext for use in MACing each record */
130static int tls1InitMac (
131	CipherContext *cipherCtx)		// macRef, macSecret valid on entry
132									// macCtx valid on return
133{
134	const HMACReference *hmac;
135	int serr;
136
137    check(cipherCtx);
138	check(cipherCtx->macRef != NULL);
139	hmac = cipherCtx->macRef->hmac;
140	check(hmac != NULL);
141
142	if(cipherCtx->macCtx.hmacCtx != NULL) {
143		hmac->free(cipherCtx->macCtx.hmacCtx);
144		cipherCtx->macCtx.hmacCtx = NULL;
145	}
146	serr = hmac->alloc(hmac, cipherCtx->macSecret,
147		cipherCtx->macRef->hmac->macSize, &cipherCtx->macCtx.hmacCtx);
148
149	/* mac secret now stored in macCtx.hmacCtx, delete it from cipherCtx */
150	memset(cipherCtx->macSecret, 0, sizeof(cipherCtx->macSecret));
151	return serr;
152}
153
154static int tls1FreeMac (
155	CipherContext *cipherCtx)
156{
157	/* this can be called on a completely zeroed out CipherContext... */
158	if(cipherCtx->macRef == NULL) {
159		return 0;
160	}
161	check(cipherCtx->macRef->hmac != NULL);
162
163	if(cipherCtx->macCtx.hmacCtx != NULL) {
164		cipherCtx->macRef->hmac->free(cipherCtx->macCtx.hmacCtx);
165		cipherCtx->macCtx.hmacCtx = NULL;
166	}
167	return 0;
168}
169
170/*
171 * mac = HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
172 *					TLSCompressed.version + TLSCompressed.length +
173 *					TLSCompressed.fragment));
174 */
175
176/* sequence, type, version, length */
177#define HDR_LENGTH (8 + 1 + 2 + 2)
178static int tls1ComputeMac (
179	uint8_t type,
180	SSLBuffer data,
181	SSLBuffer mac, 					// caller mallocs data
182	CipherContext *cipherCtx,		// assumes macCtx, macRef
183	sslUint64 seqNo,
184	struct SSLRecordInternalContext *ctx)
185{
186	uint8_t hdr[HDR_LENGTH];
187	uint8_t *p;
188	HMACContextRef hmacCtx;
189	int serr;
190	const HMACReference *hmac;
191	size_t macLength;
192
193	check(cipherCtx != NULL);
194	check(cipherCtx->macRef != NULL);
195	hmac = cipherCtx->macRef->hmac;
196	check(hmac != NULL);
197	hmacCtx = cipherCtx->macCtx.hmacCtx;	// may be NULL, for null cipher
198
199	serr = hmac->init(hmacCtx);
200	if(serr) {
201		goto fail;
202	}
203	p = SSLEncodeUInt64(hdr, seqNo);
204	*p++ = type;
205	*p++ = ctx->negProtocolVersion >> 8;
206	*p++ = ctx->negProtocolVersion & 0xff;
207	*p++ = data.length >> 8;
208	*p   = data.length & 0xff;
209	serr = hmac->update(hmacCtx, hdr, HDR_LENGTH);
210	if(serr) {
211		goto fail;
212	}
213	serr = hmac->update(hmacCtx, data.data, data.length);
214	if(serr) {
215		goto fail;
216	}
217	macLength = mac.length;
218	serr = hmac->final(hmacCtx, mac.data, &macLength);
219	if(serr) {
220		goto fail;
221	}
222	mac.length = macLength;
223fail:
224	return serr;
225}
226
227const SslRecordCallouts Tls1RecordCallouts = {
228	tls1DecryptRecord,
229	ssl3WriteRecord,
230	tls1InitMac,
231	tls1FreeMac,
232	tls1ComputeMac,
233};
234
235