Example #1
0
/**
 * gnutls_x509_privkey_deinit:
 * @key: The structure to be deinitialized
 *
 * This function will deinitialize a private key structure.
 **/
void gnutls_x509_privkey_deinit(gnutls_x509_privkey_t key)
{
	if (!key)
		return;

	_gnutls_x509_privkey_reinit(key);
	gnutls_free(key);
}
Example #2
0
/**
 * gnutls_x509_privkey_import_pkcs8:
 * @key: The data to store the parsed key
 * @data: The DER or PEM encoded key.
 * @format: One of DER or PEM
 * @password: the password to decrypt the key (if it is encrypted).
 * @flags: 0 if encrypted or GNUTLS_PKCS_PLAIN if not encrypted.
 *
 * This function will convert the given DER or PEM encoded PKCS8 2.0
 * encrypted key to the native gnutls_x509_privkey_t format. The
 * output will be stored in @key.  Both RSA and DSA keys can be
 * imported, and flags can only be used to indicate an unencrypted
 * key.
 *
 * The @password can be either ASCII or UTF-8 in the default PBES2
 * encryption schemas, or ASCII for the PKCS12 schemas.
 *
 * If the Certificate is PEM encoded it should have a header of
 * "ENCRYPTED PRIVATE KEY", or "PRIVATE KEY". You only need to
 * specify the flags if the key is DER encoded, since in that case
 * the encryption status cannot be auto-detected.
 *
 * If the %GNUTLS_PKCS_PLAIN flag is specified and the supplied data
 * are encrypted then %GNUTLS_E_DECRYPTION_FAILED is returned.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey_t key,
				 const gnutls_datum_t * data,
				 gnutls_x509_crt_fmt_t format,
				 const char *password, unsigned int flags)
{
	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->params.algo = GNUTLS_PK_UNKNOWN;

	/* If the Certificate is in PEM format then decode it
	 */
	if (format == GNUTLS_X509_FMT_PEM) {
		/* Try the first header 
		 */
		result =
		    _gnutls_fbase64_decode(PEM_UNENCRYPTED_PKCS8,
					   data->data, data->size, &_data);

		if (result < 0) {	/* Try the encrypted header 
					 */
			result =
			    _gnutls_fbase64_decode(PEM_PKCS8, data->data,
						   data->size, &_data);

			if (result < 0) {
				gnutls_assert();
				return result;
			}
		} else if (flags == 0)
			flags |= GNUTLS_PKCS_PLAIN;

		need_free = 1;
	}

	if (key->expanded) {
		_gnutls_x509_privkey_reinit(key);
	}
	key->expanded = 1;

	/* Here we don't check for password == NULL to maintain a backwards
	 * compatibility behavior, with old versions that were encrypting using
	 * a NULL password.
	 */
	if (flags & GNUTLS_PKCS_PLAIN) {
		result = decode_private_key_info(&_data, key);
		if (result < 0) {	/* check if it is encrypted */
			if (pkcs8_key_decode(&_data, "", key, 0) == 0)
				result = GNUTLS_E_DECRYPTION_FAILED;
		}
	} else {		/* encrypted. */
		result = pkcs8_key_decode(&_data, password, key, 1);
	}

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

	/* This part is necessary to get the public key on certain algorithms.
	 * In the import above we only get the private key. */
	result =
	    _gnutls_pk_fixup(key->params.algo, GNUTLS_IMPORT, &key->params);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (need_free)
		_gnutls_free_datum(&_data);

	/* The key has now been decoded.
	 */
	return 0;

 cleanup:
	asn1_delete_structure2(&key->key, ASN1_DELETE_FLAG_ZEROIZE);
	key->params.algo = GNUTLS_PK_UNKNOWN;
	if (need_free)
		_gnutls_free_datum(&_data);
	return result;
}
Example #3
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) {
		/* Try the first header */
		result =
		    _gnutls_fbase64_decode(PEM_KEY_RSA, data->data,
					   data->size, &_data);

		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, &_data);

			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,
							   &_data);
				if (result >= 0)
					key->pk_algorithm = GNUTLS_PK_EC;
			}
		}

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

		need_free = 1;
	}

	if (key->expanded) {
		_gnutls_x509_privkey_reinit(key);
	}
	key->expanded = 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) {
		result = _gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
		if (result < 0) {
			gnutls_assert();
			goto failover;
		}
	} 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;
				result =
				    _gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
				if (result < 0) {
					gnutls_assert();
					goto failover;
				}
			}
		}
	}

	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;
}