/ lib / sslChangeCipher.c
sslChangeCipher.c
  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   * sslChangeCipher.c - support for change cipher spec messages
 26   */
 27  
 28  #include "tls_handshake_priv.h"
 29  #include "sslHandshake.h"
 30  #include "sslHandshake_priv.h"
 31  #include "sslMemory.h"
 32  #include "sslAlertMessage.h"
 33  #include "sslDebug.h"
 34  #include "sslCipherSpecs.h"
 35  
 36  #include <assert.h>
 37  #include <string.h>
 38  
 39  int
 40  SSLEncodeChangeCipherSpec(tls_buffer *rec, tls_handshake_t ctx)
 41  {   int          err;
 42      
 43      assert(ctx->writePending_ready);
 44      
 45      sslLogNegotiateDebug("===Sending changeCipherSpec msg");
 46  	assert(ctx->negProtocolVersion >= tls_protocol_version_SSL_3);
 47      rec->length = 1;
 48      if ((err = SSLAllocBuffer(rec, 1)))
 49          return err;
 50      rec->data[0] = 1;
 51  
 52      ctx->messageQueueContainsChangeCipherSpec=true;
 53  
 54      return errSSLSuccess;
 55  }
 56  
 57  int
 58  SSLProcessChangeCipherSpec(tls_buffer rec, tls_handshake_t ctx)
 59  {   int          err;
 60  
 61      if (rec.length != 1 || rec.data[0] != 1)
 62      {
 63  #warning This is fishy:
 64          if(ctx->isDTLS)
 65              return errSSLUnexpectedRecord;
 66  
 67          SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx);
 68      	sslErrorLog("***bad changeCipherSpec msg: length %d data 0x%x\n",
 69      		(unsigned)rec.length, (unsigned)rec.data[0]);
 70          return errSSLProtocol;
 71      }
 72  
 73  	/*
 74  	 * Handle PAC-style session resumption, client side only.
 75  	 * In that case, the handshake state was left in either KeyExchange or
 76  	 * Cert.
 77       * Other client side resumption cases are handled in SSLAdvanceHandshake
 78       * (case SSL_HdskServerHello:).
 79  	 */
 80  	if((!ctx->isServer) &&
 81  	   (ctx->externalSessionTicket.length != 0) &&
 82  	   ((ctx->state == SSL_HdskStateKeyExchange) || (ctx->state == SSL_HdskStateCert)) &&
 83  	   (ctx->masterSecretCallback != NULL)) {
 84  		size_t secretLen = SSL_MASTER_SECRET_SIZE;
 85  		sslEapDebug("Client side resuming based on masterSecretCallback");
 86  		ctx->masterSecretCallback(ctx->masterSecretArg,
 87  			ctx->masterSecret, &secretLen);
 88  		ctx->sessionMatch = 1;
 89  
 90  		/* set up selectedCipherSpec */
 91  		if ((err = ValidateSelectedCiphersuite(ctx)) != 0) {
 92  			return err;
 93  		}
 94  		if((err = SSLInitPendingCiphers(ctx)) != 0) {
 95  			SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
 96  			return err;
 97  		}
 98  		SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec);
 99  	}
100  
101      if (!ctx->readPending_ready || ctx->state != SSL_HdskStateChangeCipherSpec)
102      {
103          // This mean we received a ChangeCipherSpec message when we didnt expect it.
104          // Just drop silently.
105          if(ctx->isDTLS)
106              return errSSLUnexpectedRecord;
107  
108          SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx);
109      	sslErrorLog("***bad changeCipherSpec msg: readPending.ready %d state %d\n",
110  		(unsigned)ctx->readPending_ready, (unsigned)ctx->state);
111          return errSSLProtocol;
112      }
113  
114      sslLogNegotiateDebug("===Processing changeCipherSpec msg");
115  
116      /* Install new cipher spec on read side */
117      /* TODO: if we want to enable app data during most of handshake, 
118         we should disable read channel here:
119          sslReadReady(ctx, false);
120      */
121      if ((err = ctx->callbacks->advance_read_cipher(ctx->callback_ctx)) != 0)
122      {
123          SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
124          return err;
125      }
126      /* make the pending read cipher invalid */
127      ctx->readPending_ready = 0;
128      SSLChangeHdskState(ctx, SSL_HdskStateFinished);
129      return errSSLSuccess;
130  }
131