Beispiel #1
0
/* Reads a DER encoded certificate list from memory and stores it to a
 * gnutls_cert structure.  Returns the number of certificates parsed.
 */
static int
parse_crt_mem (gnutls_cert ** cert_list, unsigned *ncerts,
	       gnutls_x509_crt_t cert)
{
  int i;
  int ret;

  i = *ncerts + 1;

  *cert_list =
    (gnutls_cert *) gnutls_realloc_fast (*cert_list,
					 i * sizeof (gnutls_cert));

  if (*cert_list == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  ret = _gnutls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  *ncerts = i;

  return 1;			/* one certificate parsed */
}
Beispiel #2
0
/* Reads a DER or PEM certificate from memory
 */
static int
read_cert_mem (gnutls_certificate_credentials_t res, const void *cert,
	       int cert_size, gnutls_x509_crt_fmt_t type)
{
  int ret;

  /* allocate space for the certificate to add
   */
  res->cert_list = gnutls_realloc_fast (res->cert_list,
					(1 +
					 res->ncerts) *
					sizeof (gnutls_cert *));
  if (res->cert_list == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
					       (1 +
						res->ncerts) * sizeof (int));
  if (res->cert_list_length == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list[res->ncerts] = NULL;	/* for realloc */
  res->cert_list_length[res->ncerts] = 0;

  if (type == GNUTLS_X509_FMT_DER)
    ret = parse_der_cert_mem (&res->cert_list[res->ncerts],
			      &res->cert_list_length[res->ncerts],
			      cert, cert_size);
  else
    ret = parse_pem_cert_mem (&res->cert_list[res->ncerts],
			      &res->cert_list_length[res->ncerts], cert,
			      cert_size);

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

  return ret;
}
/**
 * gnutls_x509_trust_list_add_crls:
 * @list: The structure of the list
 * @crl_list: A list of CRLs
 * @crl_size: The length of the CRL list
 * @flags: if GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added.
 * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
 *
 * This function will add the given certificate revocation lists
 * to the trusted list. The list of CRLs must not be deinitialized
 * during this structure's lifetime.
 *
 * This function must be called after gnutls_x509_trust_list_add_cas()
 * to allow verifying the CRLs for validity.
 *
 * Returns: The number of added elements is returned.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list,
                                const gnutls_x509_crl_t * crl_list,
                                int crl_size, unsigned int flags,
                                unsigned int verification_flags)
{
    int ret, i, j = 0;
    gnutls_datum_t dn;
    unsigned int vret = 0;
    uint32_t hash;

    /* Probably we can optimize things such as removing duplicates
     * etc.
     */

    if (crl_size == 0 || crl_list == NULL)
        return 0;

    for (i = 0; i < crl_size; i++) {
        ret = gnutls_x509_crl_get_raw_issuer_dn(crl_list[i], &dn);
        if (ret < 0) {
            gnutls_assert();
            return i;
        }

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

        _gnutls_free_datum(&dn);

        if (flags & GNUTLS_TL_VERIFY_CRL) {

            ret =
                gnutls_x509_crl_verify(crl_list[i],
                                       list->node[hash].trusted_cas,
                                       list->node[hash].trusted_ca_size,
                                       verification_flags, &vret);
            if (ret < 0 || vret != 0)
                continue;
        }

        list->node[hash].crls =
            gnutls_realloc_fast(list->node[hash].crls,
                                (list->node[hash].crl_size +
                                 1) *
                                sizeof(list->node[hash].trusted_cas[0]));
        if (list->node[hash].crls == NULL) {
            gnutls_assert();
            return i;
        }

        list->node[hash].crls[list->node[hash].crl_size] = crl_list[i];
        list->node[hash].crl_size++;
        j++;
    }

    return j;
}
Beispiel #4
0
/* This function will set the auth info structure in the key
 * structure.
 * If allow change is !=0 then this will allow changing the auth
 * info structure to a different type.
 */
int
_gnutls_auth_info_set (gnutls_session_t session,
		       gnutls_credentials_type_t type, int size,
		       int allow_change)
{
  if (session->key->auth_info == NULL)
    {
      session->key->auth_info = gnutls_calloc (1, size);
      if (session->key->auth_info == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}
      session->key->auth_info_type = type;
      session->key->auth_info_size = size;
    }
  else
    {
      if (allow_change == 0)
	{
	  /* If the credentials for the current authentication scheme,
	   * are not the one we want to set, then it's an error.
	   * This may happen if a rehandshake is performed an the
	   * ciphersuite which is negotiated has different authentication
	   * schema.
	   */
	  if (gnutls_auth_get_type (session) != session->key->auth_info_type)
	    {
	      gnutls_assert ();
	      return GNUTLS_E_INVALID_REQUEST;
	    }
	}
      else
	{
	  /* The new behaviour: Here we reallocate the auth info structure
	   * in order to be able to negotiate different authentication
	   * types. Ie. perform an auth_anon and then authenticate again using a
	   * certificate (in order to prevent revealing the certificate's contents,
	   * to passive eavesdropers.
	   */
	  if (gnutls_auth_get_type (session) != session->key->auth_info_type)
	    {
	      session->key->auth_info =
		gnutls_realloc_fast (session->key->auth_info, size);
	      if (session->key->auth_info == NULL)
		{
		  gnutls_assert ();
		  return GNUTLS_E_MEMORY_ERROR;
		}
	      memset (session->key->auth_info, 0, size);
	      session->key->auth_info_type = type;
	      session->key->auth_info_size = size;
	    }
	}
    }
  return 0;
}
Beispiel #5
0
/**
 * gnutls_x509_trust_list_remove_cas:
 * @list: The structure of the list
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
 *
 * This function will remove the given certificate authorities
 * from the trusted list.
 *
 * Note that this function can accept certificates and authorities
 * not yet known. In that case they will be kept in a separate
 * black list that will be used during certificate verification.
 * Unlike gnutls_x509_trust_list_add_cas() there is no deinitialization
 * restriction for  certificate list provided in this function.
 *
 * Returns: The number of removed elements is returned.
 *
 * Since: 3.1.10
 **/
int
gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list,
				  const gnutls_x509_crt_t * clist,
				  int clist_size)
{
	int i, r = 0;
	unsigned j;
	uint32_t hash;

	for (i = 0; i < clist_size; i++) {
		hash =
		    hash_pjw_bare(clist[i]->raw_dn.data,
				  clist[i]->raw_dn.size);
		hash %= list->size;

		for (j = 0; j < list->node[hash].trusted_ca_size; j++) {
			if (_gnutls_check_if_same_cert
			    (clist[i],
			     list->node[hash].trusted_cas[j]) != 0) {

				gnutls_x509_crt_deinit(list->node[hash].
						       trusted_cas[j]);
				list->node[hash].trusted_cas[j] =
				    list->node[hash].trusted_cas[list->
								 node
								 [hash].
								 trusted_ca_size
								 - 1];
				list->node[hash].trusted_ca_size--;
				r++;
				break;
			}
		}

		/* Add the CA (or plain) certificate to the black list as well.
		 * This will prevent a subordinate CA from being valid, and 
		 * ensure that a server certificate will also get rejected.
		 */
		list->blacklisted =
		    gnutls_realloc_fast(list->blacklisted,
				(list->blacklisted_size + 1) *
				sizeof(list->blacklisted[0]));
		if (list->blacklisted == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		list->blacklisted[list->blacklisted_size] = crt_cpy(clist[i]);
		if (list->blacklisted[list->blacklisted_size] != NULL)
			list->blacklisted_size++;
	}

	return r;
}
Beispiel #6
0
static int
add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list,
		       gnutls_x509_crt_t ca)
{
	gnutls_datum_t tmp;
	size_t newsize;
	unsigned char *newdata, *p;

	/* Add DN of the last added CAs to the RDN sequence
	 * This will be sent to clients when a certificate
	 * request message is sent.
	 */

	/* FIXME: in case of a client it is not needed
	 * to do that. This would save time and memory.
	 * However we don't have that information available
	 * here.
	 * Further, this function is now much more efficient,
	 * so optimizing that is less important.
	 */
	tmp.data = ca->raw_dn.data;
	tmp.size = ca->raw_dn.size;

	newsize = list->x509_rdn_sequence.size + 2 + tmp.size;
	if (newsize < list->x509_rdn_sequence.size) {
		gnutls_assert();
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
	}

	newdata =
	    gnutls_realloc_fast(list->x509_rdn_sequence.data,
				newsize);
	if (newdata == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	p = newdata + list->x509_rdn_sequence.size;
	_gnutls_write_uint16(tmp.size, p);
	if (tmp.data != NULL)
		memcpy(p + 2, tmp.data, tmp.size);

	list->x509_rdn_sequence.size = newsize;
	list->x509_rdn_sequence.data = newdata;

	return 0;
}
Beispiel #7
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 flags)
{
	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) {
			if (!(flags & GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED)
			    &&
			    gnutls_x509_crt_check_issuer((*extra_certs)[i],
							 (*extra_certs)[i])
			    != 0)
				goto skip;

			*chain =
			    gnutls_realloc_fast(*chain,
						sizeof((*chain)[0]) *
						++(*chain_len));
			if (*chain == NULL) {
				gnutls_assert();
				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;
		}

	      skip:
		i++;
	}
	return 0;
}
int _gnutls_ext_register(extension_entry_st * mod)
{
	extension_entry_st *p;

	p = gnutls_realloc_fast(extfunc,
				sizeof(*extfunc) * (extfunc_size + 1));
	if (!p) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	extfunc = p;

	memcpy(&extfunc[extfunc_size], mod, sizeof(*mod));

	extfunc_size++;

	return GNUTLS_E_SUCCESS;
}
Beispiel #9
0
/* Keeps the provided certificate in a structure that will be
 * deallocated on deinit. This is to handle get_issuer() with 
 * pkcs11 trust modules when the GNUTLS_TL_GET_COPY flag isn't
 * given. It is not thread safe. */
static int
trust_list_add_compat(gnutls_x509_trust_list_t list,
			       gnutls_x509_crt_t cert)
{
	list->keep_certs =
		    gnutls_realloc_fast(list->keep_certs,
					(list->keep_certs_size +
					 1) *
					sizeof(list->keep_certs[0]));
	if (list->keep_certs == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	list->keep_certs[list->keep_certs_size] = cert;
	list->keep_certs_size++;

	return 0;
}
/**
 * gnutls_x509_trust_list_add_named_crt:
 * @list: The structure of the list
 * @cert: A certificate
 * @name: An identifier for the certificate
 * @name_size: The size of the identifier
 * @flags: should be 0.
 *
 * This function will add the given certificate to the trusted
 * list and associate it with a name. The certificate will not be
 * be used for verification with gnutls_x509_trust_list_verify_crt()
 * but only with gnutls_x509_trust_list_verify_named_crt().
 *
 * In principle this function can be used to set individual "server"
 * certificates that are trusted by the user for that specific server
 * but for no other purposes.
 *
 * The certificate must not be deinitialized during the lifetime
 * of the trusted list.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list,
                                     gnutls_x509_crt_t cert,
                                     const void *name, size_t name_size,
                                     unsigned int flags)
{
    gnutls_datum_t dn;
    int ret;
    uint32_t hash;

    if (name_size >= MAX_NAME_SIZE)
        return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

    ret = gnutls_x509_crt_get_raw_issuer_dn(cert, &dn);
    if (ret < 0) {
        gnutls_assert();
        return ret;
    }

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

    _gnutls_free_datum(&dn);

    list->node[hash].named_certs =
        gnutls_realloc_fast(list->node[hash].named_certs,
                            (list->node[hash].named_cert_size +
                             1) * sizeof(list->node[hash].named_certs[0]));
    if (list->node[hash].named_certs == NULL)
        return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

    list->node[hash].named_certs[list->node[hash].named_cert_size].cert =
        cert;
    memcpy(list->node[hash].named_certs[list->node[hash].named_cert_size].
           name, name, name_size);
    list->node[hash].named_certs[list->node[hash].named_cert_size].
        name_size = name_size;

    list->node[hash].named_cert_size++;

    return 0;
}
Beispiel #11
0
/**
 * gnutls_x509_crl_list_import2:
 * @crls: The structures to store the parsed crl list. Must not be initialized.
 * @size: It will contain the size of the list.
 * @data: The PEM encoded CRL.
 * @format: One of DER or PEM.
 * @flags: must be (0) or an OR'd sequence of gnutls_certificate_import_flags.
 *
 * This function will convert the given PEM encoded CRL list
 * to the native gnutls_x509_crl_t format. The output will be stored
 * in @crls.  They will be automatically initialized.
 *
 * If the Certificate is PEM encoded it should have a header of "X509
 * CRL".
 *
 * Returns: the number of certificates read or a negative error value.
 *
 * Since: 3.0
 **/
int
gnutls_x509_crl_list_import2(gnutls_x509_crl_t ** crls,
			     unsigned int *size,
			     const gnutls_datum_t * data,
			     gnutls_x509_crt_fmt_t format,
			     unsigned int flags)
{
	unsigned int init = 1024;
	int ret;

	*crls = gnutls_malloc(sizeof(gnutls_x509_crl_t) * init);
	if (*crls == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	ret =
	    gnutls_x509_crl_list_import(*crls, &init, data, format,
					GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
	if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
		*crls =
		    gnutls_realloc_fast(*crls,
					sizeof(gnutls_x509_crl_t) * init);
		if (*crls == NULL) {
			gnutls_assert();
			return GNUTLS_E_MEMORY_ERROR;
		}

		ret =
		    gnutls_x509_crl_list_import(*crls, &init, data, format,
						flags);
	}

	if (ret < 0) {
		gnutls_free(*crls);
		*crls = NULL;
		return ret;
	}

	*size = init;
	return 0;
}
Beispiel #12
0
static int
add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list,
		       gnutls_x509_crt_t ca)
{
	gnutls_datum_t tmp;
	size_t newsize;
	unsigned char *newdata, *p;

	/* Add DN of the last added CAs to the RDN sequence
	 * This will be sent to clients when a certificate
	 * request message is sent.
	 */
	tmp.data = ca->raw_dn.data;
	tmp.size = ca->raw_dn.size;

	newsize = list->x509_rdn_sequence.size + 2 + tmp.size;
	if (newsize < list->x509_rdn_sequence.size) {
		gnutls_assert();
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
	}

	newdata =
	    gnutls_realloc_fast(list->x509_rdn_sequence.data,
				newsize);
	if (newdata == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	p = newdata + list->x509_rdn_sequence.size;
	_gnutls_write_uint16(tmp.size, p);
	if (tmp.data != NULL)
		memcpy(p + 2, tmp.data, tmp.size);

	list->x509_rdn_sequence.size = newsize;
	list->x509_rdn_sequence.data = newdata;

	return 0;
}
/**
 * gnutls_x509_trust_list_add_cas:
 * @list: The structure of the list
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
 * @flags: should be 0.
 *
 * This function will add the given certificate authorities
 * to the trusted list. The list of CAs must not be deinitialized
 * during this structure's lifetime.
 *
 * Returns: The number of added elements is returned.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
                               const gnutls_x509_crt_t * clist,
                               int clist_size, unsigned int flags)
{
    gnutls_datum_t dn;
    int ret, i;
    uint32_t hash;

    for (i = 0; i < clist_size; i++) {
        ret = gnutls_x509_crt_get_raw_dn(clist[i], &dn);
        if (ret < 0) {
            gnutls_assert();
            return i;
        }

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

        _gnutls_free_datum(&dn);
        list->node[hash].trusted_cas =
            gnutls_realloc_fast(list->node[hash].trusted_cas,
                                (list->node[hash].trusted_ca_size +
                                 1) *
                                sizeof(list->node[hash].trusted_cas[0]));
        if (list->node[hash].trusted_cas == NULL) {
            gnutls_assert();
            return i;
        }

        list->node[hash].trusted_cas[list->node[hash].trusted_ca_size] =
            clist[i];
        list->node[hash].trusted_ca_size++;
    }

    return i;
}
Beispiel #14
0
/* Reads a PEM encoded PKCS-1 RSA/DSA private key from memory.  Type
 * indicates the certificate format.  KEY can be NULL, to indicate
 * that GnuTLS doesn't know the private key.
 */
static int
read_key_mem (gnutls_certificate_credentials_t res,
	      const void *key, int key_size, gnutls_x509_crt_fmt_t type)
{
  int ret;
  gnutls_datum_t tmp;

  /* allocate space for the pkey list
   */
  res->pkey =
    gnutls_realloc_fast (res->pkey,
			 (res->ncerts + 1) * sizeof (gnutls_privkey));
  if (res->pkey == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  if (key)
    {
      tmp.data = (opaque *) key;
      tmp.size = key_size;

      ret =
	_gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp,
					  type);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}
    }
  else
    memset (&res->pkey[res->ncerts], 0, sizeof (gnutls_privkey));

  return 0;
}
Beispiel #15
0
/**
 * gnutls_x509_trust_list_add_named_crt:
 * @list: The structure of the list
 * @cert: A certificate
 * @name: An identifier for the certificate
 * @name_size: The size of the identifier
 * @flags: should be 0.
 *
 * This function will add the given certificate to the trusted
 * list and associate it with a name. The certificate will not be
 * be used for verification with gnutls_x509_trust_list_verify_crt()
 * but with gnutls_x509_trust_list_verify_named_crt() or
 * gnutls_x509_trust_list_verify_crt2() - the latter only since
 * GnuTLS 3.4.0 and if a hostname is provided.
 *
 * In principle this function can be used to set individual "server"
 * certificates that are trusted by the user for that specific server
 * but for no other purposes.
 *
 * The certificate must not be deinitialized during the lifetime
 * of the trusted list.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list,
				     gnutls_x509_crt_t cert,
				     const void *name, size_t name_size,
				     unsigned int flags)
{
	uint32_t hash;

	if (name_size >= MAX_SERVER_NAME_SIZE)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	hash =
	    hash_pjw_bare(cert->raw_issuer_dn.data,
			  cert->raw_issuer_dn.size);
	hash %= list->size;

	list->node[hash].named_certs =
	    gnutls_realloc_fast(list->node[hash].named_certs,
				(list->node[hash].named_cert_size +
				 1) *
				sizeof(list->node[hash].named_certs[0]));
	if (list->node[hash].named_certs == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	list->node[hash].named_certs[list->node[hash].named_cert_size].
	    cert = cert;
	memcpy(list->node[hash].
	       named_certs[list->node[hash].named_cert_size].name, name,
	       name_size);
	list->node[hash].named_certs[list->node[hash].
				     named_cert_size].name_size =
	    name_size;

	list->node[hash].named_cert_size++;

	return 0;
}
Beispiel #16
0
static int
gen_dhe_server_kx (gnutls_session_t session, opaque ** data)
{
  bigint_t g, p;
  const bigint_t *mpis;
  int ret = 0, data_size;
  gnutls_cert *apr_cert_list;
  gnutls_privkey_t apr_pkey;
  int apr_cert_list_length;
  gnutls_datum_t signature = { NULL, 0 }, ddata;
  gnutls_certificate_credentials_t cred;
  gnutls_dh_params_t dh_params;
  gnutls_sign_algorithm_t sign_algo;
  gnutls_protocol_t ver = gnutls_protocol_get_version (session);

  cred = (gnutls_certificate_credentials_t)
    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
  if (cred == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  /* find the appropriate certificate */
  if ((ret =
       _gnutls_get_selected_cert (session, &apr_cert_list,
                                  &apr_cert_list_length, &apr_pkey)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  dh_params =
    _gnutls_get_dh_params (cred->dh_params, cred->params_func, session);
  mpis = _gnutls_dh_params_to_mpi (dh_params);
  if (mpis == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
    }

  p = mpis[0];
  g = mpis[1];

  if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE,
                                    sizeof (cert_auth_info_st), 0)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  _gnutls_dh_set_group (session, g, p);

  ret = _gnutls_dh_common_print_server_kx (session, g, p, data, 0);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }
  data_size = ret;

  /* Generate the signature. */

  ddata.data = *data;
  ddata.size = data_size;

  if (apr_cert_list_length > 0)
    {
      if ((ret =
           _gnutls_handshake_sign_data (session, &apr_cert_list[0],
                                        apr_pkey, &ddata, &signature,
                                        &sign_algo)) < 0)
        {
          gnutls_assert ();
          goto cleanup;
        }
    }
  else
    {
      gnutls_assert ();
      ret = data_size;         /* do not put a signature - ILLEGAL! */
      goto cleanup;
    }

  *data = gnutls_realloc_fast (*data, data_size + signature.size + 4);
  if (*data == NULL)
    {
      gnutls_assert ();
      ret = GNUTLS_E_MEMORY_ERROR;
      goto cleanup;
    }

  if (_gnutls_version_has_selectable_sighash (ver))
    {
      const sign_algorithm_st *aid;

      if (sign_algo == GNUTLS_SIGN_UNKNOWN)
        {
          ret = GNUTLS_E_UNKNOWN_ALGORITHM;
          goto cleanup;
        }

      aid = _gnutls_sign_to_tls_aid (sign_algo);
      if (aid == NULL)
        {
          gnutls_assert();
          ret = GNUTLS_E_UNKNOWN_ALGORITHM;
          goto cleanup;
        }
      
      (*data)[data_size++] = aid->hash_algorithm;
      (*data)[data_size++] = aid->sign_algorithm;
    }

  _gnutls_write_datum16 (&(*data)[data_size], signature);
  data_size += signature.size + 2;

  _gnutls_free_datum (&signature);

  return data_size;

cleanup:
  _gnutls_free_datum (&signature);
  gnutls_free(*data);
  return ret;

}
Beispiel #17
0
static int
find_ext_cb(struct pkcs11_session_info *sinfo,
	     struct token_info *info, struct ck_info *lib_info,
	     void *input)
{
	struct find_ext_data_st *find_data = input;
	struct ck_attribute a[4];
	ck_object_class_t class = -1;
	unsigned long count;
	ck_rv_t rv;
	ck_object_handle_t obj;
	int ret;
	gnutls_datum_t ext;

	if (info == NULL) {	/* we don't support multiple calls */
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

	/* do not bother reading the token if basic fields do not match
	 */
	if (!p11_kit_uri_match_token_info
	    (find_data->obj->info, &info->tinfo)
	    || !p11_kit_uri_match_module_info(find_data->obj->info,
					      lib_info)) {
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

	/* retrieve the extensions */
	class = CKO_X_CERTIFICATE_EXTENSION;
	a[0].type = CKA_CLASS;
	a[0].value = &class;
	a[0].value_len = sizeof class;

	a[1].type = CKA_PUBLIC_KEY_INFO;
	a[1].value = find_data->spki.data;
	a[1].value_len = find_data->spki.size;

	rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log
		    ("p11: FindObjectsInit failed for cert extensions.\n");
		return pkcs11_rv_to_err(rv);
	}

	while(pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1) {
		rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext);
		if (rv == CKR_OK) {

			find_data->exts = gnutls_realloc_fast(find_data->exts, (1+find_data->exts_size)*sizeof(find_data->exts[0]));
			if (find_data->exts == NULL) {
				gnutls_assert();
				ret = pkcs11_rv_to_err(rv);
				goto cleanup;
			}

			if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) {
				find_data->exts_size++;
			}
		}
	}

	ret = 0;
 cleanup:
 	pkcs11_find_objects_final(sinfo);
	return ret;
}
Beispiel #18
0
/**
 * gnutls_pkcs12_simple_parse:
 * @p12: A pkcs12 type
 * @password: optional password used to decrypt the structure, bags and keys.
 * @key: a structure to store the parsed private key.
 * @chain: the corresponding to key certificate chain (may be %NULL)
 * @chain_len: will be updated with the number of additional (may be %NULL)
 * @extra_certs: optional pointer to receive an array of additional
 *	       certificates found in the PKCS12 structure (may be %NULL).
 * @extra_certs_len: will be updated with the number of additional
 *		   certs (may be %NULL).
 * @crl: an optional structure to store the parsed CRL (may be %NULL).
 * @flags: should be zero or one of GNUTLS_PKCS12_SP_*
 *
 * This function parses a PKCS12 structure in @pkcs12 and extracts the
 * private key, the corresponding certificate chain, any additional
 * certificates and a CRL. The structures in @key, @chain @crl, and @extra_certs
 * must not be initialized.
 *
 * The @extra_certs and @extra_certs_len parameters are optional
 * and both may be set to %NULL. If either is non-%NULL, then both must
 * be set. The value for @extra_certs is allocated
 * using gnutls_malloc().
 * 
 * Encrypted PKCS12 bags and PKCS8 private keys are supported, but
 * only with password based security and the same password for all
 * operations.
 *
 * Note that a PKCS12 structure may contain many keys and/or certificates,
 * and there is no way to identify which key/certificate pair you want.
 * For this reason this function is useful for PKCS12 files that contain 
 * only one key/certificate pair and/or one CRL.
 *
 * If the provided structure has encrypted fields but no password
 * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED.
 *
 * Note that normally the chain constructed does not include self signed
 * certificates, to comply with TLS' requirements. If, however, the flag 
 * %GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED is specified then
 * self signed certificates will be included in the chain.
 *
 * Prior to using this function the PKCS #12 structure integrity must
 * be verified using gnutls_pkcs12_verify_mac().
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.1.0
 **/
int
gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12,
			   const char *password,
			   gnutls_x509_privkey_t * key,
			   gnutls_x509_crt_t ** chain,
			   unsigned int *chain_len,
			   gnutls_x509_crt_t ** extra_certs,
			   unsigned int *extra_certs_len,
			   gnutls_x509_crl_t * crl, unsigned int flags)
{
	gnutls_pkcs12_bag_t bag = NULL;
	gnutls_x509_crt_t *_extra_certs = NULL;
	unsigned int _extra_certs_len = 0;
	gnutls_x509_crt_t *_chain = NULL;
	unsigned int _chain_len = 0;
	int idx = 0;
	int ret;
	size_t cert_id_size = 0;
	size_t key_id_size = 0;
	uint8_t cert_id[20];
	uint8_t key_id[20];
	int privkey_ok = 0;
	unsigned int i;
	int elements_in_bag;

	*key = NULL;

	if (crl)
		*crl = NULL;

	/* find the first private key */
	for (;;) {

		ret = gnutls_pkcs12_bag_init(&bag);
		if (ret < 0) {
			bag = NULL;
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_get_bag(p12, idx, bag);
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
			gnutls_pkcs12_bag_deinit(bag);
			bag = NULL;
			break;
		}
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_bag_get_type(bag, 0);
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		if (ret == GNUTLS_BAG_ENCRYPTED) {
			if (password == NULL) {
				ret =
				    gnutls_assert_val
				    (GNUTLS_E_DECRYPTION_FAILED);
				goto done;
			}

			ret = gnutls_pkcs12_bag_decrypt(bag, password);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}
		}

		elements_in_bag = gnutls_pkcs12_bag_get_count(bag);
		if (elements_in_bag < 0) {
			gnutls_assert();
			goto done;
		}

		for (i = 0; i < (unsigned)elements_in_bag; i++) {
			int type;
			gnutls_datum_t data;

			type = gnutls_pkcs12_bag_get_type(bag, i);
			if (type < 0) {
				gnutls_assert();
				goto done;
			}

			ret = gnutls_pkcs12_bag_get_data(bag, i, &data);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}

			switch (type) {
			case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
				if (password == NULL) {
					ret =
					    gnutls_assert_val
					    (GNUTLS_E_DECRYPTION_FAILED);
					goto done;
				}

				FALLTHROUGH;
			case GNUTLS_BAG_PKCS8_KEY:
				if (*key != NULL) {	/* too simple to continue */
					gnutls_assert();
					break;
				}

				ret = gnutls_x509_privkey_init(key);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				ret = gnutls_x509_privkey_import_pkcs8
				    (*key, &data, GNUTLS_X509_FMT_DER,
				     password,
				     type ==
				     GNUTLS_BAG_PKCS8_KEY ?
				     GNUTLS_PKCS_PLAIN : 0);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				key_id_size = sizeof(key_id);
				ret =
				    gnutls_x509_privkey_get_key_id(*key, 0,
								   key_id,
								   &key_id_size);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				privkey_ok = 1;	/* break */
				break;
			default:
				break;
			}
		}

		idx++;
		gnutls_pkcs12_bag_deinit(bag);
		bag = NULL;

		if (privkey_ok != 0)	/* private key was found */
			break;
	}

	if (privkey_ok == 0) {	/* no private key */
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

	/* now find the corresponding certificate 
	 */
	idx = 0;
	bag = NULL;
	for (;;) {
		ret = gnutls_pkcs12_bag_init(&bag);
		if (ret < 0) {
			bag = NULL;
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_get_bag(p12, idx, bag);
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
			gnutls_pkcs12_bag_deinit(bag);
			bag = NULL;
			break;
		}
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_bag_get_type(bag, 0);
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		if (ret == GNUTLS_BAG_ENCRYPTED) {
			ret = gnutls_pkcs12_bag_decrypt(bag, password);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}
		}

		elements_in_bag = gnutls_pkcs12_bag_get_count(bag);
		if (elements_in_bag < 0) {
			gnutls_assert();
			goto done;
		}

		for (i = 0; i < (unsigned)elements_in_bag; i++) {
			int type;
			gnutls_datum_t data;
			gnutls_x509_crt_t this_cert;

			type = gnutls_pkcs12_bag_get_type(bag, i);
			if (type < 0) {
				gnutls_assert();
				goto done;
			}

			ret = gnutls_pkcs12_bag_get_data(bag, i, &data);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}

			switch (type) {
			case GNUTLS_BAG_CERTIFICATE:
				ret = gnutls_x509_crt_init(&this_cert);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				ret =
				    gnutls_x509_crt_import(this_cert,
							   &data,
							   GNUTLS_X509_FMT_DER);
				if (ret < 0) {
					gnutls_assert();
					gnutls_x509_crt_deinit(this_cert);
					this_cert = NULL;
					goto done;
				}

				/* check if the key id match */
				cert_id_size = sizeof(cert_id);
				ret =
				    gnutls_x509_crt_get_key_id(this_cert,
							       0, cert_id,
							       &cert_id_size);
				if (ret < 0) {
					gnutls_assert();
					gnutls_x509_crt_deinit(this_cert);
					this_cert = NULL;
					goto done;
				}

				if (memcmp(cert_id, key_id, cert_id_size) != 0) {	/* they don't match - skip the certificate */
					_extra_certs =
						gnutls_realloc_fast
						(_extra_certs,
						 sizeof(_extra_certs
							[0]) *
						 ++_extra_certs_len);
					if (!_extra_certs) {
						gnutls_assert();
						ret =
							GNUTLS_E_MEMORY_ERROR;
						goto done;
					}
					_extra_certs
						[_extra_certs_len -
						 1] = this_cert;
					this_cert = NULL;
				} else {
					if (chain && _chain_len == 0) {
						_chain =
						    gnutls_malloc(sizeof
								  (_chain
								   [0]) *
								  (++_chain_len));
						if (!_chain) {
							gnutls_assert();
							ret =
							    GNUTLS_E_MEMORY_ERROR;
							goto done;
						}
						_chain[_chain_len - 1] =
						    this_cert;
						this_cert = NULL;
					} else {
						gnutls_x509_crt_deinit
						    (this_cert);
						this_cert = NULL;
					}
				}
				break;

			case GNUTLS_BAG_CRL:
				if (crl == NULL || *crl != NULL) {
					gnutls_assert();
					break;
				}

				ret = gnutls_x509_crl_init(crl);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				ret =
				    gnutls_x509_crl_import(*crl, &data,
							   GNUTLS_X509_FMT_DER);
				if (ret < 0) {
					gnutls_assert();
					gnutls_x509_crl_deinit(*crl);
					*crl = NULL;
					goto done;
				}
				break;

			case GNUTLS_BAG_ENCRYPTED:
				/* XXX Bother to recurse one level down?  Unlikely to
				   use the same password anyway. */
			case GNUTLS_BAG_EMPTY:
			default:
				break;
			}
		}

		idx++;
		gnutls_pkcs12_bag_deinit(bag);
		bag = NULL;
	}

	if (chain != NULL) {
		if (_chain_len != 1) {
			ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
			goto done;
		}

		ret =
		    make_chain(&_chain, &_chain_len, &_extra_certs,
			       &_extra_certs_len, flags);
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}
	}

	ret = 0;

      done:
	if (bag)
		gnutls_pkcs12_bag_deinit(bag);

	if (ret < 0) {
		if (*key) {
			gnutls_x509_privkey_deinit(*key);
			*key = NULL;
		}
		if (crl != NULL && *crl != NULL) {
			gnutls_x509_crl_deinit(*crl);
			*crl = NULL;
		}
		if (_extra_certs_len && _extra_certs != NULL) {
			for (i = 0; i < _extra_certs_len; i++)
				gnutls_x509_crt_deinit(_extra_certs[i]);
			gnutls_free(_extra_certs);
		}
		if (_chain_len && _chain != NULL) {
			for (i = 0; i < _chain_len; i++)
				gnutls_x509_crt_deinit(_chain[i]);
			gnutls_free(_chain);
		}

		return ret;
	}

	if (extra_certs && _extra_certs_len > 0) {
		*extra_certs = _extra_certs;
		*extra_certs_len = _extra_certs_len;
	} else {
		if (extra_certs) {
			*extra_certs = NULL;
			*extra_certs_len = 0;
		}
		for (i = 0; i < _extra_certs_len; i++)
			gnutls_x509_crt_deinit(_extra_certs[i]);
		gnutls_free(_extra_certs);
	}

	if (chain != NULL) {
		*chain = _chain;
		*chain_len = _chain_len;
	}

	return ret;
}
Beispiel #19
0
/* Reads a base64 encoded certificate list from memory and stores it to
 * a gnutls_cert structure. Returns the number of certificate parsed.
 */
static int
parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
		    const char *input_cert, int input_cert_size)
{
  int size, siz2, i;
  const char *ptr;
  opaque *ptr2;
  gnutls_datum_t tmp;
  int ret, count;

  /* move to the certificate
   */
  ptr = memmem (input_cert, input_cert_size,
		PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1);
  if (ptr == NULL)
    ptr = memmem (input_cert, input_cert_size,
		  PEM_CERT_SEP2, sizeof (PEM_CERT_SEP2) - 1);

  if (ptr == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_BASE64_DECODING_ERROR;
    }
  size = input_cert_size - (ptr - input_cert);

  i = *ncerts + 1;
  count = 0;

  do
    {

      siz2 = _gnutls_fbase64_decode (NULL, ptr, size, &ptr2);

      if (siz2 < 0)
	{
	  gnutls_assert ();
	  return GNUTLS_E_BASE64_DECODING_ERROR;
	}

      *cert_list =
	(gnutls_cert *) gnutls_realloc_fast (*cert_list,
					     i * sizeof (gnutls_cert));

      if (*cert_list == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      tmp.data = ptr2;
      tmp.size = siz2;

      ret = _gnutls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}
      _gnutls_free_datum (&tmp);	/* free ptr2 */

      /* now we move ptr after the pem header 
       */
      ptr++;
      /* find the next certificate (if any)
       */
      size = input_cert_size - (ptr - input_cert);

      if (size > 0)
	{
	  char *ptr3;

	  ptr3 = memmem (ptr, size, PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1);
	  if (ptr3 == NULL)
	    ptr3 = memmem (ptr, size, PEM_CERT_SEP2,
			   sizeof (PEM_CERT_SEP2) - 1);

	  ptr = ptr3;
	}
      else
	ptr = NULL;

      i++;
      count++;

    }
  while (ptr != NULL);

  *ncerts = i - 1;

  return count;
}
Beispiel #20
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;
}
Beispiel #21
0
int
_gnutls_decompress (comp_hd_t handle, opaque * compressed,
                    size_t compressed_size, opaque ** plain,
                    size_t max_record_size)
{
  int plain_size = GNUTLS_E_DECOMPRESSION_FAILED;

  if (compressed_size > max_record_size + EXTRA_COMP_SIZE)
    {
      gnutls_assert ();
      return GNUTLS_E_DECOMPRESSION_FAILED;
    }

  /* NULL compression is not handled here
   */

  if (handle == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  switch (handle->algo)
    {
#ifdef USE_LZO
    case GNUTLS_COMP_LZO:
      {
        lzo_uint out_size;
        lzo_uint new_size;
        int err;

        if (_gnutls_lzo1x_decompress_safe == NULL)
          return GNUTLS_E_DECOMPRESSION_FAILED;

        *plain = NULL;
        out_size = compressed_size + compressed_size;
        plain_size = 0;

        do
          {
            out_size += 512;
            *plain = gnutls_realloc_fast (*plain, out_size);
            if (*plain == NULL)
              {
                gnutls_assert ();
                return GNUTLS_E_MEMORY_ERROR;
              }

            new_size = out_size;
            err =
              _gnutls_lzo1x_decompress_safe (compressed,
                                             compressed_size, *plain,
                                             &new_size, NULL);

          }
        while ((err == LZO_E_OUTPUT_OVERRUN && out_size < max_record_size));

        if (err != LZO_E_OK)
          {
            gnutls_assert ();
            gnutls_free (*plain);
            *plain = NULL;
            return GNUTLS_E_DECOMPRESSION_FAILED;
          }

        plain_size = new_size;
        break;
      }
#endif
#ifdef HAVE_LIBZ
    case GNUTLS_COMP_DEFLATE:
      {
        uLongf out_size;
        z_stream *zhandle;
        int cur_pos;
        int err;

        *plain = NULL;
        out_size = compressed_size + compressed_size;
        plain_size = 0;

        zhandle = handle->handle;

        zhandle->next_in = (Bytef *) compressed;
        zhandle->avail_in = compressed_size;

        cur_pos = 0;

        do
          {
            out_size += 512;
            *plain = gnutls_realloc_fast (*plain, out_size);
            if (*plain == NULL)
              {
                gnutls_assert ();
                return GNUTLS_E_MEMORY_ERROR;
              }

            zhandle->next_out = (Bytef *) (*plain + cur_pos);
            zhandle->avail_out = out_size - cur_pos;

            err = inflate (zhandle, Z_SYNC_FLUSH);

            cur_pos = out_size - zhandle->avail_out;

          }
        while ((err == Z_BUF_ERROR && zhandle->avail_out == 0
                && out_size < max_record_size)
               || (err == Z_OK && zhandle->avail_in != 0));

        if (err != Z_OK)
          {
            gnutls_assert ();
            gnutls_free (*plain);
            *plain = NULL;
            return GNUTLS_E_DECOMPRESSION_FAILED;
          }

        plain_size = out_size - zhandle->avail_out;
        break;
      }
#endif
    default:
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }                           /* switch */

  if ((size_t) plain_size > max_record_size)
    {
      gnutls_assert ();
      gnutls_free (*plain);
      *plain = NULL;
      return GNUTLS_E_DECOMPRESSION_FAILED;
    }

  return plain_size;
}
Beispiel #22
0
static int
gen_srp_cert_server_kx (gnutls_session_t session, opaque ** data)
{
  ssize_t ret, data_size;
  gnutls_datum_t signature, ddata;
  gnutls_certificate_credentials_t cred;
  gnutls_cert *apr_cert_list;
  gnutls_privkey_t apr_pkey;
  int apr_cert_list_length;
  gnutls_sign_algorithm_t sign_algo;

  ret = _gnutls_gen_srp_server_kx (session, data);

  if (ret < 0)
    return ret;

  data_size = ret;
  ddata.data = *data;
  ddata.size = data_size;

  cred = (gnutls_certificate_credentials_t)
    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
  if (cred == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  /* find the appropriate certificate */
  if ((ret =
       _gnutls_get_selected_cert (session, &apr_cert_list,
                                  &apr_cert_list_length, &apr_pkey)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  if ((ret =
       _gnutls_handshake_sign_data (session, &apr_cert_list[0],
                                    apr_pkey, &ddata, &signature,
                                    &sign_algo)) < 0)
    {
      gnutls_assert ();
      gnutls_free (*data);
      return ret;
    }

  *data = gnutls_realloc_fast (*data, data_size + signature.size + 2);
  if (*data == NULL)
    {
      _gnutls_free_datum (&signature);
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  _gnutls_write_datum16 (&(*data)[data_size], signature);
  data_size += signature.size + 2;

  _gnutls_free_datum (&signature);

  return data_size;

}
Beispiel #23
0
/* 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_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. A pointer (iptr) to this buffer is returned.
 *
 */
ssize_t
_gnutls_io_read_buffered (gnutls_session_t session, opaque ** iptr,
                          size_t sizeOfPtr, content_type_t recv_type)
{
    ssize_t ret = 0, ret2 = 0;
    size_t min;
    int buf_pos;
    opaque *buf;
    int recvlowat;
    int recvdata, alloc_size;

    *iptr = session->internals.record_recv_buffer.data;

    if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0)
    {
        gnutls_assert ();		/* internal error */
        return GNUTLS_E_INVALID_REQUEST;
    }

    /* If an external pull function is used, then do not leave
     * any data into the kernel buffer.
     */
    if (session->internals._gnutls_pull_func != NULL)
    {
        recvlowat = 0;
    }
    else
    {
        /* leave peeked data to the kernel space only if application data
         * is received and we don't have any peeked
         * data in gnutls session.
         */
        if (recv_type != GNUTLS_APPLICATION_DATA
                && session->internals.have_peeked_data == 0)
            recvlowat = 0;
        else
            recvlowat = RCVLOWAT;
    }



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

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

    /* 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.length + recvdata) >
            MAX_RECV_SIZE)
    {
        gnutls_assert ();		/* internal error */
        return GNUTLS_E_INVALID_REQUEST;
    }

    /* Allocate the data required to store the new packet.
     */
    alloc_size = recvdata + session->internals.record_recv_buffer.length;
    session->internals.record_recv_buffer.data =
        gnutls_realloc_fast (session->internals.record_recv_buffer.data,
                             alloc_size);
    if (session->internals.record_recv_buffer.data == NULL)
    {
        gnutls_assert ();
        return GNUTLS_E_MEMORY_ERROR;
    }

    buf_pos = session->internals.record_recv_buffer.length;
    buf = session->internals.record_recv_buffer.data;
    *iptr = buf;

    /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer.
     */
    if (recvdata - recvlowat > 0)
    {
        ret = _gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0);

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

    /* copy fresh data to our buffer.
     */
    if (ret > 0)
    {
        _gnutls_read_log
        ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
         session->internals.record_recv_buffer.length, ret);
        _gnutls_read_log ("RB: Requested %d bytes\n", sizeOfPtr);
        session->internals.record_recv_buffer.length += ret;
    }

    buf_pos = session->internals.record_recv_buffer.length;

    /* This is hack in order for select to work. Just leave recvlowat data,
     * into the kernel buffer (using a read with MSG_PEEK), thus making
     * select think, that the socket is ready for reading.
     * MSG_PEEK is only used with berkeley style sockets.
     */
    if (ret == (recvdata - recvlowat) && recvlowat > 0)
    {
        ret2 = _gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK);

        if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0)
        {
            return ret2;
        }

        if (ret2 > 0)
        {
            _gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n", ret2);
            _gnutls_read_log
            ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n",
             session->internals.record_recv_buffer.length, ret2, sizeOfPtr);
            session->internals.have_peeked_data = 1;
            session->internals.record_recv_buffer.length += ret2;

        }
    }

    if (ret < 0 || ret2 < 0)
    {
        gnutls_assert ();
        /* that's because they are initialized to 0 */
        return MIN (ret, ret2);
    }

    ret += ret2;

    if (ret > 0 && ret < recvlowat)
    {
        gnutls_assert ();
        return GNUTLS_E_AGAIN;
    }

    if (ret == 0)
    {   /* EOF */
        gnutls_assert ();
        return 0;
    }

    ret = session->internals.record_recv_buffer.length;

    if ((ret > 0) && ((size_t) ret < sizeOfPtr))
    {
        /* Short Read */
        gnutls_assert ();
        return GNUTLS_E_AGAIN;
    }
    else
    {
        return ret;
    }
}
Beispiel #24
0
/**
 * gnutls_certificate_set_x509_key:
 * @res: is a #gnutls_certificate_credentials_t structure.
 * @cert_list: contains a certificate list (path) for the specified private key
 * @cert_list_size: holds the size of the certificate list
 * @key: is a gnutls_x509_privkey_t key
 *
 * This function sets a certificate/private key pair in the
 * gnutls_certificate_credentials_t structure.  This function may be
 * called more than once (in case multiple keys/certificates exist for
 * the server).  For clients that wants to send more than its own end
 * entity certificate (e.g., also an intermediate CA cert) then put
 * the certificate chain in @cert_list.
 *
 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
 *
 * Since: 2.4.0
 **/
int
gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res,
				 gnutls_x509_crt_t * cert_list,
				 int cert_list_size,
				 gnutls_x509_privkey_t key)
{
  int ret, i;

  /* this should be first
   */

  res->pkey =
    gnutls_realloc_fast (res->pkey,
			 (res->ncerts + 1) * sizeof (gnutls_privkey));
  if (res->pkey == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  ret = _gnutls_x509_privkey_to_gkey (&res->pkey[res->ncerts], key);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  res->cert_list = gnutls_realloc_fast (res->cert_list,
					(1 +
					 res->ncerts) *
					sizeof (gnutls_cert *));
  if (res->cert_list == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
					       (1 +
						res->ncerts) * sizeof (int));
  if (res->cert_list_length == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list[res->ncerts] = NULL;	/* for realloc */
  res->cert_list_length[res->ncerts] = 0;


  for (i = 0; i < cert_list_size; i++)
    {
      ret = parse_crt_mem (&res->cert_list[res->ncerts],
			   &res->cert_list_length[res->ncerts], cert_list[i]);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}
    }
  res->ncerts++;

  if ((ret = _gnutls_check_key_cert_match (res)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  return 0;
}
Beispiel #25
0
static int
gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data)
{
  gnutls_rsa_params_t rsa_params;
  const bigint_t *rsa_mpis;
  size_t n_e, n_m;
  uint8_t *data_e, *data_m;
  int ret = 0, data_size;
  gnutls_cert *apr_cert_list;
  gnutls_privkey *apr_pkey;
  int apr_cert_list_length;
  gnutls_datum_t signature, ddata;
  cert_auth_info_t info;
  gnutls_certificate_credentials_t cred;

  cred = (gnutls_certificate_credentials_t)
    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
  if (cred == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

  /* find the appropriate certificate */
  if ((ret =
       _gnutls_get_selected_cert (session, &apr_cert_list,
				  &apr_cert_list_length, &apr_pkey)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  /* abort sending this message if we have a certificate
   * of 512 bits or less.
   */
  if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512)
    {
      gnutls_assert ();
      return GNUTLS_E_INT_RET_0;
    }

  rsa_params =
    _gnutls_certificate_get_rsa_params (cred->rsa_params, cred->params_func,
					session);
  rsa_mpis = _gnutls_rsa_params_to_mpi (rsa_params);
  if (rsa_mpis == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
    }

  if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE,
				    sizeof (cert_auth_info_st), 0)) < 0)
    {
      gnutls_assert ();
      return ret;
    }

  info = _gnutls_get_auth_info (session);
  _gnutls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]);

  _gnutls_mpi_print (rsa_mpis[0], NULL, &n_m);
  _gnutls_mpi_print (rsa_mpis[1], NULL, &n_e);

  (*data) = gnutls_malloc (n_e + n_m + 4);
  if (*data == NULL)
    {
      return GNUTLS_E_MEMORY_ERROR;
    }

  data_m = &(*data)[0];
  _gnutls_mpi_print (rsa_mpis[0], &data_m[2], &n_m);

  _gnutls_write_uint16 (n_m, data_m);

  data_e = &data_m[2 + n_m];
  _gnutls_mpi_print (rsa_mpis[1], &data_e[2], &n_e);

  _gnutls_write_uint16 (n_e, data_e);

  data_size = n_m + n_e + 4;


  /* Generate the signature. */

  ddata.data = *data;
  ddata.size = data_size;

  if (apr_cert_list_length > 0)
    {
      if ((ret =
	   _gnutls_tls_sign_params (session, &apr_cert_list[0],
				    apr_pkey, &ddata, &signature)) < 0)
	{
	  gnutls_assert ();
	  gnutls_free (*data);
	  *data = NULL;
	  return ret;
	}
    }
  else
    {
      gnutls_assert ();
      return data_size;		/* do not put a signature - ILLEGAL! */
    }

  *data = gnutls_realloc_fast (*data, data_size + signature.size + 2);
  if (*data == NULL)
    {
      _gnutls_free_datum (&signature);
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  _gnutls_write_datum16 (&((*data)[data_size]), signature);
  data_size += signature.size + 2;

  _gnutls_free_datum (&signature);

  return data_size;
}
Beispiel #26
0
/**
 * gnutls_certificate_set_openpgp_key - Used to set keys in a gnutls_certificate_credentials_t structure
 * @res: is a #gnutls_certificate_credentials_t structure.
 * @key: contains an openpgp public key
 * @pkey: is an openpgp private key
 *
 * This function sets a certificate/private key pair in the
 * gnutls_certificate_credentials_t structure.  This function may be
 * called more than once (in case multiple keys/certificates exist
 * for the server).
 *
 * With this function the subkeys of the certificate are not used.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
 *   otherwise an error code is returned.
 **/
int
gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
				    gnutls_openpgp_crt_t crt,
				    gnutls_openpgp_privkey_t pkey)
{
  int ret;

  /* this should be first */

  res->pkey = gnutls_realloc_fast (res->pkey,
				   (res->ncerts + 1) *
				   sizeof (gnutls_privkey));
  if (res->pkey == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  ret = _gnutls_openpgp_privkey_to_gkey (&res->pkey[res->ncerts], pkey);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  res->cert_list = gnutls_realloc_fast (res->cert_list,
					(1 +
					 res->ncerts) *
					sizeof (gnutls_cert *));
  if (res->cert_list == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
					       (1 +
						res->ncerts) * sizeof (int));
  if (res->cert_list_length == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list[res->ncerts] = gnutls_calloc (1, sizeof (gnutls_cert));
  if (res->cert_list[res->ncerts] == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  res->cert_list_length[res->ncerts] = 1;

  ret = _gnutls_openpgp_crt_to_gcert (res->cert_list[res->ncerts], crt);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  res->ncerts++;

  /* FIXME: Check if the keys match. */

  return 0;
}
Beispiel #27
0
/**
 * gnutls_x509_trust_list_add_cas:
 * @list: The structure of the list
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
 * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options.
 *
 * This function will add the given certificate authorities
 * to the trusted list. The list of CAs must not be deinitialized
 * during this structure's lifetime.
 *
 * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then
 * the provided @clist entries that are duplicates will not be
 * added to the list and will be deinitialized.
 *
 * Returns: The number of added elements is returned.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
			       const gnutls_x509_crt_t * clist,
			       unsigned clist_size, unsigned int flags)
{
	unsigned i, j;
	uint32_t hash;
	int ret;
	unsigned exists;

	for (i = 0; i < clist_size; i++) {
		exists = 0;
		hash =
		    hash_pjw_bare(clist[i]->raw_dn.data,
				  clist[i]->raw_dn.size);
		hash %= list->size;

		/* avoid duplicates */
		if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) {
			for (j=0;j<list->node[hash].trusted_ca_size;j++) {
				if (flags & GNUTLS_TL_NO_DUPLICATES)
					ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]);
				else
					ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1);
				if (ret != 0) {
					exists = 1;
					break;
				}
			}

			if (exists != 0) {
				gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]);
				list->node[hash].trusted_cas[j] = clist[i];
				continue;
			}
		}

		list->node[hash].trusted_cas =
		    gnutls_realloc_fast(list->node[hash].trusted_cas,
					(list->node[hash].trusted_ca_size +
					 1) *
					sizeof(list->node[hash].
					       trusted_cas[0]));
		if (list->node[hash].trusted_cas == NULL) {
			gnutls_assert();
			return i;
		}

		if (gnutls_x509_crt_get_version(clist[i]) >= 3 &&
		    gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) {
			gnutls_datum_t dn;
			gnutls_assert();
			if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) {
				_gnutls_audit_log(NULL,
					  "There was a non-CA certificate in the trusted list: %s.\n",
					  dn.data);
				gnutls_free(dn.data);
			}
		}

		list->node[hash].trusted_cas[list->node[hash].
					     trusted_ca_size] = clist[i];
		list->node[hash].trusted_ca_size++;

		if (flags & GNUTLS_TL_USE_IN_TLS) {
			ret = add_new_ca_to_rdn_seq(list, clist[i]);
			if (ret < 0) {
				gnutls_assert();
				return i;
			}
		}
	}

	return i;
}
Beispiel #28
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;
}
Beispiel #29
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,
                               content_type_t type,
                               gnutls_handshake_description_t htype,
                               void *iptr, size_t sizeOfPtr)
{
    size_t left;
    ssize_t i;
    opaque *ptr;
    size_t dsize;

    ptr = iptr;
    left = sizeOfPtr;

    if (sizeOfPtr == 0 || iptr == NULL)
    {
        gnutls_assert ();
        return GNUTLS_E_INVALID_REQUEST;
    }

    if (session->internals.handshake_recv_buffer.length > 0)
    {
        /* if we have already received some data */
        if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
        {
            /* if requested less data then return it.
             */
            gnutls_assert ();
            memcpy (iptr, session->internals.handshake_recv_buffer.data,
                    sizeOfPtr);

            session->internals.handshake_recv_buffer.length -= sizeOfPtr;

            memmove (session->internals.handshake_recv_buffer.data,
                     &session->internals.handshake_recv_buffer.
                     data[sizeOfPtr],
                     session->internals.handshake_recv_buffer.length);

            return sizeOfPtr;
        }
        gnutls_assert ();
        memcpy (iptr, session->internals.handshake_recv_buffer.data,
                session->internals.handshake_recv_buffer.length);

        htype = session->internals.handshake_recv_buffer_htype;
        type = session->internals.handshake_recv_buffer_type;

        left -= session->internals.handshake_recv_buffer.length;

        session->internals.handshake_recv_buffer.length = 0;
    }

    while (left > 0)
    {
        dsize = sizeOfPtr - left;
        i = _gnutls_recv_int (session, type, htype, &ptr[dsize], left);
        if (i < 0)
        {

            if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN))
            {
                gnutls_assert ();

                session->internals.handshake_recv_buffer.data =
                    gnutls_realloc_fast (session->internals.
                                         handshake_recv_buffer.data, dsize);
                if (session->internals.handshake_recv_buffer.data == NULL)
                {
                    gnutls_assert ();
                    return GNUTLS_E_MEMORY_ERROR;
                }

                memcpy (session->internals.handshake_recv_buffer.data, iptr,
                        dsize);

                session->internals.handshake_recv_buffer_htype = htype;
                session->internals.handshake_recv_buffer_type = type;

                session->internals.handshake_recv_buffer.length = dsize;
            }
            else
                session->internals.handshake_recv_buffer.length = 0;

            gnutls_assert ();

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

        left -= i;

    }

    session->internals.handshake_recv_buffer.length = 0;

    return sizeOfPtr - left;
}