-/* not needed; encrypt/encode is the same for both protocols as long as
- * we don't use the "variable length padding" feature. */
-#if 0
-static OSStatus tls1WriteRecord(
- SSLRecord rec,
- SSLContext *ctx)
-{
- assert(0);
- return unimpErr;
-}
-#endif
-
-static OSStatus tls1DecryptRecord(
- UInt8 type,
- SSLBuffer *payload,
- SSLContext *ctx)
-{
- OSStatus err;
- SSLBuffer content;
- bool decryption_failed_or_bad_record_mac = false;
-
- if ((ctx->readCipher.symCipher->blockSize > 0) &&
- ((payload->length % ctx->readCipher.symCipher->blockSize) != 0)) {
- SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx);
- return errSSLRecordOverflow;
- }
-
- /* Decrypt in place */
- if ((err = ctx->readCipher.symCipher->decrypt(payload->data,
- payload->data, payload->length,
- &ctx->readCipher,
- ctx)) != 0)
- {
- /* note: we no longer send a SSL_AlertDecryptError here;
- * all subsequent failures result in SSL_AlertBadRecordMac
- * being sent at the end of the function, to avoid leaking
- * differences between padding and decryption failures. */
- decryption_failed_or_bad_record_mac = true;
- }
-
- /* Locate content within decrypted payload */
-
- /* TLS 1.1 and DTLS 1.0 block ciphers */
- if((ctx->negProtocolVersion>=TLS_Version_1_1) && (ctx->readCipher.symCipher->blockSize>0))
- {
- content.data = payload->data + ctx->readCipher.symCipher->blockSize;
- content.length = payload->length - (ctx->readCipher.macRef->hash->digestSize + ctx->readCipher.symCipher->blockSize);
- } else {
- content.data = payload->data;
- content.length = payload->length - ctx->readCipher.macRef->hash->digestSize;
- }
-
- if (ctx->readCipher.symCipher->blockSize > 0) {
- /* for TLSv1, padding can be anywhere from 0 to 255 bytes */
- UInt8 padSize = payload->data[payload->length - 1];
- UInt8 *padChars;
-
- /* verify that all padding bytes are equal - WARNING - OpenSSL code
- * has a special case here dealing with some kind of bug related to
- * even size packets...beware... */
- if(padSize > payload->length) {
- /* This is TLS 1.1 compliant - Do it for all protocols versions */
- sslErrorLog("tls1DecryptRecord: bad padding length (%d)\n",
- (unsigned)payload->data[payload->length - 1]);
- decryption_failed_or_bad_record_mac = true;
- }
- padChars = payload->data + payload->length - padSize;
- while(padChars < (payload->data + payload->length)) {
- if(*padChars++ != padSize) {
- /* This is TLS 1.1 compliant - Do it for all protocols versions */
- sslErrorLog("tls1DecryptRecord: bad padding value\n");
- decryption_failed_or_bad_record_mac = true;
- }
- }
- /* Remove block size padding and its one-byte length */
- content.length -= (1 + padSize);
- }
-
- /* Verify MAC on payload */
- if (ctx->readCipher.macRef->hash->digestSize > 0)
- /* Optimize away MAC for null case */
- if ((err = SSLVerifyMac(type, &content,
- content.data + content.length, ctx)) != 0)
- {
- decryption_failed_or_bad_record_mac = true;
- }
-
- if (decryption_failed_or_bad_record_mac) {
- SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
- return errSSLDecryptionFail;
- }
-
- *payload = content; /* Modify payload buffer to indicate content length */
-
- return noErr;
-}
-
-/* initialize a per-CipherContext HashHmacContext for use in MACing each record */
-static OSStatus tls1InitMac (
- CipherContext *cipherCtx, // macRef, macSecret valid on entry
- // macCtx valid on return
- SSLContext *ctx)
-{
- const HMACReference *hmac;
- OSStatus serr;
-
- assert(cipherCtx->macRef != NULL);
- hmac = cipherCtx->macRef->hmac;
- assert(hmac != NULL);
-
- if(cipherCtx->macCtx.hmacCtx != NULL) {
- hmac->free(cipherCtx->macCtx.hmacCtx);
- cipherCtx->macCtx.hmacCtx = NULL;
- }
- serr = hmac->alloc(hmac, ctx, cipherCtx->macSecret,
- cipherCtx->macRef->hmac->macSize, &cipherCtx->macCtx.hmacCtx);
-
- /* mac secret now stored in macCtx.hmacCtx, delete it from cipherCtx */
- memset(cipherCtx->macSecret, 0, sizeof(cipherCtx->macSecret));
- return serr;
-}
-
-static OSStatus tls1FreeMac (
- CipherContext *cipherCtx)
-{
- /* this can be called on a completely zeroed out CipherContext... */
- if(cipherCtx->macRef == NULL) {
- return noErr;
- }
- assert(cipherCtx->macRef->hmac != NULL);
-
- if(cipherCtx->macCtx.hmacCtx != NULL) {
- cipherCtx->macRef->hmac->free(cipherCtx->macCtx.hmacCtx);
- cipherCtx->macCtx.hmacCtx = NULL;
- }
- return noErr;
-}
-
-/*
- * mac = HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
- * TLSCompressed.version + TLSCompressed.length +
- * TLSCompressed.fragment));
- */
-
-/* sequence, type, version, length */
-#define HDR_LENGTH (8 + 1 + 2 + 2)
-static OSStatus tls1ComputeMac (
- UInt8 type,
- SSLBuffer data,
- SSLBuffer mac, // caller mallocs data
- CipherContext *cipherCtx, // assumes macCtx, macRef
- sslUint64 seqNo,
- SSLContext *ctx)
-{
- uint8_t hdr[HDR_LENGTH];
- uint8_t *p;
- HMACContextRef hmacCtx;
- OSStatus serr;
- const HMACReference *hmac;
- size_t macLength;
-
- assert(cipherCtx != NULL);
- assert(cipherCtx->macRef != NULL);
- hmac = cipherCtx->macRef->hmac;
- assert(hmac != NULL);
- hmacCtx = cipherCtx->macCtx.hmacCtx; // may be NULL, for null cipher
-
- serr = hmac->init(hmacCtx);
- if(serr) {
- goto fail;
- }
- p = SSLEncodeUInt64(hdr, seqNo);
- *p++ = type;
- *p++ = ctx->negProtocolVersion >> 8;
- *p++ = ctx->negProtocolVersion & 0xff;
- *p++ = data.length >> 8;
- *p = data.length & 0xff;
- serr = hmac->update(hmacCtx, hdr, HDR_LENGTH);
- if(serr) {
- goto fail;
- }
- serr = hmac->update(hmacCtx, data.data, data.length);
- if(serr) {
- goto fail;
- }
- macLength = mac.length;
- serr = hmac->final(hmacCtx, mac.data, &macLength);
- if(serr) {
- goto fail;
- }
- mac.length = macLength;
-fail:
- return serr;
-}
-