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