Exemple #1
0
/* A generic export function. Will export the given ASN.1 encoded data
 * to PEM or DER raw data.
 */
int
_gnutls_x509_export_int_named2(ASN1_TYPE asn1_data, const char *name,
			       gnutls_x509_crt_fmt_t format,
			       const char *pem_header,
			       gnutls_datum_t * out)
{
	int ret;

	if (format == GNUTLS_X509_FMT_DER) {
		ret = _gnutls_x509_der_encode(asn1_data, name, out, 0);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else {		/* PEM */
		gnutls_datum_t tmp;

		ret = _gnutls_x509_der_encode(asn1_data, name, &tmp, 0);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret =
		    _gnutls_fbase64_encode(pem_header, tmp.data, tmp.size,
					   out);
		_gnutls_free_datum(&tmp);

		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	return 0;
}
Exemple #2
0
/**
 * gnutls_pem_base64_encode:
 * @msg: is a message to be put in the header
 * @data: contain the raw data
 * @result: the place where base64 data will be copied
 * @result_size: holds the size of the result
 *
 * This function will convert the given data to printable data, using
 * the base64 encoding. This is the encoding used in PEM messages.
 *
 * The output string will be null terminated, although the size will
 * not include the terminating null.
 *
 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
 *   %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
 *   not long enough, or 0 on success.
 **/
int
gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
                          char *result, size_t * result_size)
{
  gnutls_datum_t res;
  int ret;

  ret = _gnutls_fbase64_encode (msg, data->data, data->size, &res);
  if (ret < 0)
    return ret;

  if (result == NULL || *result_size < (unsigned) res.size)
    {
      gnutls_free (res.data);
      *result_size = res.size + 1;
      return GNUTLS_E_SHORT_MEMORY_BUFFER;
    }
  else
    {
      memcpy (result, res.data, res.size);
      gnutls_free (res.data);
      *result_size = res.size;
    }

  return 0;
}
Exemple #3
0
/**
 * gnutls_pem_base64_encode_alloc:
 * @msg: is a message to be put in the encoded header
 * @data: contains the raw data
 * @result: will hold the newly allocated encoded data
 *
 * This function will convert the given data to printable data, using
 * the base64 encoding.  This is the encoding used in PEM messages.
 * This function will allocate the required memory to hold the encoded
 * data.
 *
 * You should use gnutls_free() to free the returned data.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
 *   an error code is returned.
 **/
int
gnutls_pem_base64_encode_alloc (const char *msg,
                                const gnutls_datum_t * data,
                                gnutls_datum_t * result)
{
  int ret;

  if (result == NULL)
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

  ret = _gnutls_fbase64_encode (msg, data->data, data->size, result);
  if (ret < 0)
    return gnutls_assert_val(ret);

  return 0;
}
Exemple #4
0
/**
 * gnutls_dh_params_export_pkcs3 - export DH params to a pkcs3 structure
 * @params: Holds the DH parameters
 * @format: the format of output params. One of PEM or DER.
 * @params_data: will contain a PKCS3 DHParams structure PEM or DER encoded
 * @params_data_size: holds the size of params_data (and will be replaced by the actual size of parameters)
 *
 * This function will export the given dh parameters to a PKCS3
 * DHParams structure. This is the format generated by "openssl dhparam" tool.
 * If the buffer provided is not long enough to hold the output, then
 * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
 *
 * If the structure is PEM encoded, it will have a header
 * of "BEGIN DH PARAMETERS".
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
 *   otherwise an error code is returned.
 **/
int
gnutls_dh_params_export_pkcs3 (gnutls_dh_params_t params,
                               gnutls_x509_crt_fmt_t format,
                               unsigned char *params_data,
                               size_t * params_data_size)
{
    ASN1_TYPE c2;
    int result, _params_data_size;
    size_t g_size, p_size;
    opaque *p_data, *g_data;
    opaque *all_data;

    _gnutls_mpi_print_lz (params->params[1], NULL, &g_size);
    _gnutls_mpi_print_lz (params->params[0], NULL, &p_size);

    all_data = gnutls_malloc (g_size + p_size);
    if (all_data == NULL)
    {
        gnutls_assert ();
        return GNUTLS_E_MEMORY_ERROR;
    }

    p_data = &all_data[0];
    g_data = &all_data[p_size];

    _gnutls_mpi_print_lz (params->params[0], p_data, &p_size);
    _gnutls_mpi_print_lz (params->params[1], g_data, &g_size);

    /* Ok. Now we have the data. Create the asn1 structures
     */

    if ((result = asn1_create_element
                  (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2))
            != ASN1_SUCCESS)
    {
        gnutls_assert ();
        gnutls_free (all_data);
        return _gnutls_asn2err (result);
    }

    /* Write PRIME
     */
    if ((result = asn1_write_value (c2, "prime",
                                    p_data, p_size)) != ASN1_SUCCESS)
    {
        gnutls_assert ();
        gnutls_free (all_data);
        asn1_delete_structure (&c2);
        return _gnutls_asn2err (result);
    }

    /* Write the GENERATOR
     */
    if ((result = asn1_write_value (c2, "base",
                                    g_data, g_size)) != ASN1_SUCCESS)
    {
        gnutls_assert ();
        gnutls_free (all_data);
        asn1_delete_structure (&c2);
        return _gnutls_asn2err (result);
    }

    gnutls_free (all_data);

    if ((result = asn1_write_value (c2, "privateValueLength",
                                    NULL, 0)) != ASN1_SUCCESS)
    {
        gnutls_assert ();
        asn1_delete_structure (&c2);
        return _gnutls_asn2err (result);
    }

    if (format == GNUTLS_X509_FMT_DER)
    {
        if (params_data == NULL)
            *params_data_size = 0;

        _params_data_size = *params_data_size;
        result =
            asn1_der_coding (c2, "", params_data, &_params_data_size, NULL);
        *params_data_size = _params_data_size;
        asn1_delete_structure (&c2);

        if (result != ASN1_SUCCESS)
        {
            gnutls_assert ();
            if (result == ASN1_MEM_ERROR)
                return GNUTLS_E_SHORT_MEMORY_BUFFER;

            return _gnutls_asn2err (result);
        }

    }
    else
    {   /* PEM */
        opaque *tmp;
        opaque *out;
        int len;

        len = 0;
        asn1_der_coding (c2, "", NULL, &len, NULL);

        tmp = gnutls_malloc (len);
        if (tmp == NULL)
        {
            gnutls_assert ();
            asn1_delete_structure (&c2);
            return GNUTLS_E_MEMORY_ERROR;
        }

        if ((result =
                    asn1_der_coding (c2, "", tmp, &len, NULL)) != ASN1_SUCCESS)
        {
            gnutls_assert ();
            gnutls_free (tmp);
            asn1_delete_structure (&c2);
            return _gnutls_asn2err (result);
        }

        asn1_delete_structure (&c2);

        result = _gnutls_fbase64_encode ("DH PARAMETERS", tmp, len, &out);

        gnutls_free (tmp);

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

        if (result == 0)
        {   /* oooops */
            gnutls_assert ();
            gnutls_free (out);
            return GNUTLS_E_INTERNAL_ERROR;
        }

        if ((unsigned) result > *params_data_size)
        {
            gnutls_assert ();
            gnutls_free (out);
            *params_data_size = result;
            return GNUTLS_E_SHORT_MEMORY_BUFFER;
        }

        *params_data_size = result - 1;

        if (params_data)
            memcpy (params_data, out, result);

        gnutls_free (out);

    }

    return 0;
}
Exemple #5
0
/* A generic export function. Will export the given ASN.1 encoded data
 * to PEM or DER raw data.
 */
int
_gnutls_x509_export_int_named (ASN1_TYPE asn1_data, const char *name,
                               gnutls_x509_crt_fmt_t format,
                               const char *pem_header,
                               unsigned char *output_data,
                               size_t * output_data_size)
{
  int result, len;

  if (format == GNUTLS_X509_FMT_DER)
    {

      if (output_data == NULL)
        *output_data_size = 0;

      len = *output_data_size;

      if ((result =
           asn1_der_coding (asn1_data, name, output_data, &len,
                            NULL)) != ASN1_SUCCESS)
        {
          *output_data_size = len;
          if (result == ASN1_MEM_ERROR)
            {
              return GNUTLS_E_SHORT_MEMORY_BUFFER;
            }
          gnutls_assert ();
          return _gnutls_asn2err (result);
        }

      *output_data_size = len;

    }
  else
    {                           /* PEM */
      opaque *out;
      gnutls_datum_t tmp;

      result = _gnutls_x509_der_encode (asn1_data, name, &tmp, 0);
      if (result < 0)
        {
          gnutls_assert ();
          return result;
        }

      result = _gnutls_fbase64_encode (pem_header, tmp.data, tmp.size, &out);

      _gnutls_free_datum (&tmp);

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

      if (result == 0)
        {                       /* oooops */
          gnutls_assert ();
          return GNUTLS_E_INTERNAL_ERROR;
        }

      if ((unsigned) result > *output_data_size)
        {
          gnutls_assert ();
          gnutls_free (out);
          *output_data_size = result;
          return GNUTLS_E_SHORT_MEMORY_BUFFER;
        }

      *output_data_size = result;

      if (output_data)
        {
          memcpy (output_data, out, result);

          /* do not include the null character into output size.
           */
          *output_data_size = result - 1;
        }
      gnutls_free (out);

    }

  return 0;
}
Exemple #6
0
/**
 * gnutls_dh_params_export2_pkcs3:
 * @params: Holds the DH parameters
 * @format: the format of output params. One of PEM or DER.
 * @out: will contain a PKCS3 DHParams structure PEM or DER encoded
 *
 * This function will export the given dh parameters to a PKCS3
 * DHParams structure. This is the format generated by "openssl dhparam" tool.
 * The data in @out will be allocated using gnutls_malloc().
 *
 * If the structure is PEM encoded, it will have a header
 * of "BEGIN DH PARAMETERS".
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
 *   otherwise a negative error code is returned.
 *
 * Since: 3.1.3
 **/
int
gnutls_dh_params_export2_pkcs3(gnutls_dh_params_t params,
			       gnutls_x509_crt_fmt_t format,
			       gnutls_datum_t * out)
{
	ASN1_TYPE c2;
	int result;
	size_t g_size, p_size;
	uint8_t *p_data, *g_data;
	uint8_t *all_data;

	_gnutls_mpi_print_lz(params->params[1], NULL, &g_size);
	_gnutls_mpi_print_lz(params->params[0], NULL, &p_size);

	all_data = gnutls_malloc(g_size + p_size);
	if (all_data == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	p_data = &all_data[0];
	_gnutls_mpi_print_lz(params->params[0], p_data, &p_size);

	g_data = &all_data[p_size];
	_gnutls_mpi_print_lz(params->params[1], g_data, &g_size);


	/* Ok. Now we have the data. Create the asn1 structures
	 */

	if ((result = asn1_create_element
	     (_gnutls_get_gnutls_asn(), "GNUTLS.DHParameter", &c2))
	    != ASN1_SUCCESS) {
		gnutls_assert();
		gnutls_free(all_data);
		return _gnutls_asn2err(result);
	}

	/* Write PRIME 
	 */
	if ((result = asn1_write_value(c2, "prime",
				       p_data, p_size)) != ASN1_SUCCESS) {
		gnutls_assert();
		gnutls_free(all_data);
		asn1_delete_structure(&c2);
		return _gnutls_asn2err(result);
	}

	if (params->q_bits > 0)
		result =
		    _gnutls_x509_write_uint32(c2, "privateValueLength",
					      params->q_bits);
	else
		result =
		    asn1_write_value(c2, "privateValueLength", NULL, 0);

	if (result < 0) {
		gnutls_assert();
		gnutls_free(all_data);
		asn1_delete_structure(&c2);
		return _gnutls_asn2err(result);
	}

	/* Write the GENERATOR
	 */
	if ((result = asn1_write_value(c2, "base",
				       g_data, g_size)) != ASN1_SUCCESS) {
		gnutls_assert();
		gnutls_free(all_data);
		asn1_delete_structure(&c2);
		return _gnutls_asn2err(result);
	}

	gnutls_free(all_data);


	if (format == GNUTLS_X509_FMT_DER) {
		result = _gnutls_x509_der_encode(c2, "", out, 0);

		asn1_delete_structure(&c2);

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

	} else {		/* PEM */
		gnutls_datum_t t;

		result = _gnutls_x509_der_encode(c2, "", &t, 0);

		asn1_delete_structure(&c2);

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

		result =
		    _gnutls_fbase64_encode("DH PARAMETERS", t.data, t.size,
					   out);

		gnutls_free(t.data);

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

	return 0;
}
Exemple #7
0
/**
 * gnutls_tpm_privkey_generate:
 * @pk: the public key algorithm
 * @bits: the security bits
 * @srk_password: a password to protect the exported key (optional)
 * @key_password: the password for the TPM (optional)
 * @format: the format of the private key
 * @pub_format: the format of the public key
 * @privkey: the generated key
 * @pubkey: the corresponding public key (may be null)
 * @flags: should be a list of GNUTLS_TPM_* flags
 *
 * This function will generate a private key in the TPM
 * chip. The private key will be generated within the chip
 * and will be exported in a wrapped with TPM's master key
 * form. Furthermore the wrapped key can be protected with
 * the provided @password.
 *
 * Note that bits in TPM is quantized value. If the input value
 * is not one of the allowed values, then it will be quantized to
 * one of 512, 1024, 2048, 4096, 8192 and 16384.
 *
 * Allowed flags are:
 *
 * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy,

 * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that
 * case @privkey would contain a URL with the UUID.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.1.0
 **/
int
gnutls_tpm_privkey_generate(gnutls_pk_algorithm_t pk, unsigned int bits,
			    const char *srk_password,
			    const char *key_password,
			    gnutls_tpmkey_fmt_t format,
			    gnutls_x509_crt_fmt_t pub_format,
			    gnutls_datum_t * privkey,
			    gnutls_datum_t * pubkey, unsigned int flags)
{
	TSS_FLAG tpm_flags = TSS_KEY_VOLATILE;
	TSS_HKEY key_ctx;
	TSS_RESULT tssret;
	int ret;
	void *tdata;
	UINT32 tint;
	gnutls_datum_t tmpkey = { NULL, 0 };
	TSS_HPOLICY key_policy;
	gnutls_pubkey_t pub;
	struct tpm_ctx_st s;
	TSS_FLAG storage_type;
	TSS_HTPM htpm;
	uint8_t buf[32];

	if (flags & GNUTLS_TPM_KEY_SIGNING)
		tpm_flags |= TSS_KEY_TYPE_SIGNING;
	else
		tpm_flags |= TSS_KEY_TYPE_LEGACY;

	if (flags & GNUTLS_TPM_KEY_USER)
		storage_type = TSS_PS_TYPE_USER;
	else
		storage_type = TSS_PS_TYPE_SYSTEM;

	if (bits <= 512)
		tpm_flags |= TSS_KEY_SIZE_512;
	else if (bits <= 1024)
		tpm_flags |= TSS_KEY_SIZE_1024;
	else if (bits <= 2048)
		tpm_flags |= TSS_KEY_SIZE_2048;
	else if (bits <= 4096)
		tpm_flags |= TSS_KEY_SIZE_4096;
	else if (bits <= 8192)
		tpm_flags |= TSS_KEY_SIZE_8192;
	else
		tpm_flags |= TSS_KEY_SIZE_16384;

	ret = tpm_open_session(&s, srk_password);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* put some randomness into TPM. 
	 * Let's not trust it completely.
	 */
	tssret = Tspi_Context_GetTpmObject(s.tpm_ctx, &htpm);
	if (tssret != 0) {
		gnutls_assert();
		ret = tss_err(tssret);
		goto err_cc;
	}


	ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf));
	if (ret < 0) {
		gnutls_assert();
		goto err_cc;
	}

	tssret = Tspi_TPM_StirRandom(htpm, sizeof(buf), buf);
	if (tssret) {
		gnutls_assert();
	}

	tssret =
	    Tspi_Context_CreateObject(s.tpm_ctx, TSS_OBJECT_TYPE_RSAKEY,
				      tpm_flags, &key_ctx);
	if (tssret != 0) {
		gnutls_assert();
		ret = tss_err(tssret);
		goto err_cc;
	}

	tssret =
	    Tspi_SetAttribUint32(key_ctx, TSS_TSPATTRIB_KEY_INFO,
				 TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
				 TSS_SS_RSASSAPKCS1V15_DER);
	if (tssret != 0) {
		gnutls_assert();
		ret = tss_err(tssret);
		goto err_sa;
	}

	/* set the password of the actual key */
	if (key_password) {
		tssret =
		    Tspi_GetPolicyObject(key_ctx, TSS_POLICY_USAGE,
					 &key_policy);
		if (tssret != 0) {
			gnutls_assert();
			ret = tss_err(tssret);
			goto err_sa;
		}

		tssret = myTspi_Policy_SetSecret(key_policy,
						 SAFE_LEN(key_password),
						 (void *) key_password);
		if (tssret != 0) {
			gnutls_assert();
			ret = tss_err(tssret);
			goto err_sa;
		}
	}

	tssret = Tspi_Key_CreateKey(key_ctx, s.srk, 0);
	if (tssret != 0) {
		gnutls_assert();
		ret = tss_err(tssret);
		goto err_sa;
	}

	if (flags & GNUTLS_TPM_REGISTER_KEY) {
		TSS_UUID key_uuid;

		ret = randomize_uuid(&key_uuid);
		if (ret < 0) {
			gnutls_assert();
			goto err_sa;
		}

		tssret =
		    Tspi_Context_RegisterKey(s.tpm_ctx, key_ctx,
					     storage_type, key_uuid,
					     TSS_PS_TYPE_SYSTEM, srk_uuid);
		if (tssret != 0) {
			gnutls_assert();
			ret = tss_err(tssret);
			goto err_sa;
		}

		ret =
		    encode_tpmkey_url((char **) &privkey->data, &key_uuid,
				      storage_type);
		if (ret < 0) {
			TSS_HKEY tkey;

			Tspi_Context_UnregisterKey(s.tpm_ctx, storage_type,
						   key_uuid, &tkey);
			gnutls_assert();
			goto err_sa;
		}
		privkey->size = strlen((char *) privkey->data);

	} else {		/* get the key as blob */


		tssret =
		    Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_KEY_BLOB,
				       TSS_TSPATTRIB_KEYBLOB_BLOB, &tint,
				       (void *) &tdata);
		if (tssret != 0) {
			gnutls_assert();
			ret = tss_err(tssret);
			goto err_sa;
		}


		if (format == GNUTLS_TPMKEY_FMT_CTK_PEM) {
			ret =
			    _gnutls_x509_encode_string
			    (ASN1_ETYPE_OCTET_STRING, tdata, tint,
			     &tmpkey);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

			ret =
			    _gnutls_fbase64_encode("TSS KEY BLOB",
						   tmpkey.data,
						   tmpkey.size, privkey);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}
		} else {
			UINT32 tint2;

			tmpkey.size = tint + 32;	/* spec says no more than 20 */
			tmpkey.data = gnutls_malloc(tmpkey.size);
			if (tmpkey.data == NULL) {
				gnutls_assert();
				ret = GNUTLS_E_MEMORY_ERROR;
				goto cleanup;
			}

			tint2 = tmpkey.size;
			tssret =
			    Tspi_EncodeDER_TssBlob(tint, tdata,
						   TSS_BLOB_TYPE_PRIVATEKEY,
						   &tint2, tmpkey.data);
			if (tssret != 0) {
				gnutls_assert();
				ret = tss_err(tssret);
				goto cleanup;
			}

			tmpkey.size = tint2;

			privkey->data = tmpkey.data;
			privkey->size = tmpkey.size;
			tmpkey.data = NULL;
		}
	}

	/* read the public key */
	if (pubkey != NULL) {
		size_t psize;

		ret = gnutls_pubkey_init(&pub);
		if (ret < 0) {
			gnutls_assert();
			goto privkey_cleanup;
		}

		ret = read_pubkey(pub, key_ctx, &psize);
		if (ret < 0) {
			gnutls_assert();
			goto privkey_cleanup;
		}
		psize += 512;

		pubkey->data = gnutls_malloc(psize);
		if (pubkey->data == NULL) {
			gnutls_assert();
			ret = GNUTLS_E_MEMORY_ERROR;
			goto pubkey_cleanup;
		}

		ret =
		    gnutls_pubkey_export(pub, pub_format, pubkey->data,
					 &psize);
		if (ret < 0) {
			gnutls_assert();
			goto pubkey_cleanup;
		}
		pubkey->size = psize;

		gnutls_pubkey_deinit(pub);
	}

	ret = 0;
	goto cleanup;

      pubkey_cleanup:
	gnutls_pubkey_deinit(pub);
      privkey_cleanup:
	gnutls_free(privkey->data);
	privkey->data = NULL;
      cleanup:
	gnutls_free(tmpkey.data);
	tmpkey.data = NULL;
      err_sa:
	Tspi_Context_CloseObject(s.tpm_ctx, key_ctx);
      err_cc:
	tpm_close_session(&s);
	return ret;
}
Exemple #8
0
/* A generic export function. Will export the given ASN.1 encoded data
 * to PEM or DER raw data.
 */
int
_gnutls_x509_export_int (ASN1_TYPE asn1_data,
			 gnutls_x509_crt_fmt_t format, char *pem_header,
			 int tmp_buf_size, unsigned char *output_data,
			 size_t * output_data_size)
{
  int result, len;
  if (tmp_buf_size == 0)
    tmp_buf_size = 16 * 1024;

  if (format == GNUTLS_X509_FMT_DER)
    {

      if (output_data == NULL)
	*output_data_size = 0;

      len = *output_data_size;

      if ((result =
	   asn1_der_coding (asn1_data, "", output_data, &len,
			    NULL)) != ASN1_SUCCESS)
	{
	  *output_data_size = len;
	  if (result == ASN1_MEM_ERROR)
	    {
	      return GNUTLS_E_SHORT_MEMORY_BUFFER;
	    }
	  gnutls_assert ();
	  return _gnutls_asn2err (result);
	}

      *output_data_size = len;

    }
  else
    {				/* PEM */
      opaque *tmp;
      opaque *out;

      len = tmp_buf_size;

      tmp = gnutls_alloca (len);
      if (tmp == NULL)
	{
	  gnutls_assert ();
	  return GNUTLS_E_MEMORY_ERROR;
	}

      if ((result =
	   asn1_der_coding (asn1_data, "", tmp, &len, NULL)) != ASN1_SUCCESS)
	{
	  gnutls_assert ();
	  if (result == ASN1_MEM_ERROR)
	    {
	      *output_data_size = B64FSIZE (strlen (pem_header), len) + 1;
	    }
	  gnutls_afree (tmp);
	  return _gnutls_asn2err (result);
	}

      result = _gnutls_fbase64_encode (pem_header, tmp, len, &out);

      gnutls_afree (tmp);

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

      if (result == 0)
	{			/* oooops */
	  gnutls_assert ();
	  return GNUTLS_E_INTERNAL_ERROR;
	}

      if ((unsigned) result > *output_data_size)
	{
	  gnutls_assert ();
	  gnutls_free (out);
	  *output_data_size = result;
	  return GNUTLS_E_SHORT_MEMORY_BUFFER;
	}

      *output_data_size = result;

      if (output_data)
	{
	  memcpy (output_data, out, result);

	  /* do not include the null character into output size.
	   */
	  *output_data_size = result - 1;
	}
      gnutls_free (out);

    }

  return 0;
}