Пример #1
0
int
_gnutls_recv_client_kx_message (gnutls_session_t session)
{
  gnutls_buffer_st buf;
  int ret = 0;


  /* Do key exchange only if the algorithm permits it */
  if (session->internals.auth_struct->gnutls_process_client_kx != NULL)
    {

      ret =
        _gnutls_recv_handshake (session, 
                                GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE,
                                MANDATORY_PACKET, &buf);
      if (ret < 0)
        return ret;

      ret =
        session->internals.auth_struct->gnutls_process_client_kx (session,
                                                                  buf.data,
                                                                  buf.length);
      _gnutls_buffer_clear (&buf);
      if (ret < 0)
        return ret;

    }

  return ret;
}
Пример #2
0
int
_gnutls_recv_server_certificate_request (gnutls_session_t session)
{
    uint8_t *data;
    int datasize;
    int ret = 0;

    if (session->internals.
            auth_struct->gnutls_process_server_certificate_request != NULL)
    {

        ret =
            _gnutls_recv_handshake (session, &data,
                                    &datasize,
                                    GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST,
                                    OPTIONAL_PACKET);
        if (ret < 0)
            return ret;

        if (ret == 0 && datasize == 0)
            return 0;		/* ignored */

        ret =
            session->internals.
            auth_struct->gnutls_process_server_certificate_request (session, data,
                    datasize);
        gnutls_free (data);
        if (ret < 0)
            return ret;

    }
    return ret;
}
Пример #3
0
int
_gnutls_recv_server_certificate_request (gnutls_session_t session)
{
  gnutls_buffer_st buf;
  int ret = 0;

  if (session->internals.
      auth_struct->gnutls_process_server_certificate_request != NULL)
    {

      ret =
        _gnutls_recv_handshake (session, 
                                GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST,
                                OPTIONAL_PACKET, &buf);
      if (ret < 0)
        return ret;

      if (ret == 0 && buf.length == 0)
        {
          _gnutls_buffer_clear(&buf);
          return 0;               /* ignored */
        }

      ret =
        session->internals.
        auth_struct->gnutls_process_server_certificate_request (session, buf.data,
                                                                buf.length);
      _gnutls_buffer_clear (&buf);
      if (ret < 0)
        return ret;

    }
  return ret;
}
Пример #4
0
int _gnutls_recv_server_kx_message(gnutls_session_t session)
{
	gnutls_buffer_st buf;
	int ret = 0;
	unsigned int optflag = 0;

	if (session->internals.auth_struct->gnutls_process_server_kx !=
	    NULL) {
		/* Server key exchange packet is optional for PSK. */
		if (_gnutls_session_is_psk(session))
			optflag = 1;

		ret =
		    _gnutls_recv_handshake(session,
					   GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE,
					   optflag, &buf);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		ret =
		    session->internals.auth_struct->
		    gnutls_process_server_kx(session, buf.data,
					     buf.length);
		_gnutls_buffer_clear(&buf);

		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

	}
	return ret;
}
Пример #5
0
int
_gnutls_recv_client_kx_message (gnutls_session_t session)
{
    uint8_t *data;
    int datasize;
    int ret = 0;


    /* Do key exchange only if the algorithm permits it */
    if (session->internals.auth_struct->gnutls_process_client_kx != NULL)
    {

        ret =
            _gnutls_recv_handshake (session, &data,
                                    &datasize,
                                    GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE,
                                    MANDATORY_PACKET);
        if (ret < 0)
            return ret;

        ret =
            session->internals.auth_struct->gnutls_process_client_kx (session,
                    data,
                    datasize);
        gnutls_free (data);
        if (ret < 0)
            return ret;

    }

    return ret;
}
Пример #6
0
int
_gnutls_recv_server_certificate (gnutls_session_t session)
{
  gnutls_buffer_st buf;
  int ret = 0;

  if (session->internals.auth_struct->gnutls_process_server_certificate !=
      NULL)
    {

      ret =
        _gnutls_recv_handshake (session, 
                                GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
                                MANDATORY_PACKET, &buf);
      if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }

      ret =
        session->internals.
        auth_struct->gnutls_process_server_certificate (session, buf.data,
                                                        buf.length);
      _gnutls_buffer_clear(&buf);
      if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }
    }

  return ret;
}
Пример #7
0
int
_gnutls_recv_server_kx_message (gnutls_session_t session)
{
    uint8_t *data = NULL;
    int datasize;
    int ret = 0;
    Optional optflag = MANDATORY_PACKET;

    if (session->internals.auth_struct->gnutls_process_server_kx != NULL)
    {

        /* EXCEPTION FOR RSA_EXPORT cipher suite
         */
        if (_gnutls_session_is_export (session) != 0 &&
                _gnutls_peers_cert_less_512 (session) != 0)
        {
            gnutls_assert ();
            return 0;
        }

        /* Server key exchange packet is optional for PSK. */
        if (_gnutls_session_is_psk (session))
            optflag = OPTIONAL_PACKET;

        ret =
            _gnutls_recv_handshake (session, &data,
                                    &datasize,
                                    GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE,
                                    optflag);
        if (ret < 0)
        {
            gnutls_assert ();
            return ret;
        }

        ret =
            session->internals.auth_struct->gnutls_process_server_kx (session,
                    data,
                    datasize);
        gnutls_free (data);

        if (ret < 0)
        {
            gnutls_assert ();
            return ret;
        }

    }
    return ret;
}
Пример #8
0
int
_gnutls_recv_server_kx_message (gnutls_session_t session)
{
  gnutls_buffer_st buf;
  int ret = 0;
  optional_t optflag = MANDATORY_PACKET;

  if (session->internals.auth_struct->gnutls_process_server_kx != NULL)
    {

      /* EXCEPTION FOR RSA_EXPORT cipher suite 
       */
      if (_gnutls_session_is_export (session) != 0 &&
          _gnutls_peers_cert_less_512 (session) != 0)
        {
          gnutls_assert ();
          return 0;
        }

      /* Server key exchange packet is optional for PSK. */
      if (_gnutls_session_is_psk (session))
        optflag = OPTIONAL_PACKET;

      ret =
        _gnutls_recv_handshake (session, 
                                GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE,
                                optflag, &buf);
      if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }

      ret =
        session->internals.auth_struct->gnutls_process_server_kx (session,
                                                                  buf.data,
                                                                  buf.length);
      _gnutls_buffer_clear(&buf);

      if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }

    }
  return ret;
}
Пример #9
0
/* Recv the client certificate verify. This packet may not
 * arrive if the peer did not send us a certificate.
 */
int
_gnutls_recv_client_certificate_verify_message (gnutls_session_t session)
{
    uint8_t *data;
    int datasize;
    int ret = 0;


    if (session->internals.auth_struct->gnutls_process_client_cert_vrfy != NULL)
    {

        if (session->internals.send_cert_req == 0 ||
                session->key->certificate_requested == 0)
        {
            return 0;
        }

        ret =
            _gnutls_recv_handshake (session, &data,
                                    &datasize,
                                    GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY,
                                    OPTIONAL_PACKET);
        if (ret < 0)
            return ret;

        if (ret == 0 && datasize == 0
                && session->internals.send_cert_req == GNUTLS_CERT_REQUIRE)
        {
            /* certificate was required */
            gnutls_assert ();
            return GNUTLS_E_NO_CERTIFICATE_FOUND;
        }

        ret =
            session->internals.
            auth_struct->gnutls_process_client_cert_vrfy (session, data,
                    datasize);
        gnutls_free (data);
        if (ret < 0)
            return ret;

    }

    return ret;
}
Пример #10
0
/* Recv the client certificate verify. This packet may not
 * arrive if the peer did not send us a certificate.
 */
int
_gnutls_recv_client_certificate_verify_message (gnutls_session_t session)
{
  gnutls_buffer_st buf;
  int ret = 0;


  if (session->internals.auth_struct->gnutls_process_client_cert_vrfy == NULL)
    return 0;

  if (session->internals.send_cert_req == 0 ||
      session->key->certificate_requested == 0)
    {
      return 0;
    }

  ret =
    _gnutls_recv_handshake (session, 
                            GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY,
                            OPTIONAL_PACKET, &buf);
  if (ret < 0)
    return ret;

  if (ret == 0 && buf.length == 0
      && session->internals.send_cert_req == GNUTLS_CERT_REQUIRE)
    {
      /* certificate was required */
      gnutls_assert ();
      ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
      goto cleanup;
    }

  ret =
    session->internals.
    auth_struct->gnutls_process_client_cert_vrfy (session, buf.data,
                                                  buf.length);

cleanup:
  _gnutls_buffer_clear(&buf);
  return ret;
}
Пример #11
0
int
_gnutls_recv_server_certificate (gnutls_session_t session)
{
    int datasize;
    opaque *data;
    int ret = 0;

    if (session->internals.auth_struct->gnutls_process_server_certificate !=
            NULL)
    {

        ret =
            _gnutls_recv_handshake (session, &data,
                                    &datasize,
                                    GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
                                    MANDATORY_PACKET);
        if (ret < 0)
        {
            gnutls_assert ();
            return ret;
        }

        ret =
            session->internals.
            auth_struct->gnutls_process_server_certificate (session, data,
                    datasize);
        gnutls_free (data);
        if (ret < 0)
        {
            gnutls_assert ();
            return ret;
        }
    }

    return ret;
}
Пример #12
0
int _gnutls_recv_new_session_ticket(gnutls_session_t session)
{
    uint8_t *p;
    int data_size;
    gnutls_buffer_st buf;
    uint16_t ticket_len;
    int ret;
    session_ticket_ext_st *priv = NULL;
    extension_priv_data_t epriv;

    ret =
        _gnutls_ext_get_session_data(session,
                                     GNUTLS_EXTENSION_SESSION_TICKET,
                                     &epriv);
    if (ret < 0) {
        gnutls_assert();
        return 0;
    }
    priv = epriv;

    if (!priv->session_ticket_renew)
        return 0;

    /* This is the last flight and peer cannot be sure
     * we have received it unless we notify him. So we
     * wait for a message and retransmit if needed. */
    if (IS_DTLS(session) && !_dtls_is_async(session) &&
            (gnutls_record_check_pending(session) +
             record_check_unprocessed(session)) == 0) {
        ret = _dtls_wait_and_retransmit(session);
        if (ret < 0)
            return gnutls_assert_val(ret);
    }

    ret = _gnutls_recv_handshake(session,
                                 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
                                 0, &buf);
    if (ret < 0)
        return gnutls_assert_val_fatal(ret);

    p = buf.data;
    data_size = buf.length;

    DECR_LENGTH_COM(data_size, 4, ret =
                        GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
                    goto error);
    /* skip over lifetime hint */
    p += 4;

    DECR_LENGTH_COM(data_size, 2, ret =
                        GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
                    goto error);
    ticket_len = _gnutls_read_uint16(p);
    p += 2;

    DECR_LENGTH_COM(data_size, ticket_len, ret =
                        GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
                    goto error);
    priv->session_ticket =
        gnutls_realloc_fast(priv->session_ticket, ticket_len);
    if (!priv->session_ticket) {
        gnutls_assert();
        ret = GNUTLS_E_MEMORY_ERROR;
        goto error;
    }
    memcpy(priv->session_ticket, p, ticket_len);
    priv->session_ticket_len = ticket_len;

    /* Discard the current session ID.  (RFC5077 3.4) */
    ret =
        _gnutls_generate_session_id(session->security_parameters.
                                    session_id,
                                    &session->security_parameters.
                                    session_id_size);
    if (ret < 0) {
        gnutls_assert();
        gnutls_free(priv->session_ticket);
        priv->session_ticket = NULL;
        ret = GNUTLS_E_INTERNAL_ERROR;
        goto error;
    }
    ret = 0;

error:
    _gnutls_buffer_clear(&buf);

    return ret;
}
Пример #13
0
int
_gnutls_recv_client_certificate (gnutls_session_t session)
{
    int datasize;
    opaque *data;
    int ret = 0;
    int optional;

    if (session->internals.auth_struct->gnutls_process_client_certificate !=
            NULL)
    {

        /* if we have not requested a certificate then just return
         */
        if (session->internals.send_cert_req == 0)
        {
            return 0;
        }

        if (session->internals.send_cert_req == GNUTLS_CERT_REQUIRE)
            optional = MANDATORY_PACKET;
        else
            optional = OPTIONAL_PACKET;

        ret =
            _gnutls_recv_handshake (session, &data,
                                    &datasize,
                                    GNUTLS_HANDSHAKE_CERTIFICATE_PKT, optional);

        if (ret < 0)
        {
            /* Handle the case of old SSL3 clients who send
             * a warning alert instead of an empty certificate to indicate
             * no certificate.
             */
            if (optional == OPTIONAL_PACKET &&
                    ret == GNUTLS_E_WARNING_ALERT_RECEIVED &&
                    gnutls_protocol_get_version (session) == GNUTLS_SSL3 &&
                    gnutls_alert_get (session) == GNUTLS_A_SSL3_NO_CERTIFICATE)
            {

                /* SSL3 does not send an empty certificate,
                 * but this alert. So we just ignore it.
                 */
                gnutls_assert ();
                return 0;
            }

            /* certificate was required
             */
            if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED
                    || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
                    && optional == MANDATORY_PACKET)
            {
                gnutls_assert ();
                return GNUTLS_E_NO_CERTIFICATE_FOUND;
            }

            return ret;
        }

        if (ret == 0 && datasize == 0 && optional == OPTIONAL_PACKET)
        {
            /* Client has not sent the certificate message.
             * well I'm not sure we should accept this
             * behaviour.
             */
            gnutls_assert ();
            return 0;
        }
        ret =
            session->internals.
            auth_struct->gnutls_process_client_certificate (session, data,
                    datasize);

        gnutls_free (data);
        if (ret < 0 && ret != GNUTLS_E_NO_CERTIFICATE_FOUND)
        {
            gnutls_assert ();
            return ret;
        }

        /* ok we should expect a certificate verify message now
         */
        if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND && optional == OPTIONAL_PACKET)
            ret = 0;
        else
            session->key->certificate_requested = 1;

    }

    return ret;
}
Пример #14
0
int _gnutls_recv_server_certificate_status(gnutls_session_t session)
{
	uint8_t *data;
	int data_size;
	size_t r_size;
	gnutls_buffer_st buf;
	int ret;
	status_request_ext_st *priv = NULL;
	extension_priv_data_t epriv;

	ret =
	    _gnutls_ext_get_session_data(session,
					 GNUTLS_EXTENSION_STATUS_REQUEST,
					 &epriv);
	if (ret < 0)
		return 0;

	priv = epriv.ptr;

	if (!priv->expect_cstatus)
		return 0;

	ret = _gnutls_recv_handshake(session,
				     GNUTLS_HANDSHAKE_CERTIFICATE_STATUS,
				     0, &buf);
	if (ret < 0)
		return gnutls_assert_val_fatal(ret);

	priv->expect_cstatus = 0;

	data = buf.data;
	data_size = buf.length;

	/* minimum message is type (1) + response (3) + data */
	if (data_size == 0)
		return 0;
	else if (data_size < 4)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	if (data[0] != 0x01) {
		gnutls_assert();
		_gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
				      session, data[0]);
		return 0;
	}
	DECR_LENGTH_COM(data_size, 1, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);
	data++;

	DECR_LENGTH_COM(data_size, 3, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);
	r_size = _gnutls_read_uint24(data);
	data += 3;

	DECR_LENGTH_COM(data_size, r_size, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);

	ret = _gnutls_set_datum(&priv->response, data, r_size);
	if (ret < 0)
		goto error;

	ret = 0;

      error:
	_gnutls_buffer_clear(&buf);

	return ret;
}
Пример #15
0
int _gnutls_recv_client_certificate(gnutls_session_t session)
{
	gnutls_buffer_st buf;
	int ret = 0;
	int optional;

	if (session->internals.auth_struct->
	    gnutls_process_client_certificate == NULL)
		return 0;

	/* if we have not requested a certificate then just return
	 */
	if (session->internals.send_cert_req == 0) {
		return 0;
	}

	if (session->internals.send_cert_req == GNUTLS_CERT_REQUIRE)
		optional = 0;
	else
		optional = 1;

	ret =
	    _gnutls_recv_handshake(session,
				   GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
				   optional, &buf);

	if (ret < 0) {
		/* Handle the case of old SSL3 clients who send
		 * a warning alert instead of an empty certificate to indicate
		 * no certificate.
		 */
#ifdef ENABLE_SSL3
		if (optional != 0 &&
		    ret == GNUTLS_E_WARNING_ALERT_RECEIVED &&
		    get_num_version(session) == GNUTLS_SSL3 &&
		    gnutls_alert_get(session) ==
		    GNUTLS_A_SSL3_NO_CERTIFICATE) {

			/* SSL3 does not send an empty certificate,
			 * but this alert. So we just ignore it.
			 */
			gnutls_assert();
			return 0;
		}
#endif

		/* certificate was required 
		 */
		if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED
		     || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
		    && optional == 0) {
			gnutls_assert();
			return GNUTLS_E_NO_CERTIFICATE_FOUND;
		}

		return ret;
	}

	if (ret == 0 && buf.length == 0 && optional != 0) {
		/* Client has not sent the certificate message.
		 * well I'm not sure we should accept this
		 * behaviour.
		 */
		gnutls_assert();
		ret = 0;
		goto cleanup;
	}
	ret =
	    session->internals.auth_struct->
	    gnutls_process_client_certificate(session, buf.data,
					      buf.length);

	if (ret < 0 && ret != GNUTLS_E_NO_CERTIFICATE_FOUND) {
		gnutls_assert();
		goto cleanup;
	}

	/* ok we should expect a certificate verify message now 
	 */
	if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND && optional != 0)
		ret = 0;
	else
		session->internals.crt_requested = 1;

      cleanup:
	_gnutls_buffer_clear(&buf);
	return ret;
}
Пример #16
0
/*
 * Return zero if session tickets haven't been enabled.
 */
int _gnutls_recv_new_session_ticket(gnutls_session_t session)
{
	uint8_t *p;
	int data_size;
	gnutls_buffer_st buf;
	uint16_t ticket_len;
	int ret;
	session_ticket_ext_st *priv = NULL;
	gnutls_ext_priv_data_t epriv;

	if (session->internals.flags & GNUTLS_NO_TICKETS)
		return 0;
	if (!session->internals.session_ticket_renew)
		return 0;

	/* This is the last flight and peer cannot be sure
	 * we have received it unless we notify him. So we
	 * wait for a message and retransmit if needed. */
	if (IS_DTLS(session) && !_dtls_is_async(session)) {
		unsigned have;
		mbuffer_st *bufel = NULL;

		have = gnutls_record_check_pending(session) +
		       record_check_unprocessed(session);

		if (have != 0) {
			bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL);
		}

		if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) {
			ret = _dtls_wait_and_retransmit(session);
			if (ret < 0)
				return gnutls_assert_val(ret);
		}
	}

	ret = _gnutls_recv_handshake(session,
				     GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
				     0, &buf);
	if (ret < 0)
		return gnutls_assert_val_fatal(ret);

	p = buf.data;
	data_size = buf.length;

	DECR_LENGTH_COM(data_size, 4, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);
	/* skip over lifetime hint */
	p += 4;

	DECR_LENGTH_COM(data_size, 2, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);
	ticket_len = _gnutls_read_uint16(p);
	p += 2;

	DECR_LENGTH_COM(data_size, ticket_len, ret =
			GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
			goto error);

	priv = gnutls_calloc(1, sizeof(*priv));
	if (!priv) {
		gnutls_assert();
		ret = GNUTLS_E_MEMORY_ERROR;
		goto error;
	}
	priv->session_ticket =
	    gnutls_realloc_fast(priv->session_ticket, ticket_len);
	if (!priv->session_ticket) {
		gnutls_free(priv);
		gnutls_assert();
		ret = GNUTLS_E_MEMORY_ERROR;
		goto error;
	}
	memcpy(priv->session_ticket, p, ticket_len);
	priv->session_ticket_len = ticket_len;
	epriv = priv;

	/* Discard the current session ID.  (RFC5077 3.4) */
	ret =
	    _gnutls_generate_session_id(session->security_parameters.
					session_id,
					&session->security_parameters.
					session_id_size);
	if (ret < 0) {
		gnutls_assert();
		session_ticket_deinit_data(epriv);
		ret = GNUTLS_E_INTERNAL_ERROR;
		goto error;
	}
	ret = 0;

	_gnutls_handshake_log
		    ("HSK[%p]: received session ticket\n", session);
	session->internals.hsk_flags |= HSK_TICKET_RECEIVED;

	_gnutls_hello_ext_set_priv(session,
			GNUTLS_EXTENSION_SESSION_TICKET,
			epriv);

      error:
	_gnutls_buffer_clear(&buf);

	return ret;
}
Пример #17
0
int _gnutls13_recv_certificate(gnutls_session_t session)
{
	int ret;
	gnutls_buffer_st buf;
	unsigned optional = 0;

	if (!session->internals.initial_negotiation_completed &&
	    session->internals.hsk_flags & HSK_PSK_SELECTED)
		return 0;

	if (session->security_parameters.entity == GNUTLS_SERVER) {
		/* if we didn't request a certificate, there will not be any */
		if (session->internals.send_cert_req == 0)
			return 0;

		if (session->internals.send_cert_req != GNUTLS_CERT_REQUIRE)
			optional = 1;
	}

	ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, 0, &buf);
	if (ret < 0) {
		if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET && session->internals.send_cert_req)
			return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);

		return gnutls_assert_val(ret);
	}

	if (buf.length == 0) {
		gnutls_assert();
		ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
		goto cleanup;
	}

	if (session->internals.initial_negotiation_completed &&
	    session->internals.post_handshake_cr_context.size > 0) {
		gnutls_datum_t context;

		/* verify whether the context matches */
		ret = _gnutls_buffer_pop_datum_prefix8(&buf, &context);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		if (context.size != session->internals.post_handshake_cr_context.size ||
		    memcmp(context.data, session->internals.post_handshake_cr_context.data,
		           context.size) != 0) {
			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
			gnutls_assert();
			goto cleanup;
		}
	} else {
		if (buf.data[0] != 0) {
			/* The context field must be empty during handshake */
			gnutls_assert();
			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
			goto cleanup;
		}

		/* buf.length is positive */
		buf.data++;
		buf.length--;
	}

	_gnutls_handshake_log("HSK[%p]: parsing certificate message\n", session);

	ret = parse_cert_list(session, buf.data, buf.length);
	if (ret < 0) {
		if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
			if (optional)
				ret = 0;
			else if (session->security_parameters.entity ==
				 GNUTLS_SERVER)
				ret = GNUTLS_E_CERTIFICATE_REQUIRED;
		}
		gnutls_assert();
		goto cleanup;
	}

	session->internals.hsk_flags |= HSK_CRT_VRFY_EXPECTED;

	ret = 0;
cleanup:

	_gnutls_buffer_clear(&buf);
	return ret;
}