예제 #1
0
/* Decodes an ECC privateKey from a PKCS8 structure.
 */
static int
_decode_pkcs8_ecc_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
{
	int ret;
	gnutls_datum_t tmp = {NULL, 0};
	unsigned char oid[MAX_OID_SIZE];
	unsigned curve = GNUTLS_ECC_CURVE_INVALID;
	int len, result;

	/* openssl PKCS #8 files with ECC keys place the curve in
	 * privateKeyAlgorithm.parameters instead of the ECPrivateKey.parameters.
	 */
	len = sizeof(oid);
	result =
	    asn1_read_value(pkcs8_asn, "privateKeyAlgorithm.parameters",
			    oid, &len);
	if (result == ASN1_SUCCESS) {
		ret = _gnutls_x509_read_ecc_params(oid, len, &curve);
		if (ret < 0) {
			_gnutls_debug_log("PKCS#8: unknown curve OID %s\n", oid);
			curve = GNUTLS_ECC_CURVE_INVALID;
		}
	}

	ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp);
	if (ret < 0) {
		gnutls_assert();
		goto error;
	}

	ret = _gnutls_privkey_decode_ecc_key(&pkey->key, &tmp, pkey, curve);
	_gnutls_free_key_datum(&tmp);

	if (ret < 0) {
		gnutls_assert();
		goto error;
	}

	ret = 0;

      error:
	return ret;
}
예제 #2
0
/**
 * 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;
}