]>
Commit | Line | Data |
---|---|---|
427c49bc A |
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 | |
41 | static int tls1WriteRecord( | |
42 | SSLRecord rec, | |
43 | SSLContext *ctx) | |
44 | { | |
45 | check(0); | |
46 | return errSecUnimplemented; | |
47 | } | |
48 | #endif | |
49 | ||
50 | static 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 */ | |
130 | static 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 | ||
154 | static 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) | |
178 | static 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; | |
223 | fail: | |
224 | return serr; | |
225 | } | |
226 | ||
227 | const SslRecordCallouts Tls1RecordCallouts = { | |
228 | tls1DecryptRecord, | |
229 | ssl3WriteRecord, | |
230 | tls1InitMac, | |
231 | tls1FreeMac, | |
232 | tls1ComputeMac, | |
233 | }; | |
234 |