Beispiel #1
0
/* Waits for the last flight or retransmits
 * the previous on timeout. Returns 0 on success.
 */
int _dtls_wait_and_retransmit(gnutls_session_t session)
{
int ret;

  if (session->internals.dtls.blocking != 0)
    ret = _gnutls_io_check_recv(session, TIMER_WINDOW);
  else
    ret = _gnutls_io_check_recv(session, 0);

  if (ret == GNUTLS_E_TIMEDOUT)
    {
      ret = _dtls_retransmit(session);
      if (ret == 0)
        {
          RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
        }
      else
        return gnutls_assert_val(ret);
    }

  RESET_TIMER;
  return 0;
}
Beispiel #2
0
static int wrap_nettle_rnd_init(void **_ctx)
{
	int ret;
	uint8_t new_key[PRNG_KEY_SIZE*2];
	struct generators_ctx_st *ctx;

	ctx = calloc(1, sizeof(*ctx));
	if (ctx == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	/* initialize the nonce RNG */
	ret = _rnd_get_system_entropy(new_key, sizeof(new_key));
	if (ret < 0) {
		gnutls_assert();
		goto fail;
	}

	ret = single_prng_init(&ctx->nonce, new_key, PRNG_KEY_SIZE, 1);
	if (ret < 0) {
		gnutls_assert();
		goto fail;
	}

	/* initialize the random/key RNG */
	ret = single_prng_init(&ctx->normal, new_key+PRNG_KEY_SIZE, PRNG_KEY_SIZE, 1);
	if (ret < 0) {
		gnutls_assert();
		goto fail;
	}

	*_ctx = ctx;

	return 0;
 fail:
	gnutls_free(ctx);
	return ret;
}
Beispiel #3
0
int _gnutls13_send_key_update(gnutls_session_t session, unsigned again, unsigned flags /* GNUTLS_KU_* */)
{
	int ret;
	mbuffer_st *bufel = NULL;
	uint8_t val;

	if (again == 0) {
		if (flags & GNUTLS_KU_PEER) {
			/* mark that we asked a key update to prevent an
			 * infinite ping pong when receiving the reply */
			session->internals.hsk_flags |= HSK_KEY_UPDATE_ASKED;
			val = 0x01;
		} else {
			val = 0x00;
		}

		_gnutls_handshake_log("HSK[%p]: sending key update (%u)\n", session, (unsigned)val);

		bufel = _gnutls_handshake_alloc(session, 1);
		if (bufel == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		_mbuffer_set_udata_size(bufel, 0);
		ret = _mbuffer_append_data(bufel, &val, 1);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

	}

	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_KEY_UPDATE);

cleanup:
	_mbuffer_xfree(&bufel);
	return ret;
}
Beispiel #4
0
int _gnutls_proc_ecdh_common_client_kx(gnutls_session_t session,
				       uint8_t * data, size_t _data_size,
				       gnutls_ecc_curve_t curve,
				       gnutls_datum_t * psk_key)
{
	ssize_t data_size = _data_size;
	int ret, i = 0;
	int point_size;

	if (curve == GNUTLS_ECC_CURVE_INVALID)
		return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);

	DECR_LEN(data_size, 1);
	point_size = data[i];
	i += 1;

	DECR_LEN(data_size, point_size);
	ret =
	    _gnutls_ecc_ansi_x963_import(&data[i], point_size,
					 &session->key.ecdh_x,
					 &session->key.ecdh_y);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	/* generate pre-shared key */
	ret = calc_ecdh_key(session, psk_key, curve);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

cleanup:
      	gnutls_pk_params_clear(&session->key.ecdh_params);
	return ret;
}
Beispiel #5
0
/* @total: The sum of the data in giovec
 */
static ssize_t
_gnutls_writev(gnutls_session_t session, const giovec_t * giovec,
	       unsigned giovec_cnt, unsigned total)
{
	int i;
	bool is_dtls = IS_DTLS(session);
	unsigned no_writev = 0;
	gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;

	reset_errno(session);

	if (session->internals.vec_push_func != NULL) {
		if (is_dtls && giovec_cnt > 1) {
			if (total > session->internals.dtls.mtu) {
				no_writev = 1;
			}
		}

		if (no_writev == 0) {
			i = session->internals.vec_push_func(fd, giovec, giovec_cnt);
		} else {
			i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 1);
		}
	} else if (session->internals.push_func != NULL) {
		i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 0);
	} else
		return gnutls_assert_val(GNUTLS_E_PUSH_ERROR);

	if (i == -1) {
		int err = get_errno(session);
		_gnutls_debug_log("WRITE: %d returned from %p, errno: %d\n",
				  i, fd, err);

		return errno_to_gerr(err, is_dtls);
	}
	return i;
}
Beispiel #6
0
/*
 * Russian differs from PKCS#12 here. It described proprietary way
 * to obtain MAC key instead of using standard mechanism.
 *
 * See https://wwwold.tc26.ru/standard/rs/%D0%A0%2050.1.112-2016.pdf
 * section 5.
 */
static int
_gnutls_pkcs12_gost_string_to_key(gnutls_mac_algorithm_t algo,
				  const uint8_t * salt,
				  unsigned int salt_size, unsigned int iter,
				  const char *pass, unsigned int req_keylen,
				  uint8_t * keybuf)
{
	uint8_t temp[96];
	size_t temp_len = sizeof(temp);
	unsigned int pass_len = 0;

	if (pass)
		pass_len = strlen(pass);

	if (algo == GNUTLS_MAC_GOSTR_94)
		pbkdf2_hmac_gosthash94cp(pass_len, (uint8_t *) pass,
				iter,
				salt_size,
				salt, temp_len, temp);
	else if (algo == GNUTLS_MAC_STREEBOG_256)
		pbkdf2_hmac_streebog256(pass_len, (uint8_t *) pass,
				iter,
				salt_size,
				salt, temp_len, temp);
	else if (algo == GNUTLS_MAC_STREEBOG_512)
		pbkdf2_hmac_streebog512(pass_len, (uint8_t *) pass,
				iter,
				salt_size,
				salt, temp_len, temp);
	else
		/* Should not reach here */
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	memcpy(keybuf, temp + temp_len - req_keylen, req_keylen);

	return 0;
}
Beispiel #7
0
/**
 * gnutls_privkey_decrypt_data:
 * @key: Holds the key
 * @flags: zero for now
 * @ciphertext: holds the data to be decrypted
 * @plaintext: will contain the decrypted data, allocated with gnutls_malloc()
 *
 * This function will decrypt the given data using the algorithm
 * supported by the private key.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 * negative error value.
 *
 * Since: 2.12.0
 **/
int
gnutls_privkey_decrypt_data(gnutls_privkey_t key,
			    unsigned int flags,
			    const gnutls_datum_t * ciphertext,
			    gnutls_datum_t * plaintext)
{
	switch (key->type) {
#ifdef ENABLE_OPENPGP
	case GNUTLS_PRIVKEY_OPENPGP:
		return _gnutls_openpgp_privkey_decrypt_data(key->key.
							    openpgp, flags,
							    ciphertext,
							    plaintext);
#endif
	case GNUTLS_PRIVKEY_X509:
		return _gnutls_pk_decrypt(key->pk_algorithm, plaintext,
					  ciphertext,
					  &key->key.x509->params);
#ifdef ENABLE_PKCS11
	case GNUTLS_PRIVKEY_PKCS11:
		return _gnutls_pkcs11_privkey_decrypt_data(key->key.pkcs11,
							   flags,
							   ciphertext,
							   plaintext);
#endif
	case GNUTLS_PRIVKEY_EXT:
		if (key->key.ext.decrypt_func == NULL)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		return key->key.ext.decrypt_func(key,
						 key->key.ext.userdata,
						 ciphertext, plaintext);
	default:
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}
}
Beispiel #8
0
/**
 * gnutls_privkey_import_x509_raw:
 * @pkey: The private key
 * @data: The private key data to be imported
 * @format: The format of the private key
 * @password: A password (optional)
 * @flags: an ORed sequence of gnutls_pkcs_encrypt_flags_t
 *
 * This function will import the given private key to the abstract
 * #gnutls_privkey_t structure. 
 *
 * The supported formats are basic unencrypted key, PKCS8, PKCS12, 
 * and the openssl format.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.1.0
 **/
int gnutls_privkey_import_x509_raw(gnutls_privkey_t pkey,
				   const gnutls_datum_t * data,
				   gnutls_x509_crt_fmt_t format,
				   const char *password,
				   unsigned int flags)
{
	gnutls_x509_privkey_t xpriv;
	int ret;

	ret = gnutls_x509_privkey_init(&xpriv);
	if (ret < 0)
		return gnutls_assert_val(ret);

	ret =
	    gnutls_x509_privkey_import2(xpriv, data, format, password,
					flags);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret =
	    gnutls_privkey_import_x509(pkey, xpriv,
				       GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	return 0;

      cleanup:
	gnutls_x509_privkey_deinit(xpriv);

	return ret;
}
Beispiel #9
0
static int randomize_uuid(TSS_UUID * uuid)
{
	uint8_t raw_uuid[16];
	int ret;

	ret = _gnutls_rnd(GNUTLS_RND_NONCE, raw_uuid, sizeof(raw_uuid));
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* mark it as random uuid */
	raw_uuid[6] &= 0x0f;
	raw_uuid[6] |= 0x40;
	raw_uuid[8] &= 0x0f;
	raw_uuid[8] |= 0x80;

	memcpy(&uuid->ulTimeLow, raw_uuid, 4);
	memcpy(&uuid->usTimeMid, &raw_uuid[4], 2);
	memcpy(&uuid->usTimeHigh, &raw_uuid[6], 2);
	uuid->bClockSeqHigh = raw_uuid[8];
	uuid->bClockSeqLow = raw_uuid[9];
	memcpy(&uuid->rgbNode, &raw_uuid[10], 6);

	return 0;
}
Beispiel #10
0
/**
 * gnutls_pkcs12_bag_set_privkey:
 * @bag: The bag
 * @privkey: the private key to be copied.
 * @password: the password to protect the key with (may be %NULL)
 * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd
 *
 * This function will insert the given private key into the
 * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data().
 *
 * Returns: the index of the added bag on success, or a negative
 * value on failure.
 **/
int
gnutls_pkcs12_bag_set_privkey(gnutls_pkcs12_bag_t bag, gnutls_x509_privkey_t privkey,
			      const char *password, unsigned flags)
{
	int ret;
	gnutls_datum_t data = {NULL, 0};

	if (bag == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ret = gnutls_x509_privkey_export2_pkcs8(privkey, GNUTLS_X509_FMT_DER,
						password, flags, &data);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (password == NULL) {
		ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_KEY, &data);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	} else {
		ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, &data);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

 cleanup:
	_gnutls_free_datum(&data);

	return ret;
}
Beispiel #11
0
int
_gnutls_encode_ber_rs(gnutls_datum_t * sig_value, bigint_t r, bigint_t s)
{
	ASN1_TYPE sig;
	int result;

	if ((result =
	     asn1_create_element(_gnutls_get_gnutls_asn(),
				 "GNUTLS.DSASignatureValue",
				 &sig)) != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = _gnutls_x509_write_int(sig, "r", r, 1);
	if (result < 0) {
		gnutls_assert();
		asn1_delete_structure(&sig);
		return result;
	}

	result = _gnutls_x509_write_int(sig, "s", s, 1);
	if (result < 0) {
		gnutls_assert();
		asn1_delete_structure(&sig);
		return result;
	}

	result = _gnutls_x509_der_encode(sig, "", sig_value, 0);
	asn1_delete_structure(&sig);

	if (result < 0)
		return gnutls_assert_val(result);

	return 0;
}
Beispiel #12
0
/* Checks if the extra_certs contain certificates that may form a chain
 * with the first certificate in chain (it is expected that chain_len==1)
 * and appends those in the chain.
 */
static int make_chain(gnutls_x509_crt_t **chain, unsigned int *chain_len,
                      gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len)
{
unsigned int i;

  if (*chain_len != 1)
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
  
  i = 0;
  while(i<*extra_certs_len)
    {
      /* if it is an issuer but not a self-signed one */
      if (gnutls_x509_crt_check_issuer((*chain)[*chain_len - 1], (*extra_certs)[i]) != 0 &&
          gnutls_x509_crt_check_issuer((*extra_certs)[i], (*extra_certs)[i]) == 0)
        {
           void *tmp = *chain;
           *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) *
                                                     ++(*chain_len));
           if (*chain == NULL)
             {
               gnutls_assert();
               gnutls_free(tmp);
               return GNUTLS_E_MEMORY_ERROR;
             }
           (*chain)[*chain_len - 1] = (*extra_certs)[i];
           
           (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1];
           (*extra_certs_len)--;

           i=0;
           continue;
        }
      i++;
    }
  return 0;
}
Beispiel #13
0
static int
gen_ecdhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
{
	int ret;

	if ((ret =
	     _gnutls_auth_info_set(session, GNUTLS_CRD_PSK,
				   sizeof(psk_auth_info_st), 1)) < 0) {
		gnutls_assert();
		return ret;
	}

	ret = _gnutls_buffer_append_prefix(data, 16, 0);
	if (ret < 0)
		return gnutls_assert_val(ret);

	ret = _gnutls_ecdh_common_print_server_kx(session, data,
						  _gnutls_session_ecc_curve_get
						  (session));
	if (ret < 0)
		gnutls_assert();

	return ret;
}
Beispiel #14
0
/**
 * gnutls_privkey_import_rsa_raw:
 * @key: The structure to store the parsed key
 * @m: holds the modulus
 * @e: holds the public exponent
 * @d: holds the private exponent
 * @p: holds the first prime (p)
 * @q: holds the second prime (q)
 * @u: holds the coefficient (optional)
 * @e1: holds e1 = d mod (p-1) (optional)
 * @e2: holds e2 = d mod (q-1) (optional)
 *
 * This function will convert the given RSA raw parameters to the
 * native #gnutls_privkey_t format.  The output will be stored in
 * @key.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_privkey_import_rsa_raw(gnutls_privkey_t key,
				    const gnutls_datum_t * m,
				    const gnutls_datum_t * e,
				    const gnutls_datum_t * d,
				    const gnutls_datum_t * p,
				    const gnutls_datum_t * q,
				    const gnutls_datum_t * u,
				    const gnutls_datum_t * e1,
				    const gnutls_datum_t * e2)
{
int ret;
gnutls_x509_privkey_t xkey;

	ret = gnutls_x509_privkey_init(&xkey);
	if (ret < 0)
		return gnutls_assert_val(ret);

	ret = gnutls_x509_privkey_import_rsa_raw2(xkey, m, e, d, p, q, u, e1, e1);
	if (ret < 0) {
		gnutls_assert();
		goto error;
	}
	
	ret = gnutls_privkey_import_x509(key, xkey, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
	if (ret < 0) {
		gnutls_assert();
		goto error;
	}
	
	return 0;

error:
	gnutls_x509_privkey_deinit(xkey);
	return ret;
}
Beispiel #15
0
/**
 * gnutls_session_ticket_key_generate:
 * @key: is a pointer to a #gnutls_datum_t which will contain a newly
 * created key.
 *
 * Generate a random key to encrypt security parameters within
 * SessionTicket.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
 * error code.
 *
 * Since: 2.10.0
 **/
int gnutls_session_ticket_key_generate(gnutls_datum_t * key)
{
	if (_gnutls_fips_mode_enabled()) {
		int ret;
		/* in FIPS140-2 mode gnutls_key_generate imposes
		 * some limits on allowed key size, thus it is not
		 * used. These limits do not affect this function as
		 * it does not generate a "key" but rather key material
		 * that includes nonces and other stuff. */
		key->data = gnutls_malloc(TICKET_MASTER_KEY_SIZE);
		if (key->data == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		key->size = TICKET_MASTER_KEY_SIZE;
		ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
		if (ret < 0) {
			gnutls_free(key->data);
			return ret;
		}
		return 0;
	} else {
		return gnutls_key_generate(key, TICKET_MASTER_KEY_SIZE);
	}
}
Beispiel #16
0
static
int capi_decrypt(gnutls_privkey_t key, void *userdata,
		 const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext)
{
	priv_st *priv = (priv_st *) userdata;
	DWORD size = 0;
	int ret;

	plaintext->data = NULL;
	plaintext->size = 0;

	if (priv->pk != GNUTLS_PK_RSA) {
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
	}

	plaintext->size = size = ciphertext->size;
	plaintext->data = (unsigned char *)gnutls_malloc(plaintext->size);
	if (plaintext->data == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	memcpy(plaintext->data, ciphertext->data, size);
	if (0 ==
	    CryptDecrypt(priv->hCryptProv, 0, true, 0, plaintext->data,
			 &size)) {
		gnutls_assert();
		ret = GNUTLS_E_PK_DECRYPTION_FAILED;
		goto fail;
	}

	return 0;
 fail:
	gnutls_free(plaintext->data);
	return ret;
}
Beispiel #17
0
/* Check if the given signature algorithm is supported.
 * This means that it is enabled by the priority functions,
 * and in case of a server a matching certificate exists.
 */
int
_gnutls_session_sign_algo_enabled(gnutls_session_t session,
				  gnutls_sign_algorithm_t sig)
{
	unsigned i;
	const version_entry_st *ver = get_version(session);

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if (!_gnutls_version_has_selectable_sighash(ver)) {
		return 0;
	}

	for (i = 0; i < session->internals.priorities.sign_algo.algorithms;
	     i++) {
		if (session->internals.priorities.sign_algo.priority[i] ==
		    sig) {
			return 0;	/* ok */
		}
	}

	return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
}
Beispiel #18
0
/* returns data_size or a negative number on failure
 */
static int
_gnutls_ext_master_secret_send_params(gnutls_session_t session,
			       gnutls_buffer_st * extdata)
{
	if ((session->internals.flags & GNUTLS_NO_EXTENSIONS) ||
	    session->internals.priorities->no_extensions != 0 ||
	    session->internals.no_ext_master_secret != 0) {
	    session->security_parameters.ext_master_secret = 0;
	    return 0;
	}

	/* this function sends the client extension data */
#ifdef ENABLE_SSL3
	if (session->security_parameters.entity == GNUTLS_CLIENT) {
		if (have_only_ssl3_enabled(session))
		    return 0; /* this extension isn't available for SSL 3.0 */

		return GNUTLS_E_INT_RET_0;
	} else { /* server side */
		const version_entry_st *ver = get_version(session);
		if (unlikely(ver == NULL))
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

		if (ver->id != GNUTLS_SSL3 && session->security_parameters.ext_master_secret != 0)
			return GNUTLS_E_INT_RET_0;
	}


	return 0;
#else
	if (session->security_parameters.entity == GNUTLS_CLIENT ||
	    session->security_parameters.ext_master_secret != 0)
		return GNUTLS_E_INT_RET_0;
	return 0;
#endif
}
Beispiel #19
0
int
_gnutls_epoch_set_cipher_suite(gnutls_session_t session,
			       int epoch_rel, const uint8_t suite[2])
{
	const cipher_entry_st *cipher_algo;
	const mac_entry_st *mac_algo;
	record_parameters_st *params;
	const gnutls_cipher_suite_entry_st *cs;
	int ret;

	ret = _gnutls_epoch_get(session, epoch_rel, &params);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (params->initialized
	    || params->cipher != NULL || params->mac != NULL)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	cs = ciphersuite_to_entry(suite);
	if (cs == NULL)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	cipher_algo = cipher_to_entry(cs->block_algorithm);
	mac_algo = mac_to_entry(cs->mac_algorithm);

	if (_gnutls_cipher_is_ok(cipher_algo) == 0
	    || _gnutls_mac_is_ok(mac_algo) == 0)
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);

	if (_gnutls_cipher_priority(session, cipher_algo->id) < 0)
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);

	if (_gnutls_mac_priority(session, mac_algo->id) < 0)
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);

	params->cipher = cipher_algo;
	params->mac = mac_algo;

	return 0;
}
Beispiel #20
0
/* If the psk flag is set, then an empty psk_identity_hint will
 * be inserted */
int _gnutls_ecdh_common_print_server_kx (gnutls_session_t session, gnutls_buffer_st* data,
                                         gnutls_ecc_curve_t curve)
{
  uint8_t p;
  int ret;
  gnutls_datum_t out;

  if (curve == GNUTLS_ECC_CURVE_INVALID)
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);

  /* curve type */
  p = 3;
  
  ret = _gnutls_buffer_append_data(data, &p, 1);
  if (ret < 0)
    return gnutls_assert_val(ret);

  ret = _gnutls_buffer_append_prefix(data, 16, _gnutls_ecc_curve_get_tls_id(curve));
  if (ret < 0)
    return gnutls_assert_val(ret);

  /* generate temporal key */
  ret = _gnutls_pk_generate(GNUTLS_PK_EC, curve, &session->key.ecdh_params);
  if (ret < 0)
    return gnutls_assert_val(ret);

  ret = _gnutls_ecc_ansi_x963_export(curve, session->key.ecdh_params.params[6] /* x */,
    session->key.ecdh_params.params[7] /* y */, &out);
  if (ret < 0)
    return gnutls_assert_val(ret);

  ret = _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size);
  
  _gnutls_free_datum(&out);
  
  if (ret < 0)
    return gnutls_assert_val(ret);
    
  return data->length;
}
Beispiel #21
0
/* will merge the given handshake_buffer_st to the handshake_recv_buffer
 * list. The given hsk packet will be released in any case (success or failure).
 * Only used in DTLS.
 */
static int merge_handshake_packet(gnutls_session_t session,
				  handshake_buffer_st * hsk)
{
	int exists = 0, i, pos = 0;
	int ret;

	for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
		if (session->internals.handshake_recv_buffer[i].htype ==
		    hsk->htype) {
			exists = 1;
			pos = i;
			break;
		}
	}

	if (!exists)
		pos = session->internals.handshake_recv_buffer_size;

	if (pos >= MAX_HANDSHAKE_MSGS)
		return
		    gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);

	if (!exists) {
		if (hsk->length > 0 && hsk->end_offset > 0
		    && hsk->end_offset - hsk->start_offset + 1 !=
		    hsk->length) {
			ret =
			    _gnutls_buffer_resize(&hsk->data, hsk->length);
			if (ret < 0)
				return gnutls_assert_val(ret);

			hsk->data.length = hsk->length;

			memmove(&hsk->data.data[hsk->start_offset],
				hsk->data.data,
				hsk->end_offset - hsk->start_offset + 1);
		}

		session->internals.handshake_recv_buffer_size++;

		/* rewrite headers to make them look as each packet came as a single fragment */
		_gnutls_write_uint24(hsk->length, &hsk->header[1]);
		_gnutls_write_uint24(0, &hsk->header[6]);
		_gnutls_write_uint24(hsk->length, &hsk->header[9]);

		_gnutls_handshake_buffer_move(&session->internals.
					      handshake_recv_buffer[pos],
					      hsk);

	} else {
		if (hsk->start_offset <
		    session->internals.handshake_recv_buffer[pos].
		    start_offset
		    && hsk->end_offset + 1 >=
		    session->internals.handshake_recv_buffer[pos].
		    start_offset) {
			memcpy(&session->internals.
			       handshake_recv_buffer[pos].data.data[hsk->
								    start_offset],
			       hsk->data.data, hsk->data.length);
			session->internals.handshake_recv_buffer[pos].
			    start_offset = hsk->start_offset;
			session->internals.handshake_recv_buffer[pos].
			    end_offset =
			    MIN(hsk->end_offset,
				session->internals.
				handshake_recv_buffer[pos].end_offset);
		} else if (hsk->end_offset >
			   session->internals.handshake_recv_buffer[pos].
			   end_offset
			   && hsk->start_offset <=
			   session->internals.handshake_recv_buffer[pos].
			   end_offset + 1) {
			memcpy(&session->internals.
			       handshake_recv_buffer[pos].data.data[hsk->
								    start_offset],
			       hsk->data.data, hsk->data.length);

			session->internals.handshake_recv_buffer[pos].
			    end_offset = hsk->end_offset;
			session->internals.handshake_recv_buffer[pos].
			    start_offset =
			    MIN(hsk->start_offset,
				session->internals.
				handshake_recv_buffer[pos].start_offset);
		}
		_gnutls_handshake_buffer_clear(hsk);
	}

	return 0;
}
Beispiel #22
0
static int
parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
		       handshake_buffer_st * hsk)
{
	uint8_t *dataptr = NULL;	/* for realloc */
	size_t handshake_header_size =
	    HANDSHAKE_HEADER_SIZE(session), data_size, frag_size;

	/* Note: SSL2_HEADERS == 1 */
	if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	dataptr = _mbuffer_get_udata_ptr(bufel);

	/* if reading a client hello of SSLv2 */
#ifdef ENABLE_SSL2
	if (unlikely
	    (!IS_DTLS(session)
	     && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
		handshake_header_size = SSL2_HEADERS;	/* we've already read one byte */

		frag_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;	/* we've read the first byte */

		if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
			return
			    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);

		hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;

		hsk->sequence = 0;
		hsk->start_offset = 0;
		hsk->length = frag_size;
	} else
#endif
	{	/* TLS or DTLS handshake headers */


		hsk->rtype = hsk->htype = dataptr[0];

		/* we do not use DECR_LEN because we know
		 * that the packet has enough data.
		 */
		hsk->length = _gnutls_read_uint24(&dataptr[1]);

		if (IS_DTLS(session)) {
			hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
			hsk->start_offset =
			    _gnutls_read_uint24(&dataptr[6]);
			frag_size =
			    _gnutls_read_uint24(&dataptr[9]);
		} else {
			hsk->sequence = 0;
			hsk->start_offset = 0;
			frag_size =
			    MIN((_mbuffer_get_udata_size(bufel) -
				 handshake_header_size), hsk->length);
		}

		/* TLS1.3: distinguish server hello versus hello retry request.
		 * The epitome of slick protocol design. */
		if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO && hsk->start_offset == 0 && !IS_DTLS(session)) {
			if (_mbuffer_get_udata_size(bufel) > handshake_header_size+2+GNUTLS_RANDOM_SIZE &&
			    memcmp(dataptr+handshake_header_size+2, HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) {
				hsk->htype = GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST;
			}
		}
	}
	data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;

	if (frag_size > 0)
		hsk->end_offset = hsk->start_offset + frag_size - 1;
	else
		hsk->end_offset = 0;

	_gnutls_handshake_log
	    ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
	     session, _gnutls_handshake2str(hsk->htype),
	     (unsigned) hsk->htype, (int) hsk->length, (int) data_size,
	     hsk->start_offset, (int) frag_size,
	     (int) hsk->sequence);

	hsk->header_size = handshake_header_size;
	memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
	       handshake_header_size);

	if (hsk->length > 0 && (frag_size > data_size ||
				(frag_size > 0 &&
				 hsk->end_offset >= hsk->length))) {
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
	}
	else if (hsk->length == 0 && hsk->end_offset != 0
		 && hsk->start_offset != 0)
		return
		    gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	return handshake_header_size;
}
Beispiel #23
0
/* This function writes the data that are left in the
 * TLS write buffer (ie. because the previous write was
 * interrupted.
 */
ssize_t _gnutls_io_write_flush(gnutls_session_t session)
{
	gnutls_datum_t msg;
	mbuffer_head_st *send_buffer =
	    &session->internals.record_send_buffer;
	int ret;
	ssize_t sent = 0, tosend = 0;
	giovec_t iovec[MAX_QUEUE];
	int i = 0;
	mbuffer_st *cur;

	session->internals.direction = 1;
	_gnutls_write_log("WRITE FLUSH: %d bytes in buffer.\n",
			  (int) send_buffer->byte_length);

	for (cur = _mbuffer_head_get_first(send_buffer, &msg);
	     cur != NULL; cur = _mbuffer_head_get_next(cur, &msg)) {
		iovec[i].iov_base = msg.data;
		iovec[i++].iov_len = msg.size;
		tosend += msg.size;

		/* we buffer up to MAX_QUEUE messages */
		if (i >= MAX_QUEUE) {
			gnutls_assert();
			return GNUTLS_E_INTERNAL_ERROR;
		}
	}

	if (tosend == 0) {
		gnutls_assert();
		return 0;
	}

	ret = _gnutls_writev(session, iovec, i, tosend);
	if (ret >= 0) {
		_mbuffer_head_remove_bytes(send_buffer, ret);
		_gnutls_write_log
		    ("WRITE: wrote %d bytes, %d bytes left.\n", ret,
		     (int) send_buffer->byte_length);

		sent += ret;
	} else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
		_gnutls_write_log("WRITE interrupted: %d bytes left.\n",
				  (int) send_buffer->byte_length);
		return ret;
	} else if (ret == GNUTLS_E_LARGE_PACKET) {
		_mbuffer_head_remove_bytes(send_buffer, tosend);
		_gnutls_write_log
		    ("WRITE cannot send large packet (%u bytes).\n",
		     (unsigned int) tosend);
		return ret;
	} else {
		_gnutls_write_log("WRITE error: code %d, %d bytes left.\n",
				  ret, (int) send_buffer->byte_length);

		gnutls_assert();
		return ret;
	}

	if (sent < tosend) {
		return gnutls_assert_val(GNUTLS_E_AGAIN);
	}

	return sent;
}
Beispiel #24
0
/* 
 * @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
 *
 * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
 * It does return gnutls_errno instead.
 * This function reads data from the socket and keeps them in a buffer, of up to
 * max_record_recv_size. 
 *
 * This is not a general purpose function. It returns EXACTLY the data requested,
 * which are stored in a local (in the session) buffer.
 *
 * If the @ms parameter is non zero then this function will return before
 * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
 *
 */
ssize_t
_gnutls_io_read_buffered(gnutls_session_t session, size_t total,
			 content_type_t recv_type, unsigned int *ms)
{
	ssize_t ret;
	size_t min;
	mbuffer_st *bufel = NULL;
	size_t recvdata, readsize;

	if (total > max_record_recv_size(session) || total == 0) {
		gnutls_assert();
		return GNUTLS_E_RECORD_OVERFLOW;
	}

	/* calculate the actual size, ie. get the minimum of the
	 * buffered data and the requested data.
	 */
	min =
	    MIN(session->internals.record_recv_buffer.byte_length, total);
	if (min > 0) {
		/* if we have enough buffered data
		 * then just return them.
		 */
		if (min == total) {
			return min;
		}
	}

	/* min is over zero. recvdata is the data we must
	 * receive in order to return the requested data.
	 */
	recvdata = total - min;
	readsize = recvdata;

	/* Check if the previously read data plus the new data to
	 * receive are longer than the maximum receive buffer size.
	 */
	if ((session->internals.record_recv_buffer.byte_length +
	     recvdata) > max_record_recv_size(session)) {
		gnutls_assert();	/* internal error */
		return GNUTLS_E_INVALID_REQUEST;
	}

	/* READ DATA
	 */
	if (readsize > 0) {
		ret =
		    _gnutls_read(session, &bufel, readsize,
				 session->internals.pull_func, ms);

		/* return immediately if we got an interrupt or eagain
		 * error.
		 */
		if (ret < 0) {
			return gnutls_assert_val(ret);
		}

		if (ret == 0)	/* EOF */
			return gnutls_assert_val(0);

		/* copy fresh data to our buffer.
		 */
		_gnutls_read_log
		    ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
		     (int) session->internals.record_recv_buffer.
		     byte_length, (int) ret);
		_gnutls_read_log("RB: Requested %d bytes\n", (int) total);

		_mbuffer_enqueue(&session->internals.record_recv_buffer,
				 bufel);

		if (IS_DTLS(session))
			ret =
			    MIN(total,
				session->internals.record_recv_buffer.
				byte_length);
		else
			ret =
			    session->internals.record_recv_buffer.
			    byte_length;

		if ((ret > 0) && ((size_t) ret < total))	/* Short Read */
			return gnutls_assert_val(GNUTLS_E_AGAIN);
		else
			return ret;
	} else
		return gnutls_assert_val(0);
}
Beispiel #25
0
static ssize_t
_gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel,
		    size_t size, gnutls_pull_func pull_func,
		    unsigned int *ms)
{
	size_t left;
	ssize_t i = 0;
	size_t max_size = max_record_recv_size(session);
	uint8_t *ptr;
	gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
	int ret;
	struct timespec t1, t2;
	unsigned int diff;

	session->internals.direction = 0;

	*bufel = _mbuffer_alloc_align16(MAX(max_size, size), get_total_headers(session));
	if (!*bufel) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}
	ptr = (*bufel)->msg.data;

	left = size;
	while (left > 0) {
		if (ms && *ms > 0) {
			ret = _gnutls_io_check_recv(session, *ms);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

			gnutls_gettime(&t1);
		}

		reset_errno(session);

		i = pull_func(fd, &ptr[size - left], left);

		if (i < 0) {
			int err = get_errno(session);

			_gnutls_read_log
			    ("READ: %d returned from %p, errno=%d gerrno=%d\n",
			     (int) i, fd, errno,
			     session->internals.errnum);

			if (err == EAGAIN || err == EINTR) {
				if (size - left > 0) {

					_gnutls_read_log
					    ("READ: returning %d bytes from %p\n",
					     (int) (size - left), fd);

					goto finish;
				}

				ret = errno_to_gerr(err, 0);
				goto cleanup;
			} else {
				gnutls_assert();
				ret = GNUTLS_E_PULL_ERROR;
				goto cleanup;
			}
		} else {

			_gnutls_read_log("READ: Got %d bytes from %p\n",
					 (int) i, fd);

			if (i == 0)
				break;	/* EOF */
		}

		left -= i;
		(*bufel)->msg.size += i;

		if (ms && *ms > 0 && *ms != GNUTLS_INDEFINITE_TIMEOUT) {
			gnutls_gettime(&t2);
			diff = timespec_sub_ms(&t2, &t1);
			if (diff < *ms)
				*ms -= diff;
			else {
				ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
				goto cleanup;
			}
		}
	}

      finish:

	_gnutls_read_log("READ: read %d bytes from %p\n",
			 (int) (size - left), fd);

	if (size - left == 0)
		_mbuffer_xfree(bufel);

	return (size - left);

      cleanup:
	_mbuffer_xfree(bufel);
	return ret;
}
Beispiel #26
0
static ssize_t
_gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel,
		   gnutls_pull_func pull_func, unsigned int *ms)
{
	ssize_t i, ret;
	uint8_t *ptr;
	struct timespec t1, t2;
	size_t max_size, recv_size;
	gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
	unsigned int diff;

	max_size = max_record_recv_size(session);
	recv_size = max_size;

	session->internals.direction = 0;

	if (ms && *ms > 0) {
		ret = _gnutls_io_check_recv(session, *ms);
		if (ret < 0)
			return gnutls_assert_val(ret);
		gnutls_gettime(&t1);
	}

	*bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session));
	if (*bufel == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	ptr = (*bufel)->msg.data;

	reset_errno(session);
	i = pull_func(fd, ptr, recv_size);

	if (i < 0) {
		int err = get_errno(session);

		_gnutls_read_log("READ: %d returned from %p, errno=%d\n",
				 (int) i, fd, err);

		ret = errno_to_gerr(err, 1);
		goto cleanup;
	} else {
		_gnutls_read_log("READ: Got %d bytes from %p\n", (int) i,
				 fd);
		if (i == 0) {
			/* If we get here, we likely have a stream socket.
			 * That assumption may not work on DCCP. */
			gnutls_assert();
			ret = 0;
			goto cleanup;
		}

		_mbuffer_set_udata_size(*bufel, i);
	}

	if (ms && *ms > 0) {
		gnutls_gettime(&t2);
		diff = timespec_sub_ms(&t2, &t1);
		if (diff < *ms)
			*ms -= diff;
		else {
			ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
			goto cleanup;
		}
	}

	_gnutls_read_log("READ: read %d bytes from %p\n", (int) i, fd);

	return i;

      cleanup:
	_mbuffer_xfree(bufel);
	return ret;
}
Beispiel #27
0
/* This is a receive function for the gnutls handshake 
 * protocol. Makes sure that we have received all data.
 */
ssize_t
_gnutls_handshake_io_recv_int(gnutls_session_t session,
			      gnutls_handshake_description_t htype,
			      handshake_buffer_st * hsk,
			      unsigned int optional)
{
	int ret;
	unsigned int tleft = 0;
	int retries = 7;

	ret = get_last_packet(session, htype, hsk, optional);
	if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED &&
	    ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE &&
	    ret != GNUTLS_E_INT_CHECK_AGAIN) {
		return gnutls_assert_val(ret);
	}

	/* try using the already existing records before
	 * trying to receive.
	 */
	ret = _gnutls_parse_record_buffered_msgs(session);

	if (ret == 0) {
		ret = get_last_packet(session, htype, hsk, optional);
	}

	if (IS_DTLS(session)) {
		if (ret >= 0)
			return ret;
	} else {
		if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
		     && ret < 0) || ret >= 0)
			return gnutls_assert_val(ret);
	}

	if (htype != (gnutls_handshake_description_t) -1) {
		ret = handshake_remaining_time(session);
		if (ret < 0)
			return gnutls_assert_val(ret);
		tleft = ret;
	}

	do {
		/* if we don't have a complete message waiting for us, try 
		 * receiving more */
		ret =
		    _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
					    tleft);
		if (ret < 0)
			return gnutls_assert_val_fatal(ret);

		ret = _gnutls_parse_record_buffered_msgs(session);
		if (ret == 0) {
			ret = get_last_packet(session, htype, hsk, optional);
		}
		/* we put an upper limit (retries) to the number of partial handshake
		 * messages in a record packet. */
	} while(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN && retries-- > 0);

	if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
		ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
	}

	return ret;
}
Beispiel #28
0
/* This is a receive function for the gnutls handshake 
 * protocol. Makes sure that we have received all data.
 *
 * htype is the next handshake packet expected.
 */
int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
{
	gnutls_datum_t msg;
	mbuffer_st *bufel = NULL, *prev = NULL;
	int ret;
	size_t data_size;
	handshake_buffer_st *recv_buf =
	    session->internals.handshake_recv_buffer;

	bufel =
	    _mbuffer_head_get_first(&session->internals.record_buffer,
				    &msg);
	if (bufel == NULL)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;

	if (!IS_DTLS(session)) {
		ssize_t append, header_size;

		do {
			if (bufel->type != GNUTLS_HANDSHAKE)
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_PACKET);

			if (unlikely
			    (session->internals.handshake_recv_buffer_size == 0 &&
			     msg.size < HANDSHAKE_HEADER_SIZE(session) &&
			     session->internals.handshake_header_recv_buffer.byte_length <
			     HANDSHAKE_HEADER_SIZE(session) - msg.size)) {
				bufel = _mbuffer_head_pop_first(&session->internals.record_buffer);
				_mbuffer_enqueue(&session->internals.handshake_header_recv_buffer,
						 bufel);
				break;
			} else if (session->internals.handshake_recv_buffer_size >
				   0 && recv_buf[0].length > recv_buf[0].data.length) {
				/* this is the rest of a previous message */
				append = MIN(msg.size,
					     recv_buf[0].length -
					     recv_buf[0].data.length);

				ret =
				    _gnutls_buffer_append_data(&recv_buf
							       [0].data,
							       msg.data,
							       append);
				if (ret < 0)
					return gnutls_assert_val(ret);

				_mbuffer_head_remove_bytes(&session->
							   internals.
							   record_buffer,
							   append);
			} else {	/* received new message */
				if (unlikely
				    (session->internals.
				     handshake_header_recv_buffer.length > 0)) {
					bufel = _mbuffer_head_pop_first(&session->internals.
									record_buffer);
					_mbuffer_enqueue(&session->internals.
							 handshake_header_recv_buffer,
							 bufel);
					ret = _mbuffer_linearize_align16(&session->internals.
									 handshake_header_recv_buffer,
									 get_total_headers(session));
					if (ret < 0)
						return gnutls_assert_val(ret);
					bufel = _mbuffer_head_pop_first(&session->internals.
									handshake_header_recv_buffer);
					_mbuffer_head_push_first(&session->internals.
								 record_buffer,
								 bufel);
				}

				ret =
				    parse_handshake_header(session, bufel,
							   &recv_buf[0]);
				if (ret < 0)
					return gnutls_assert_val(ret);

				header_size = ret;
				session->internals.
				    handshake_recv_buffer_size = 1;

				_mbuffer_set_uhead_size(bufel,
							header_size);

				data_size =
				    MIN(recv_buf[0].length,
					_mbuffer_get_udata_size(bufel));
				ret =
				    _gnutls_buffer_append_data(&recv_buf
							       [0].data,
							       _mbuffer_get_udata_ptr
							       (bufel),
							       data_size);
				if (ret < 0)
					return gnutls_assert_val(ret);
				_mbuffer_set_uhead_size(bufel, 0);
				_mbuffer_head_remove_bytes(&session->
							   internals.
							   record_buffer,
							   data_size +
							   header_size);
			}

			/* if packet is complete then return it
			 */
			if (recv_buf[0].length == recv_buf[0].data.length) {
				return 0;
			}
			bufel =
			    _mbuffer_head_get_first(&session->internals.
						    record_buffer, &msg);
		}
		while (bufel != NULL);

		/* if we are here it means that the received packets were not
		 * enough to complete the handshake packet.
		 */
		return gnutls_assert_val(GNUTLS_E_AGAIN);
	} else {		/* DTLS */

		handshake_buffer_st tmp;

		do {
			/* we now 
			 * 0. parse headers
			 * 1. insert to handshake_recv_buffer
			 * 2. sort handshake_recv_buffer on sequence numbers
			 * 3. return first packet if completed or GNUTLS_E_AGAIN.
			 */
			do {
				if (bufel->type != GNUTLS_HANDSHAKE) {
					gnutls_assert();
					goto next;	/* ignore packet */
				}

				_gnutls_handshake_buffer_init(&tmp);

				ret =
				    parse_handshake_header(session, bufel,
							   &tmp);
				if (ret < 0) {
					gnutls_assert();
					_gnutls_audit_log(session,
							  "Invalid handshake packet headers. Discarding.\n");
					break;
				}

				_mbuffer_consume(&session->internals.
						 record_buffer, bufel,
						 ret);

				data_size =
				    MIN(tmp.length,
					tmp.end_offset - tmp.start_offset +
					1);

				ret =
				    _gnutls_buffer_append_data(&tmp.data,
							       _mbuffer_get_udata_ptr
							       (bufel),
							       data_size);
				if (ret < 0)
					return gnutls_assert_val(ret);

				_mbuffer_consume(&session->internals.
						 record_buffer, bufel,
						 data_size);

				ret =
				    merge_handshake_packet(session, &tmp);
				if (ret < 0)
					return gnutls_assert_val(ret);

			}
			while (_mbuffer_get_udata_size(bufel) > 0);

			prev = bufel;
			bufel =
			    _mbuffer_dequeue(&session->internals.
					     record_buffer, bufel);

			_mbuffer_xfree(&prev);
			continue;

		      next:
			bufel = _mbuffer_head_get_next(bufel, NULL);
		}
		while (bufel != NULL);

		/* sort in descending order */
		if (session->internals.handshake_recv_buffer_size > 1)
			qsort(recv_buf,
			      session->internals.
			      handshake_recv_buffer_size,
			      sizeof(recv_buf[0]), handshake_compare);

		while (session->internals.handshake_recv_buffer_size > 0 &&
		       recv_buf[LAST_ELEMENT].sequence <
		       session->internals.dtls.hsk_read_seq) {
			_gnutls_audit_log(session,
					  "Discarded replayed handshake packet with sequence %d\n",
					  recv_buf[LAST_ELEMENT].sequence);
			_gnutls_handshake_buffer_clear(&recv_buf
						       [LAST_ELEMENT]);
			session->internals.handshake_recv_buffer_size--;
		}

		return 0;
	}
}
Beispiel #29
0
/* returns the last stored handshake packet.
 */
static int get_last_packet(gnutls_session_t session,
			   gnutls_handshake_description_t htype,
			   handshake_buffer_st * hsk,
			   unsigned int optional)
{
	handshake_buffer_st *recv_buf =
	    session->internals.handshake_recv_buffer;

	if (IS_DTLS(session)) {
		if (session->internals.handshake_recv_buffer_size == 0 ||
		    (session->internals.dtls.hsk_read_seq !=
		     recv_buf[LAST_ELEMENT].sequence))
			goto timeout;

		if (htype != recv_buf[LAST_ELEMENT].htype) {
			if (optional == 0)
				_gnutls_audit_log(session,
						  "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
						  _gnutls_handshake2str
						  (recv_buf[0].htype),
						  (int) recv_buf[0].htype,
						  _gnutls_handshake2str
						  (htype), (int) htype);

			return
			    gnutls_assert_val
			    (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
		}

		else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
			  recv_buf[LAST_ELEMENT].end_offset ==
			  recv_buf[LAST_ELEMENT].length - 1)
			 || recv_buf[LAST_ELEMENT].length == 0) {
			session->internals.dtls.hsk_read_seq++;
			_gnutls_handshake_buffer_move(hsk,
						      &recv_buf
						      [LAST_ELEMENT]);
			session->internals.handshake_recv_buffer_size--;
			return 0;
		} else {
			/* if we don't have a complete handshake message, but we
			 * have queued data waiting, try again to reconstruct the
			 * handshake packet, using the queued */
			if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
			    record_check_unprocessed(session) > 0)
				return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
			else
				goto timeout;
		}
	} else {		/* TLS */

		if (session->internals.handshake_recv_buffer_size > 0
		    && recv_buf[0].length == recv_buf[0].data.length) {
			if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) {
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
			}

			_gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
			session->internals.handshake_recv_buffer_size--;
			return 0;
		} else
			return
			    gnutls_assert_val
			    (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
	}

      timeout:
	RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
}
/**
 * gnutls_x509_trust_list_verify_crt:
 * @list: The structure of the list
 * @cert_list: is the certificate list to be verified
 * @cert_list_size: is the certificate list size
 * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
 * @verify: will hold the certificate verification output.
 * @func: If non-null will be called on each chain element verification with the output.
 *
 * This function will try to verify the given certificate and return
 * its status.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list,
                                  gnutls_x509_crt_t * cert_list,
                                  unsigned int cert_list_size,
                                  unsigned int flags,
                                  unsigned int *verify,
                                  gnutls_verify_output_function func)
{
    gnutls_datum_t dn;
    int ret, i;
    uint32_t hash;

    if (cert_list == NULL || cert_list_size < 1)
        return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

    cert_list_size = shorten_clist(list, cert_list, cert_list_size);
    if (cert_list_size <= 0)
        return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

    ret =
        gnutls_x509_crt_get_raw_issuer_dn(cert_list[cert_list_size - 1],
                                          &dn);
    if (ret < 0) {
        gnutls_assert();
        return ret;
    }

    hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH);
    hash %= list->size;

    _gnutls_free_datum(&dn);

    *verify = _gnutls_x509_verify_certificate(cert_list, cert_list_size,
                                              list->node[hash].trusted_cas,
                                              list->node[hash].
                                              trusted_ca_size, flags,
                                              func);

    if (*verify != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS))
        return 0;

    /* Check revocation of individual certificates.
     * start with the last one that we already have its hash
     */
    ret = _gnutls_x509_crt_check_revocation(cert_list[cert_list_size - 1],
                                            list->node[hash].crls,
                                            list->node[hash].crl_size,
                                            func);
    if (ret == 1) {             /* revoked */
        *verify |= GNUTLS_CERT_REVOKED;
        *verify |= GNUTLS_CERT_INVALID;
        return 0;
    }

    for (i = 0; i < cert_list_size - 1; i++) {
        ret = gnutls_x509_crt_get_raw_issuer_dn(cert_list[i], &dn);
        if (ret < 0) {
            gnutls_assert();
            return ret;
        }

        hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH);
        hash %= list->size;

        _gnutls_free_datum(&dn);

        ret = _gnutls_x509_crt_check_revocation(cert_list[i],
                                                list->node[hash].crls,
                                                list->node[hash].crl_size,
                                                func);
        if (ret == 1) {         /* revoked */
            *verify |= GNUTLS_CERT_REVOKED;
            *verify |= GNUTLS_CERT_INVALID;
            return 0;
        }
    }

    return 0;
}