/**
 * gnutls_x509_privkey_import:
 * @key: The structure to store the parsed key
 * @data: The DER or PEM encoded certificate.
 * @format: One of DER or PEM
 *
 * This function will convert the given DER or PEM encoded key to the
 * native #gnutls_x509_privkey_t format. The output will be stored in
 * @key .
 *
 * If the key is PEM encoded it should have a header that contains "PRIVATE
 * KEY". Note that this function falls back to PKCS #8 decoding without
 * password, if the default format fails to import.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_x509_privkey_import (gnutls_x509_privkey_t key,
                            const gnutls_datum_t * data,
                            gnutls_x509_crt_fmt_t format)
{
  int result = 0, need_free = 0;
  gnutls_datum_t _data;

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

  _data.data = data->data;
  _data.size = data->size;

  key->pk_algorithm = GNUTLS_PK_UNKNOWN;

  /* If the Certificate is in PEM format then decode it
   */
  if (format == GNUTLS_X509_FMT_PEM)
    {
      uint8_t *out;

      /* Try the first header */
      result =
        _gnutls_fbase64_decode (PEM_KEY_RSA, data->data, data->size, &out);

      if (result >= 0)
        key->pk_algorithm = GNUTLS_PK_RSA;

      if (result == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
        {
          /* try for the second header */
          result =
            _gnutls_fbase64_decode (PEM_KEY_DSA, data->data, data->size,
                                    &out);

          if (result >= 0)
            key->pk_algorithm = GNUTLS_PK_DSA;

          if (result == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
            {
              /* try for the second header */
              result =
                _gnutls_fbase64_decode (PEM_KEY_ECC, data->data, data->size,
                                    &out);
              if (result >= 0)
                key->pk_algorithm = GNUTLS_PK_EC;
             }
        }

      if (result < 0)
        {
          gnutls_assert ();
          goto failover;
        }

      _data.data = out;
      _data.size = result;

      need_free = 1;
    }

  if (key->pk_algorithm == GNUTLS_PK_RSA)
    {
      key->key = _gnutls_privkey_decode_pkcs1_rsa_key (&_data, key);
      if (key->key == NULL)
        gnutls_assert ();
    }
  else if (key->pk_algorithm == GNUTLS_PK_DSA)
    {
      key->key = decode_dsa_key (&_data, key);
      if (key->key == NULL)
        gnutls_assert ();
    }
  else if (key->pk_algorithm == GNUTLS_PK_EC)
    {
      key->key = _gnutls_privkey_decode_ecc_key (&_data, key);
      if (key->key == NULL)
        gnutls_assert ();
    }
  else
    {
      /* Try decoding with both, and accept the one that
       * succeeds.
       */
      key->pk_algorithm = GNUTLS_PK_RSA;
      key->key = _gnutls_privkey_decode_pkcs1_rsa_key (&_data, key);

      if (key->key == NULL)
        {
          key->pk_algorithm = GNUTLS_PK_DSA;
          key->key = decode_dsa_key (&_data, key);
          if (key->key == NULL)
            {
              key->pk_algorithm = GNUTLS_PK_EC;
              key->key = _gnutls_privkey_decode_ecc_key (&_data, key);
              if (key->key == NULL)
                gnutls_assert ();
            }
        }
    }

  if (key->key == NULL)
    {
      gnutls_assert ();
      result = GNUTLS_E_ASN1_DER_ERROR;
      goto failover;
    }

  if (need_free)
    _gnutls_free_datum (&_data);

  /* The key has now been decoded.
   */

  return 0;

failover:
  /* Try PKCS #8 */
  if (result == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
    {
      _gnutls_debug_log ("Falling back to PKCS #8 key decoding\n");
      result = gnutls_x509_privkey_import_pkcs8 (key, data, format,
                                                 NULL, GNUTLS_PKCS_PLAIN);
    }

  if (need_free)
    _gnutls_free_datum (&_data);

  return result;
}
Esempio n. 2
0
/**
  * gnutls_x509_privkey_import - This function will import a DER or PEM encoded key
  * @key: The structure to store the parsed key
  * @data: The DER or PEM encoded certificate.
  * @format: One of DER or PEM
  *
  * This function will convert the given DER or PEM encoded key
  * to the native gnutls_x509_privkey_t format. The output will be stored in @key .
  *
  * If the key is PEM encoded it should have a header of "RSA PRIVATE KEY", or
  * "DSA PRIVATE KEY".
  *
  * Returns 0 on success.
  *
  **/
int
gnutls_x509_privkey_import (gnutls_x509_privkey_t key,
			    const gnutls_datum_t * data,
			    gnutls_x509_crt_fmt_t format)
{
  int result = 0, need_free = 0;
  gnutls_datum_t _data;

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

  _data.data = data->data;
  _data.size = data->size;

  key->pk_algorithm = GNUTLS_PK_UNKNOWN;

  /* If the Certificate is in PEM format then decode it
   */
  if (format == GNUTLS_X509_FMT_PEM)
    {
      opaque *out;

      /* Try the first header */
      result =
	_gnutls_fbase64_decode (PEM_KEY_RSA, data->data, data->size, &out);
      key->pk_algorithm = GNUTLS_PK_RSA;

      if (result <= 0)
	{
	  /* try for the second header */
	  result =
	    _gnutls_fbase64_decode (PEM_KEY_DSA, data->data, data->size,
				    &out);
	  key->pk_algorithm = GNUTLS_PK_DSA;

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

      _data.data = out;
      _data.size = result;

      need_free = 1;
    }

  if (key->pk_algorithm == GNUTLS_PK_RSA)
    {
      key->key = _gnutls_privkey_decode_pkcs1_rsa_key (&_data, key);
      if (key->key == NULL)
	{
	  gnutls_assert ();
	  result = GNUTLS_E_ASN1_DER_ERROR;
	  goto cleanup;
	}
    }
  else if (key->pk_algorithm == GNUTLS_PK_DSA)
    {
      key->key = decode_dsa_key (&_data, key);
      if (key->key == NULL)
	{
	  gnutls_assert ();
	  result = GNUTLS_E_ASN1_DER_ERROR;
	  goto cleanup;
	}
    }
  else
    {
      /* Try decoding with both, and accept the one that 
       * succeeds.
       */
      key->pk_algorithm = GNUTLS_PK_DSA;
      key->key = decode_dsa_key (&_data, key);

      if (key->key == NULL)
	{
	  key->pk_algorithm = GNUTLS_PK_RSA;
	  key->key = _gnutls_privkey_decode_pkcs1_rsa_key (&_data, key);
	  if (key->key == NULL)
	    {
	      gnutls_assert ();
	      result = GNUTLS_E_ASN1_DER_ERROR;
	      goto cleanup;
	    }
	}
    }

  if (need_free)
    _gnutls_free_datum (&_data);

  /* The key has now been decoded.
   */

  return 0;

cleanup:
  key->pk_algorithm = GNUTLS_PK_UNKNOWN;
  if (need_free)
    _gnutls_free_datum (&_data);
  return result;
}