Exemplo n.º 1
0
int ssl3_send_alert(SSL *s, int level, int desc) {
  /* Map tls/ssl alert value to correct one */
  desc = s->enc_method->alert_value(desc);
  if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION) {
    /* SSL 3.0 does not have protocol_version alerts */
    desc = SSL_AD_HANDSHAKE_FAILURE;
  }
  if (desc < 0) {
    return -1;
  }

  /* If a fatal one, remove from cache */
  if (level == 2 && s->session != NULL) {
    SSL_CTX_remove_session(s->ctx, s->session);
  }

  s->s3->alert_dispatch = 1;
  s->s3->send_alert[0] = level;
  s->s3->send_alert[1] = desc;
  if (!ssl_write_buffer_is_pending(s)) {
    /* Nothing is being written out, so the alert may be dispatched
     * immediately. */
    return s->method->ssl_dispatch_alert(s);
  }

  /* else data is still being written out, we will get written some time in the
   * future */
  return -1;
}
Exemplo n.º 2
0
int ssl3_send_alert(SSL *ssl, int level, int desc) {
  /* It is illegal to send an alert when we've already sent a closing one. */
  if (ssl->s3->send_shutdown != ssl_shutdown_none) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
    return -1;
  }

  if (level == SSL3_AL_FATAL) {
    if (ssl->session != NULL) {
      SSL_CTX_remove_session(ssl->ctx, ssl->session);
    }
    ssl->s3->send_shutdown = ssl_shutdown_fatal_alert;
  } else if (level == SSL3_AL_WARNING && desc == SSL_AD_CLOSE_NOTIFY) {
    ssl->s3->send_shutdown = ssl_shutdown_close_notify;
  }

  ssl->s3->alert_dispatch = 1;
  ssl->s3->send_alert[0] = level;
  ssl->s3->send_alert[1] = desc;
  if (!ssl_write_buffer_is_pending(ssl)) {
    /* Nothing is being written out, so the alert may be dispatched
     * immediately. */
    return ssl->method->dispatch_alert(ssl);
  }

  /* The alert will be dispatched later. */
  return -1;
}
Exemplo n.º 3
0
/* do_ssl3_write writes an SSL record of the given type. */
static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len) {
  /* If there is still data from the previous record, flush it. */
  if (ssl_write_buffer_is_pending(s)) {
    return ssl3_write_pending(s, type, buf, len);
  }

  /* If we have an alert to send, lets send it */
  if (s->s3->alert_dispatch) {
    int ret = s->method->ssl_dispatch_alert(s);
    if (ret <= 0) {
      return ret;
    }
    /* if it went, fall through and send more stuff */
  }

  if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
    return -1;
  }

  if (len == 0) {
    return 0;
  }

  size_t max_out = len + ssl_max_seal_overhead(s);
  if (max_out < len) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
    return -1;
  }
  uint8_t *out;
  size_t ciphertext_len;
  if (!ssl_write_buffer_init(s, &out, max_out) ||
      !tls_seal_record(s, out, &ciphertext_len, max_out, type, buf, len)) {
    return -1;
  }
  ssl_write_buffer_set_len(s, ciphertext_len);

  /* memorize arguments so that ssl3_write_pending can detect bad write retries
   * later */
  s->s3->wpend_tot = len;
  s->s3->wpend_buf = buf;
  s->s3->wpend_type = type;
  s->s3->wpend_ret = len;

  /* we now just need to write the buffer */
  return ssl3_write_pending(s, type, buf, len);
}
Exemplo n.º 4
0
int ssl3_send_alert(SSL *ssl, int level, int desc) {
  /* If a fatal one, remove from cache */
  if (level == 2 && ssl->session != NULL) {
    SSL_CTX_remove_session(ssl->ctx, ssl->session);
  }

  ssl->s3->alert_dispatch = 1;
  ssl->s3->send_alert[0] = level;
  ssl->s3->send_alert[1] = desc;
  if (!ssl_write_buffer_is_pending(ssl)) {
    /* Nothing is being written out, so the alert may be dispatched
     * immediately. */
    return ssl->method->ssl_dispatch_alert(ssl);
  }

  /* else data is still being written out, we will get written some time in the
   * future */
  return -1;
}
Exemplo n.º 5
0
static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
                          unsigned int len, enum dtls1_use_epoch_t use_epoch) {
  /* There should never be a pending write buffer in DTLS. One can't write half
   * a datagram, so the write buffer is always dropped in
   * |ssl_write_buffer_flush|. */
  assert(!ssl_write_buffer_is_pending(s));

  /* If we have an alert to send, lets send it */
  if (s->s3->alert_dispatch) {
    int ret = s->method->ssl_dispatch_alert(s);
    if (ret <= 0) {
      return ret;
    }
    /* if it went, fall through and send more stuff */
  }

  if (len > SSL3_RT_MAX_PLAIN_LENGTH) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
    return -1;
  }

  if (len == 0) {
    return 0;
  }

  size_t max_out = len + ssl_max_seal_overhead(s);
  uint8_t *out;
  size_t ciphertext_len;
  if (!ssl_write_buffer_init(s, &out, max_out) ||
      !dtls_seal_record(s, out, &ciphertext_len, max_out, type, buf, len,
                        use_epoch)) {
    ssl_write_buffer_clear(s);
    return -1;
  }
  ssl_write_buffer_set_len(s, ciphertext_len);

  int ret = ssl_write_buffer_flush(s);
  if (ret <= 0) {
    return ret;
  }
  return (int)len;
}
Exemplo n.º 6
0
/* Return up to 'len' payload bytes received in 'type' records.
 * 'type' is one of the following:
 *
 *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
 *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
 *   -  0 (during a shutdown, no data has to be returned)
 *
 * If we don't have stored data to work from, read a SSL/TLS record first
 * (possibly multiple records if we still don't have anything to return).
 *
 * This function must handle any surprises the peer may have for us, such as
 * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
 * a surprise, but handled as if it were), or renegotiation requests.
 * Also if record payloads contain fragments too small to process, we store
 * them until there is enough for the respective protocol (the record protocol
 * may use arbitrary fragmentation and even interleaving):
 *     Change cipher spec protocol
 *             just 1 byte needed, no need for keeping anything stored
 *     Alert protocol
 *             2 bytes needed (AlertLevel, AlertDescription)
 *     Handshake protocol
 *             4 bytes needed (HandshakeType, uint24 length) -- we just have
 *             to detect unexpected Client Hello and Hello Request messages
 *             here, anything else is handled by higher layers
 *     Application data protocol
 *             none of our business
 */
int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) {
  int al, i, ret;
  unsigned int n;
  SSL3_RECORD *rr;
  void (*cb)(const SSL *ssl, int type2, int val) = NULL;

  if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) ||
      (peek && type != SSL3_RT_APPLICATION_DATA)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
    return -1;
  }

  if (type == SSL3_RT_HANDSHAKE && s->s3->handshake_fragment_len > 0) {
    /* (partially) satisfy request from storage */
    uint8_t *src = s->s3->handshake_fragment;
    uint8_t *dst = buf;
    unsigned int k;

    /* peek == 0 */
    n = 0;
    while (len > 0 && s->s3->handshake_fragment_len > 0) {
      *dst++ = *src++;
      len--;
      s->s3->handshake_fragment_len--;
      n++;
    }
    /* move any remaining fragment bytes: */
    for (k = 0; k < s->s3->handshake_fragment_len; k++) {
      s->s3->handshake_fragment[k] = *src++;
    }
    return n;
  }

  /* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */

  /* This may require multiple iterations. False Start will cause
   * |s->handshake_func| to signal success one step early, but the handshake
   * must be completely finished before other modes are accepted.
   *
   * TODO(davidben): Move this check up to a higher level. */
  while (!s->in_handshake && SSL_in_init(s)) {
    assert(type == SSL3_RT_APPLICATION_DATA);
    i = s->handshake_func(s);
    if (i < 0) {
      return i;
    }
    if (i == 0) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
      return -1;
    }
  }

start:
  s->rwstate = SSL_NOTHING;

  /* s->s3->rrec.type    - is the type of record
   * s->s3->rrec.data    - data
   * s->s3->rrec.off     - offset into 'data' for next read
   * s->s3->rrec.length  - number of bytes. */
  rr = &s->s3->rrec;

  /* get new packet if necessary */
  if (rr->length == 0) {
    ret = ssl3_get_record(s);
    if (ret <= 0) {
      return ret;
    }
  }

  /* we now have a packet which can be read and processed */

  /* |change_cipher_spec is set when we receive a ChangeCipherSpec and reset by
   * ssl3_get_finished. */
  if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE &&
      rr->type != SSL3_RT_ALERT) {
    al = SSL_AD_UNEXPECTED_MESSAGE;
    OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
    goto f_err;
  }

  /* If we are expecting a ChangeCipherSpec, it is illegal to receive a
   * Handshake record. */
  if (rr->type == SSL3_RT_HANDSHAKE && (s->s3->flags & SSL3_FLAGS_EXPECT_CCS)) {
    al = SSL_AD_UNEXPECTED_MESSAGE;
    OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS);
    goto f_err;
  }

  /* If the other end has shut down, throw anything we read away (even in
   * 'peek' mode) */
  if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
    rr->length = 0;
    s->rwstate = SSL_NOTHING;
    return 0;
  }

  if (type != 0 && type == rr->type) {
    s->s3->warning_alert_count = 0;

    /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
    /* make sure that we are not getting application data when we are doing a
     * handshake for the first time */
    if (SSL_in_init(s) && type == SSL3_RT_APPLICATION_DATA &&
        s->aead_read_ctx == NULL) {
      /* TODO(davidben): Is this check redundant with the handshake_func
       * check? */
      al = SSL_AD_UNEXPECTED_MESSAGE;
      OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE);
      goto f_err;
    }

    /* Discard empty records. */
    if (rr->length == 0) {
      goto start;
    }

    if (len <= 0) {
      return len;
    }

    if ((unsigned int)len > rr->length) {
      n = rr->length;
    } else {
      n = (unsigned int)len;
    }

    memcpy(buf, &(rr->data[rr->off]), n);
    if (!peek) {
      rr->length -= n;
      rr->off += n;
      if (rr->length == 0) {
        rr->off = 0;
        /* The record has been consumed, so we may now clear the buffer. */
        ssl_read_buffer_discard(s);
      }
    }

    return n;
  }

  /* Process unexpected records. */

  if (rr->type == SSL3_RT_HANDSHAKE) {
    /* If peer renegotiations are disabled, all out-of-order handshake records
     * are fatal. Renegotiations as a server are never supported. */
    if (s->server || !ssl3_can_renegotiate(s)) {
      al = SSL_AD_NO_RENEGOTIATION;
      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
      goto f_err;
    }

    /* HelloRequests may be fragmented across multiple records. */
    const size_t size = sizeof(s->s3->handshake_fragment);
    const size_t avail = size - s->s3->handshake_fragment_len;
    const size_t todo = (rr->length < avail) ? rr->length : avail;
    memcpy(s->s3->handshake_fragment + s->s3->handshake_fragment_len,
           &rr->data[rr->off], todo);
    rr->off += todo;
    rr->length -= todo;
    s->s3->handshake_fragment_len += todo;
    if (s->s3->handshake_fragment_len < size) {
      goto start; /* fragment was too small */
    }

    /* Parse out and consume a HelloRequest. */
    if (s->s3->handshake_fragment[0] != SSL3_MT_HELLO_REQUEST ||
        s->s3->handshake_fragment[1] != 0 ||
        s->s3->handshake_fragment[2] != 0 ||
        s->s3->handshake_fragment[3] != 0) {
      al = SSL_AD_DECODE_ERROR;
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
      goto f_err;
    }
    s->s3->handshake_fragment_len = 0;

    if (s->msg_callback) {
      s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
                      s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
    }

    if (!SSL_is_init_finished(s) || !s->s3->initial_handshake_complete) {
      /* This cannot happen. If a handshake is in progress, |type| must be
       * |SSL3_RT_HANDSHAKE|. */
      assert(0);
      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
      goto err;
    }

    /* Renegotiation is only supported at quiescent points in the application
     * protocol, namely in HTTPS, just before reading the HTTP response. Require
     * the record-layer be idle and avoid complexities of sending a handshake
     * record while an application_data record is being written. */
    if (ssl_write_buffer_is_pending(s)) {
      al = SSL_AD_NO_RENEGOTIATION;
      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
      goto f_err;
    }

    /* Begin a new handshake. */
    s->s3->total_renegotiations++;
    s->state = SSL_ST_CONNECT;
    i = s->handshake_func(s);
    if (i < 0) {
      return i;
    }
    if (i == 0) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
      return -1;
    }

    /* The handshake completed synchronously. Continue reading records. */
    goto start;
  }

  /* If an alert record, process one alert out of the record. Note that we allow
   * a single record to contain multiple alerts. */
  if (rr->type == SSL3_RT_ALERT) {
    /* Alerts may not be fragmented. */
    if (rr->length < 2) {
      al = SSL_AD_DECODE_ERROR;
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
      goto f_err;
    }

    if (s->msg_callback) {
      s->msg_callback(0, s->version, SSL3_RT_ALERT, &rr->data[rr->off], 2, s,
                      s->msg_callback_arg);
    }
    const uint8_t alert_level = rr->data[rr->off++];
    const uint8_t alert_descr = rr->data[rr->off++];
    rr->length -= 2;

    if (s->info_callback != NULL) {
      cb = s->info_callback;
    } else if (s->ctx->info_callback != NULL) {
      cb = s->ctx->info_callback;
    }

    if (cb != NULL) {
      uint16_t alert = (alert_level << 8) | alert_descr;
      cb(s, SSL_CB_READ_ALERT, alert);
    }

    if (alert_level == SSL3_AL_WARNING) {
      s->s3->warn_alert = alert_descr;
      if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
        s->shutdown |= SSL_RECEIVED_SHUTDOWN;
        return 0;
      }

      /* This is a warning but we receive it if we requested renegotiation and
       * the peer denied it. Terminate with a fatal alert because if
       * application tried to renegotiatie it presumably had a good reason and
       * expects it to succeed.
       *
       * In future we might have a renegotiation where we don't care if the
       * peer refused it where we carry on. */
      else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
        al = SSL_AD_HANDSHAKE_FAILURE;
        OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
        goto f_err;
      }

      s->s3->warning_alert_count++;
      if (s->s3->warning_alert_count > kMaxWarningAlerts) {
        al = SSL_AD_UNEXPECTED_MESSAGE;
        OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS);
        goto f_err;
      }
    } else if (alert_level == SSL3_AL_FATAL) {
      char tmp[16];

      s->rwstate = SSL_NOTHING;
      s->s3->fatal_alert = alert_descr;
      OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
      BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
      ERR_add_error_data(2, "SSL alert number ", tmp);
      s->shutdown |= SSL_RECEIVED_SHUTDOWN;
      SSL_CTX_remove_session(s->ctx, s->session);
      return 0;
    } else {
      al = SSL_AD_ILLEGAL_PARAMETER;
      OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
      goto f_err;
    }

    goto start;
  }

  if (s->shutdown & SSL_SENT_SHUTDOWN) {
    /* close_notify has been sent, so discard all records other than alerts. */
    rr->length = 0;
    goto start;
  }

  if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
    /* 'Change Cipher Spec' is just a single byte, so we know exactly what the
     * record payload has to look like */
    if (rr->length != 1 || rr->off != 0 || rr->data[0] != SSL3_MT_CCS) {
      al = SSL_AD_ILLEGAL_PARAMETER;
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
      goto f_err;
    }

    /* Check we have a cipher to change to */
    if (s->s3->tmp.new_cipher == NULL) {
      al = SSL_AD_UNEXPECTED_MESSAGE;
      OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY);
      goto f_err;
    }

    if (!(s->s3->flags & SSL3_FLAGS_EXPECT_CCS)) {
      al = SSL_AD_UNEXPECTED_MESSAGE;
      OPENSSL_PUT_ERROR(SSL, SSL_R_CCS_RECEIVED_EARLY);
      goto f_err;
    }

    s->s3->flags &= ~SSL3_FLAGS_EXPECT_CCS;

    rr->length = 0;

    if (s->msg_callback) {
      s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s,
                      s->msg_callback_arg);
    }

    s->s3->change_cipher_spec = 1;
    if (!ssl3_do_change_cipher_spec(s)) {
      goto err;
    } else {
      goto start;
    }
  }

  /* We already handled these. */
  assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT &&
         rr->type != SSL3_RT_HANDSHAKE);

  al = SSL_AD_UNEXPECTED_MESSAGE;
  OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);

f_err:
  ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
  return -1;
}
Exemplo n.º 7
0
/* Return up to 'len' payload bytes received in 'type' records.
 * 'type' is one of the following:
 *
 *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
 *   -  SSL3_RT_CHANGE_CIPHER_SPEC (when ssl3_read_change_cipher_spec calls us)
 *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read_app_data calls us)
 *   -  0 (during a shutdown, no data has to be returned)
 *
 * If we don't have stored data to work from, read a SSL/TLS record first
 * (possibly multiple records if we still don't have anything to return).
 *
 * This function must handle any surprises the peer may have for us, such as
 * Alert records (e.g. close_notify) or renegotiation requests. */
int ssl3_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek) {
  int al, i, ret;
  unsigned int n;
  SSL3_RECORD *rr;
  void (*cb)(const SSL *ssl, int type, int value) = NULL;

  if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE &&
       type != SSL3_RT_CHANGE_CIPHER_SPEC) ||
      (peek && type != SSL3_RT_APPLICATION_DATA)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
    return -1;
  }

start:
  ssl->rwstate = SSL_NOTHING;

  /* ssl->s3->rrec.type    - is the type of record
   * ssl->s3->rrec.data    - data
   * ssl->s3->rrec.off     - offset into 'data' for next read
   * ssl->s3->rrec.length  - number of bytes. */
  rr = &ssl->s3->rrec;

  /* get new packet if necessary */
  if (rr->length == 0) {
    ret = ssl3_get_record(ssl);
    if (ret <= 0) {
      return ret;
    }
  }

  /* we now have a packet which can be read and processed */

  /* If the other end has shut down, throw anything we read away (even in
   * 'peek' mode) */
  if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) {
    rr->length = 0;
    ssl->rwstate = SSL_NOTHING;
    return 0;
  }

  if (type != 0 && type == rr->type) {
    ssl->s3->warning_alert_count = 0;

    /* Make sure that we are not getting application data when we are doing a
     * handshake for the first time. */
    if (SSL_in_init(ssl) && type == SSL3_RT_APPLICATION_DATA &&
        ssl->s3->aead_read_ctx == NULL) {
      /* TODO(davidben): Is this check redundant with the handshake_func
       * check? */
      al = SSL_AD_UNEXPECTED_MESSAGE;
      OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE);
      goto f_err;
    }

    /* Discard empty records. */
    if (rr->length == 0) {
      goto start;
    }

    if (len <= 0) {
      return len;
    }

    if ((unsigned int)len > rr->length) {
      n = rr->length;
    } else {
      n = (unsigned int)len;
    }

    memcpy(buf, rr->data, n);
    if (!peek) {
      rr->length -= n;
      rr->data += n;
      if (rr->length == 0) {
        /* The record has been consumed, so we may now clear the buffer. */
        ssl_read_buffer_discard(ssl);
      }
    }

    return n;
  }

  /* Process unexpected records. */

  if (type == SSL3_RT_APPLICATION_DATA && rr->type == SSL3_RT_HANDSHAKE) {
    /* If peer renegotiations are disabled, all out-of-order handshake records
     * are fatal. Renegotiations as a server are never supported. */
    if (ssl->server || !ssl3_can_renegotiate(ssl)) {
      al = SSL_AD_NO_RENEGOTIATION;
      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
      goto f_err;
    }

    /* This must be a HelloRequest, possibly fragmented over multiple records.
     * Consume data from the handshake protocol until it is complete. */
    static const uint8_t kHelloRequest[] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0};
    while (ssl->s3->hello_request_len < sizeof(kHelloRequest)) {
      if (rr->length == 0) {
        /* Get a new record. */
        goto start;
      }
      if (rr->data[0] != kHelloRequest[ssl->s3->hello_request_len]) {
        al = SSL_AD_DECODE_ERROR;
        OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
        goto f_err;
      }
      rr->data++;
      rr->length--;
      ssl->s3->hello_request_len++;
    }
    ssl->s3->hello_request_len = 0;

    if (ssl->msg_callback) {
      ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, kHelloRequest,
                      sizeof(kHelloRequest), ssl, ssl->msg_callback_arg);
    }

    if (!SSL_is_init_finished(ssl) || !ssl->s3->initial_handshake_complete) {
      /* This cannot happen. If a handshake is in progress, |type| must be
       * |SSL3_RT_HANDSHAKE|. */
      assert(0);
      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
      goto err;
    }

    if (ssl->renegotiate_mode == ssl_renegotiate_ignore) {
      goto start;
    }

    /* Renegotiation is only supported at quiescent points in the application
     * protocol, namely in HTTPS, just before reading the HTTP response. Require
     * the record-layer be idle and avoid complexities of sending a handshake
     * record while an application_data record is being written. */
    if (ssl_write_buffer_is_pending(ssl)) {
      al = SSL_AD_NO_RENEGOTIATION;
      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
      goto f_err;
    }

    /* Begin a new handshake. */
    ssl->s3->total_renegotiations++;
    ssl->state = SSL_ST_CONNECT;
    i = ssl->handshake_func(ssl);
    if (i < 0) {
      return i;
    }
    if (i == 0) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
      return -1;
    }

    /* The handshake completed synchronously. Continue reading records. */
    goto start;
  }

  /* If an alert record, process one alert out of the record. Note that we allow
   * a single record to contain multiple alerts. */
  if (rr->type == SSL3_RT_ALERT) {
    /* Alerts may not be fragmented. */
    if (rr->length < 2) {
      al = SSL_AD_DECODE_ERROR;
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
      goto f_err;
    }

    if (ssl->msg_callback) {
      ssl->msg_callback(0, ssl->version, SSL3_RT_ALERT, rr->data, 2, ssl,
                        ssl->msg_callback_arg);
    }
    const uint8_t alert_level = rr->data[0];
    const uint8_t alert_descr = rr->data[1];
    rr->length -= 2;
    rr->data += 2;

    if (ssl->info_callback != NULL) {
      cb = ssl->info_callback;
    } else if (ssl->ctx->info_callback != NULL) {
      cb = ssl->ctx->info_callback;
    }

    if (cb != NULL) {
      uint16_t alert = (alert_level << 8) | alert_descr;
      cb(ssl, SSL_CB_READ_ALERT, alert);
    }

    if (alert_level == SSL3_AL_WARNING) {
      if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
        ssl->s3->clean_shutdown = 1;
        ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
        return 0;
      }

      /* This is a warning but we receive it if we requested renegotiation and
       * the peer denied it. Terminate with a fatal alert because if
       * application tried to renegotiatie it presumably had a good reason and
       * expects it to succeed.
       *
       * In future we might have a renegotiation where we don't care if the
       * peer refused it where we carry on. */
      else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
        al = SSL_AD_HANDSHAKE_FAILURE;
        OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
        goto f_err;
      }

      ssl->s3->warning_alert_count++;
      if (ssl->s3->warning_alert_count > kMaxWarningAlerts) {
        al = SSL_AD_UNEXPECTED_MESSAGE;
        OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS);
        goto f_err;
      }
    } else if (alert_level == SSL3_AL_FATAL) {
      char tmp[16];

      ssl->rwstate = SSL_NOTHING;
      OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
      BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
      ERR_add_error_data(2, "SSL alert number ", tmp);
      ssl->shutdown |= SSL_RECEIVED_SHUTDOWN;
      SSL_CTX_remove_session(ssl->ctx, ssl->session);
      return 0;
    } else {
      al = SSL_AD_ILLEGAL_PARAMETER;
      OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
      goto f_err;
    }

    goto start;
  }

  if (ssl->shutdown & SSL_SENT_SHUTDOWN) {
    /* close_notify has been sent, so discard all records other than alerts. */
    rr->length = 0;
    goto start;
  }

  al = SSL_AD_UNEXPECTED_MESSAGE;
  OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);

f_err:
  ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
err:
  return -1;
}
Exemplo n.º 8
0
/* Return up to 'len' payload bytes received in 'type' records.
 * 'type' is one of the following:
 *
 *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
 *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read_app_data calls us)
 *
 * If we don't have stored data to work from, read a SSL/TLS record first
 * (possibly multiple records if we still don't have anything to return).
 *
 * This function must handle any surprises the peer may have for us, such as
 * Alert records (e.g. close_notify) or renegotiation requests. */
int ssl3_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek) {
  int al, i, ret;
  unsigned int n;
  SSL3_RECORD *rr;

  if ((type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) ||
      (peek && type != SSL3_RT_APPLICATION_DATA)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
    return -1;
  }

start:
  /* ssl->s3->rrec.type    - is the type of record
   * ssl->s3->rrec.data    - data
   * ssl->s3->rrec.off     - offset into 'data' for next read
   * ssl->s3->rrec.length  - number of bytes. */
  rr = &ssl->s3->rrec;

  /* get new packet if necessary */
  if (rr->length == 0) {
    ret = ssl3_get_record(ssl);
    if (ret <= 0) {
      return ret;
    }
  }

  /* we now have a packet which can be read and processed */

  if (type == rr->type) {
    /* Discard empty records. */
    if (rr->length == 0) {
      goto start;
    }

    if (len <= 0) {
      return len;
    }

    if ((unsigned int)len > rr->length) {
      n = rr->length;
    } else {
      n = (unsigned int)len;
    }

    memcpy(buf, rr->data, n);
    if (!peek) {
      rr->length -= n;
      rr->data += n;
      if (rr->length == 0) {
        /* The record has been consumed, so we may now clear the buffer. */
        ssl_read_buffer_discard(ssl);
      }
    }

    return n;
  }

  /* Process unexpected records. */

  if (type == SSL3_RT_APPLICATION_DATA && rr->type == SSL3_RT_HANDSHAKE) {
    /* If peer renegotiations are disabled, all out-of-order handshake records
     * are fatal. Renegotiations as a server are never supported. */
    if (ssl->server || !ssl3_can_renegotiate(ssl)) {
      al = SSL_AD_NO_RENEGOTIATION;
      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
      goto f_err;
    }

    /* This must be a HelloRequest, possibly fragmented over multiple records.
     * Consume data from the handshake protocol until it is complete. */
    static const uint8_t kHelloRequest[] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0};
    while (ssl->s3->hello_request_len < sizeof(kHelloRequest)) {
      if (rr->length == 0) {
        /* Get a new record. */
        goto start;
      }
      if (rr->data[0] != kHelloRequest[ssl->s3->hello_request_len]) {
        al = SSL_AD_DECODE_ERROR;
        OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
        goto f_err;
      }
      rr->data++;
      rr->length--;
      ssl->s3->hello_request_len++;
    }
    ssl->s3->hello_request_len = 0;

    ssl_do_msg_callback(ssl, 0 /* read */, ssl->version, SSL3_RT_HANDSHAKE,
                        kHelloRequest, sizeof(kHelloRequest));

    if (ssl->renegotiate_mode == ssl_renegotiate_ignore) {
      goto start;
    }

    /* Renegotiation is only supported at quiescent points in the application
     * protocol, namely in HTTPS, just before reading the HTTP response. Require
     * the record-layer be idle and avoid complexities of sending a handshake
     * record while an application_data record is being written. */
    if (ssl_write_buffer_is_pending(ssl)) {
      al = SSL_AD_NO_RENEGOTIATION;
      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
      goto f_err;
    }

    /* Begin a new handshake. */
    ssl->s3->total_renegotiations++;
    ssl->state = SSL_ST_CONNECT;
    i = ssl->handshake_func(ssl);
    if (i < 0) {
      return i;
    }
    if (i == 0) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
      return -1;
    }

    /* The handshake completed synchronously. Continue reading records. */
    goto start;
  }

  al = SSL_AD_UNEXPECTED_MESSAGE;
  OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);

f_err:
  ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
  return -1;
}