/* * Copyright (C) 2003-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ /* Functions on OpenPGP privkey parsing */ #include #include #include #include #include #include #include #include #include /** * gnutls_openpgp_privkey_init: * @key: The structure to be initialized * * This function will initialize an OpenPGP key structure. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_privkey_init (gnutls_openpgp_privkey_t * key) { *key = gnutls_calloc (1, sizeof (gnutls_openpgp_privkey_int)); if (*key) return 0; /* success */ return GNUTLS_E_MEMORY_ERROR; } /** * gnutls_openpgp_privkey_deinit: * @key: The structure to be initialized * * This function will deinitialize a key structure. **/ void gnutls_openpgp_privkey_deinit (gnutls_openpgp_privkey_t key) { if (!key) return; if (key->knode) { cdk_kbnode_release (key->knode); key->knode = NULL; } gnutls_free (key); } /*- * _gnutls_openpgp_privkey_cpy - This function copies a gnutls_openpgp_privkey_t structure * @dest: The structure where to copy * @src: The structure to be copied * * This function will copy an X.509 certificate structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_openpgp_privkey_cpy (gnutls_openpgp_privkey_t dest, gnutls_openpgp_privkey_t src) { int ret; size_t raw_size=0; uint8_t *der; gnutls_datum_t tmp; ret = gnutls_openpgp_privkey_export (src, GNUTLS_OPENPGP_FMT_RAW, NULL, 0, NULL, &raw_size); if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) return gnutls_assert_val(ret); der = gnutls_malloc (raw_size); if (der == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ret = gnutls_openpgp_privkey_export (src, GNUTLS_OPENPGP_FMT_RAW, NULL, 0, der, &raw_size); if (ret < 0) { gnutls_assert (); gnutls_free (der); return ret; } tmp.data = der; tmp.size = raw_size; ret = gnutls_openpgp_privkey_import (dest, &tmp, GNUTLS_OPENPGP_FMT_RAW, NULL, 0); gnutls_free (der); if (ret < 0) return gnutls_assert_val(ret); memcpy(dest->preferred_keyid, src->preferred_keyid, GNUTLS_OPENPGP_KEYID_SIZE); dest->preferred_set = src->preferred_set; return 0; } /** * gnutls_openpgp_privkey_sec_param: * @key: a key structure * * This function will return the security parameter appropriate with * this private key. * * Returns: On success, a valid security parameter is returned otherwise * %GNUTLS_SEC_PARAM_UNKNOWN is returned. * * Since: 2.12.0 **/ gnutls_sec_param_t gnutls_openpgp_privkey_sec_param (gnutls_openpgp_privkey_t key) { gnutls_pk_algorithm_t algo; unsigned int bits; algo = gnutls_openpgp_privkey_get_pk_algorithm (key, &bits); if (algo == GNUTLS_PK_UNKNOWN) { gnutls_assert (); return GNUTLS_SEC_PARAM_UNKNOWN; } return gnutls_pk_bits_to_sec_param (algo, bits); } /** * gnutls_openpgp_privkey_import: * @key: The structure to store the parsed key. * @data: The RAW or BASE64 encoded key. * @format: One of #gnutls_openpgp_crt_fmt_t elements. * @password: not used for now * @flags: should be (0) * * This function will convert the given RAW or Base64 encoded key to * the native gnutls_openpgp_privkey_t format. The output will be * stored in 'key'. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_privkey_import (gnutls_openpgp_privkey_t key, const gnutls_datum_t * data, gnutls_openpgp_crt_fmt_t format, const char *password, unsigned int flags) { cdk_packet_t pkt; int rc, armor; if (data->data == NULL || data->size == 0) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } if (format == GNUTLS_OPENPGP_FMT_RAW) armor = 0; else armor = 1; rc = cdk_kbnode_read_from_mem (&key->knode, armor, data->data, data->size); if (rc != 0) { rc = _gnutls_map_cdk_rc (rc); gnutls_assert (); return rc; } /* Test if the import was successful. */ pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); if (pkt == NULL) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } return 0; } /** * gnutls_openpgp_privkey_export: * @key: Holds the key. * @format: One of gnutls_openpgp_crt_fmt_t elements. * @password: the password that will be used to encrypt the key. (unused for now) * @flags: (0) for future compatibility * @output_data: will contain the key base64 encoded or raw * @output_data_size: holds the size of output_data (and will be * replaced by the actual size of parameters) * * This function will convert the given key to RAW or Base64 format. * If the buffer provided is not long enough to hold the output, then * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_export (gnutls_openpgp_privkey_t key, gnutls_openpgp_crt_fmt_t format, const char *password, unsigned int flags, void *output_data, size_t * output_data_size) { /* FIXME for now we do not export encrypted keys */ return _gnutls_openpgp_export (key->knode, format, output_data, output_data_size, 1); } /** * gnutls_openpgp_privkey_export2: * @key: Holds the key. * @format: One of gnutls_openpgp_crt_fmt_t elements. * @password: the password that will be used to encrypt the key. (unused for now) * @flags: (0) for future compatibility * @out: will contain the raw or based64 encoded key * * This function will convert the given key to RAW or Base64 format. * The output buffer is allocated using gnutls_malloc(). * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. * * Since: 3.1.3 **/ int gnutls_openpgp_privkey_export2 (gnutls_openpgp_privkey_t key, gnutls_openpgp_crt_fmt_t format, const char *password, unsigned int flags, gnutls_datum_t *out) { /* FIXME for now we do not export encrypted keys */ return _gnutls_openpgp_export2 (key->knode, format, out, 1); } /** * gnutls_openpgp_privkey_get_pk_algorithm: * @key: is an OpenPGP key * @bits: if bits is non null it will hold the size of the parameters' in bits * * This function will return the public key algorithm of an OpenPGP * certificate. * * If bits is non null, it should have enough size to hold the parameters * size in bits. For RSA the bits returned is the modulus. * For DSA the bits returned are of the public exponent. * * Returns: a member of the #gnutls_pk_algorithm_t enumeration on * success, or a negative error code on error. * * Since: 2.4.0 **/ gnutls_pk_algorithm_t gnutls_openpgp_privkey_get_pk_algorithm (gnutls_openpgp_privkey_t key, unsigned int *bits) { cdk_packet_t pkt; int algo = 0, ret; uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; if (!key) { gnutls_assert (); return GNUTLS_PK_UNKNOWN; } ret = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid); if (ret == 0) { int idx; idx = gnutls_openpgp_privkey_get_subkey_idx (key, keyid); if (idx != GNUTLS_OPENPGP_MASTER_KEYID_IDX) { algo = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, idx, bits); return algo; } } pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); if (pkt) { if (bits) *bits = cdk_pk_get_nbits (pkt->pkt.secret_key->pk); algo = _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo); } return algo; } int _gnutls_openpgp_get_algo (int cdk_algo) { int algo; if (is_RSA (cdk_algo)) algo = GNUTLS_PK_RSA; else if (is_DSA (cdk_algo)) algo = GNUTLS_PK_DSA; else { _gnutls_debug_log ("Unknown OpenPGP algorithm %d\n", cdk_algo); algo = GNUTLS_PK_UNKNOWN; } return algo; } /** * gnutls_openpgp_privkey_get_revoked_status: * @key: the structure that contains the OpenPGP private key. * * Get revocation status of key. * * Returns: true (1) if the key has been revoked, or false (0) if it * has not, or a negative error code indicates an error. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_revoked_status (gnutls_openpgp_privkey_t key) { cdk_packet_t pkt; if (!key) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); if (!pkt) return GNUTLS_E_OPENPGP_GETKEY_FAILED; if (pkt->pkt.secret_key->is_revoked != 0) return 1; return 0; } /** * gnutls_openpgp_privkey_get_fingerprint: * @key: the raw data that contains the OpenPGP secret key. * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes. * @fprlen: the integer to save the length of the fingerprint. * * Get the fingerprint of the OpenPGP key. Depends on the * algorithm, the fingerprint can be 16 or 20 bytes. * * Returns: On success, 0 is returned, or an error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_fingerprint (gnutls_openpgp_privkey_t key, void *fpr, size_t * fprlen) { cdk_packet_t pkt; cdk_pkt_pubkey_t pk = NULL; if (!fpr || !fprlen) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } *fprlen = 0; pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); if (!pkt) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } pk = pkt->pkt.secret_key->pk; *fprlen = 20; if (is_RSA (pk->pubkey_algo) && pk->version < 4) *fprlen = 16; cdk_pk_get_fingerprint (pk, fpr); return 0; } /** * gnutls_openpgp_privkey_get_key_id: * @key: the structure that contains the OpenPGP secret key. * @keyid: the buffer to save the keyid. * * Get key-id. * * Returns: the 64-bit keyID of the OpenPGP key. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_key_id (gnutls_openpgp_privkey_t key, gnutls_openpgp_keyid_t keyid) { cdk_packet_t pkt; uint32_t kid[2]; if (!key || !keyid) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); if (!pkt) return GNUTLS_E_OPENPGP_GETKEY_FAILED; cdk_sk_get_keyid (pkt->pkt.secret_key, kid); _gnutls_write_uint32 (kid[0], keyid); _gnutls_write_uint32 (kid[1], keyid + 4); return 0; } /** * gnutls_openpgp_privkey_get_subkey_count: * @key: is an OpenPGP key * * This function will return the number of subkeys present in the * given OpenPGP certificate. * * Returns: the number of subkeys, or a negative error code on error. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_subkey_count (gnutls_openpgp_privkey_t key) { cdk_kbnode_t p, ctx; cdk_packet_t pkt; int subkeys; if (key == NULL) { gnutls_assert (); return 0; } ctx = NULL; subkeys = 0; while ((p = cdk_kbnode_walk (key->knode, &ctx, 0))) { pkt = cdk_kbnode_get_packet (p); if (pkt->pkttype == CDK_PKT_SECRET_SUBKEY) subkeys++; } return subkeys; } /* returns the subkey with the given index */ static cdk_packet_t _get_secret_subkey (gnutls_openpgp_privkey_t key, unsigned int indx) { cdk_kbnode_t p, ctx; cdk_packet_t pkt; unsigned int subkeys; ctx = NULL; subkeys = 0; while ((p = cdk_kbnode_walk (key->knode, &ctx, 0))) { pkt = cdk_kbnode_get_packet (p); if (pkt->pkttype == CDK_PKT_SECRET_SUBKEY && indx == subkeys++) return pkt; } return NULL; } /** * gnutls_openpgp_privkey_get_subkey_revoked_status: * @key: the structure that contains the OpenPGP private key. * @idx: is the subkey index * * Get revocation status of key. * * Returns: true (1) if the key has been revoked, or false (0) if it * has not, or a negative error code indicates an error. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_subkey_revoked_status (gnutls_openpgp_privkey_t key, unsigned int idx) { cdk_packet_t pkt; if (!key) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) return gnutls_openpgp_privkey_get_revoked_status(key); pkt = _get_secret_subkey (key, idx); if (!pkt) return GNUTLS_E_OPENPGP_GETKEY_FAILED; if (pkt->pkt.secret_key->is_revoked != 0) return 1; return 0; } /** * gnutls_openpgp_privkey_get_subkey_pk_algorithm: * @key: is an OpenPGP key * @idx: is the subkey index * @bits: if bits is non null it will hold the size of the parameters' in bits * * This function will return the public key algorithm of a subkey of an OpenPGP * certificate. * * If bits is non null, it should have enough size to hold the parameters * size in bits. For RSA the bits returned is the modulus. * For DSA the bits returned are of the public exponent. * * Returns: a member of the #gnutls_pk_algorithm_t enumeration on * success, or a negative error code on error. * * Since: 2.4.0 **/ gnutls_pk_algorithm_t gnutls_openpgp_privkey_get_subkey_pk_algorithm (gnutls_openpgp_privkey_t key, unsigned int idx, unsigned int *bits) { cdk_packet_t pkt; int algo; if (!key) { gnutls_assert (); return GNUTLS_PK_UNKNOWN; } if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) return gnutls_openpgp_privkey_get_pk_algorithm(key, bits); pkt = _get_secret_subkey (key, idx); algo = 0; if (pkt) { if (bits) *bits = cdk_pk_get_nbits (pkt->pkt.secret_key->pk); algo = pkt->pkt.secret_key->pubkey_algo; if (is_RSA (algo)) algo = GNUTLS_PK_RSA; else if (is_DSA (algo)) algo = GNUTLS_PK_DSA; else algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM; } return algo; } /** * gnutls_openpgp_privkey_get_subkey_idx: * @key: the structure that contains the OpenPGP private key. * @keyid: the keyid. * * Get index of subkey. * * Returns: the index of the subkey or a negative error value. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_subkey_idx (gnutls_openpgp_privkey_t key, const gnutls_openpgp_keyid_t keyid) { int ret; uint32_t kid[2]; uint8_t master_id[GNUTLS_OPENPGP_KEYID_SIZE]; if (!key) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } ret = gnutls_openpgp_privkey_get_key_id (key, master_id); if (ret < 0) return gnutls_assert_val(ret); if (memcmp(master_id, keyid, GNUTLS_OPENPGP_KEYID_SIZE)==0) return GNUTLS_OPENPGP_MASTER_KEYID_IDX; KEYID_IMPORT (kid, keyid); ret = _gnutls_openpgp_find_subkey_idx (key->knode, kid, 1); if (ret < 0) { gnutls_assert (); } return ret; } /** * gnutls_openpgp_privkey_get_subkey_creation_time: * @key: the structure that contains the OpenPGP private key. * @idx: the subkey index * * Get subkey creation time. * * Returns: the timestamp when the OpenPGP key was created. * * Since: 2.4.0 **/ time_t gnutls_openpgp_privkey_get_subkey_creation_time (gnutls_openpgp_privkey_t key, unsigned int idx) { cdk_packet_t pkt; time_t timestamp; if (!key) return (time_t) - 1; if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); else pkt = _get_secret_subkey (key, idx); if (pkt) timestamp = pkt->pkt.secret_key->pk->timestamp; else timestamp = 0; return timestamp; } /** * gnutls_openpgp_privkey_get_subkey_expiration_time: * @key: the structure that contains the OpenPGP private key. * @idx: the subkey index * * Get subkey expiration time. A value of '0' means that the key * doesn't expire at all. * * Returns: the time when the OpenPGP key expires. * * Since: 2.4.0 **/ time_t gnutls_openpgp_privkey_get_subkey_expiration_time (gnutls_openpgp_privkey_t key, unsigned int idx) { cdk_packet_t pkt; time_t timestamp; if (!key) return (time_t) - 1; if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY); else pkt = _get_secret_subkey (key, idx); if (pkt) timestamp = pkt->pkt.secret_key->pk->expiredate; else timestamp = 0; return timestamp; } /** * gnutls_openpgp_privkey_get_subkey_id: * @key: the structure that contains the OpenPGP secret key. * @idx: the subkey index * @keyid: the buffer to save the keyid. * * Get the key-id for the subkey. * * Returns: the 64-bit keyID of the OpenPGP key. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_subkey_id (gnutls_openpgp_privkey_t key, unsigned int idx, gnutls_openpgp_keyid_t keyid) { cdk_packet_t pkt; uint32_t kid[2]; if (!key || !keyid) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) return gnutls_openpgp_privkey_get_key_id(key, keyid); pkt = _get_secret_subkey (key, idx); if (!pkt) return GNUTLS_E_OPENPGP_GETKEY_FAILED; cdk_sk_get_keyid (pkt->pkt.secret_key, kid); _gnutls_write_uint32 (kid[0], keyid); _gnutls_write_uint32 (kid[1], keyid + 4); return 0; } /** * gnutls_openpgp_privkey_get_subkey_fingerprint: * @key: the raw data that contains the OpenPGP secret key. * @idx: the subkey index * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes. * @fprlen: the integer to save the length of the fingerprint. * * Get the fingerprint of an OpenPGP subkey. Depends on the * algorithm, the fingerprint can be 16 or 20 bytes. * * Returns: On success, 0 is returned, or an error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_get_subkey_fingerprint (gnutls_openpgp_privkey_t key, unsigned int idx, void *fpr, size_t * fprlen) { cdk_packet_t pkt; cdk_pkt_pubkey_t pk = NULL; if (!fpr || !fprlen) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) return gnutls_openpgp_privkey_get_fingerprint(key, fpr, fprlen); *fprlen = 0; pkt = _get_secret_subkey (key, idx); if (!pkt) return GNUTLS_E_OPENPGP_GETKEY_FAILED; pk = pkt->pkt.secret_key->pk; *fprlen = 20; if (is_RSA (pk->pubkey_algo) && pk->version < 4) *fprlen = 16; cdk_pk_get_fingerprint (pk, fpr); return 0; } /* Extracts DSA and RSA parameters from a certificate. */ int _gnutls_openpgp_privkey_get_mpis (gnutls_openpgp_privkey_t pkey, uint32_t * keyid /*[2] */ , gnutls_pk_params_st * params) { int result; unsigned int i, pk_algorithm; cdk_packet_t pkt; gnutls_pk_params_init(params); if (keyid == NULL) pkt = cdk_kbnode_find_packet (pkey->knode, CDK_PKT_SECRET_KEY); else pkt = _gnutls_openpgp_find_key (pkey->knode, keyid, 1); if (pkt == NULL) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo); switch (pk_algorithm) { case GNUTLS_PK_RSA: /* openpgp does not hold all parameters as in PKCS #1 */ params->params_nr = RSA_PRIVATE_PARAMS - 2; break; case GNUTLS_PK_DSA: params->params_nr = DSA_PRIVATE_PARAMS; break; default: gnutls_assert (); return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE; } for (i = 0; i < params->params_nr; i++) { result = _gnutls_read_pgp_mpi (pkt, 1, i, ¶ms->params[i]); if (result < 0) { gnutls_assert (); goto error; } } /* fixup will generate exp1 and exp2 that are not * available here. */ result = _gnutls_pk_fixup (pk_algorithm, GNUTLS_IMPORT, params); if (result < 0) { gnutls_assert (); goto error; } return 0; error: gnutls_pk_params_release(params); return result; } /* The internal version of export */ static int _get_sk_rsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid, gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u) { int pk_algorithm, ret; cdk_packet_t pkt; uint32_t kid32[2]; gnutls_pk_params_st params; if (pkey == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } KEYID_IMPORT (kid32, keyid); pkt = _gnutls_openpgp_find_key (pkey->knode, kid32, 1); if (pkt == NULL) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo); if (pk_algorithm != GNUTLS_PK_RSA) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, ¶ms); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_mpi_dprint (params.params[0], m); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = _gnutls_mpi_dprint (params.params[1], e); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); goto cleanup; } ret = _gnutls_mpi_dprint (params.params[2], d); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); _gnutls_free_datum (e); goto cleanup; } ret = _gnutls_mpi_dprint (params.params[3], p); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); _gnutls_free_datum (e); _gnutls_free_datum (d); goto cleanup; } ret = _gnutls_mpi_dprint (params.params[4], q); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (m); _gnutls_free_datum (e); _gnutls_free_datum (d); _gnutls_free_datum (p); goto cleanup; } ret = _gnutls_mpi_dprint (params.params[5], u); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (q); _gnutls_free_datum (m); _gnutls_free_datum (e); _gnutls_free_datum (d); _gnutls_free_datum (p); goto cleanup; } ret = 0; cleanup: gnutls_pk_params_release(¶ms); return ret; } static int _get_sk_dsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * g, gnutls_datum_t * y, gnutls_datum_t * x) { int pk_algorithm, ret; cdk_packet_t pkt; uint32_t kid32[2]; gnutls_pk_params_st params; if (pkey == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } KEYID_IMPORT (kid32, keyid); pkt = _gnutls_openpgp_find_key (pkey->knode, kid32, 1); if (pkt == NULL) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo); if (pk_algorithm != GNUTLS_PK_DSA) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, ¶ms); if (ret < 0) { gnutls_assert (); return ret; } /* P */ ret = _gnutls_mpi_dprint (params.params[0], p); if (ret < 0) { gnutls_assert (); goto cleanup; } /* Q */ ret = _gnutls_mpi_dprint (params.params[1], q); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (p); goto cleanup; } /* G */ ret = _gnutls_mpi_dprint (params.params[2], g); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (p); _gnutls_free_datum (q); goto cleanup; } /* Y */ ret = _gnutls_mpi_dprint (params.params[3], y); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (p); _gnutls_free_datum (g); _gnutls_free_datum (q); goto cleanup; } ret = _gnutls_mpi_dprint (params.params[4], x); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (y); _gnutls_free_datum (p); _gnutls_free_datum (g); _gnutls_free_datum (q); goto cleanup; } ret = 0; cleanup: gnutls_pk_params_release(¶ms); return ret; } /** * gnutls_openpgp_privkey_export_rsa_raw: * @pkey: Holds the certificate * @m: will hold the modulus * @e: will hold the public exponent * @d: will hold the private exponent * @p: will hold the first prime (p) * @q: will hold the second prime (q) * @u: will hold the coefficient * * This function will export the RSA private key's parameters found in * the given structure. The new parameters will be allocated using * gnutls_malloc() and will be stored in the appropriate datum. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_export_rsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u) { uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; int ret; ret = gnutls_openpgp_privkey_get_key_id (pkey, keyid); if (ret < 0) { gnutls_assert (); return ret; } return _get_sk_rsa_raw (pkey, keyid, m, e, d, p, q, u); } /** * gnutls_openpgp_privkey_export_dsa_raw: * @pkey: Holds the certificate * @p: will hold the p * @q: will hold the q * @g: will hold the g * @y: will hold the y * @x: will hold the x * * This function will export the DSA private key's parameters found in * the given certificate. The new parameters will be allocated using * gnutls_malloc() and will be stored in the appropriate datum. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_export_dsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * g, gnutls_datum_t * y, gnutls_datum_t * x) { uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; int ret; ret = gnutls_openpgp_privkey_get_key_id (pkey, keyid); if (ret < 0) { gnutls_assert (); return ret; } return _get_sk_dsa_raw (pkey, keyid, p, q, g, y, x); } /** * gnutls_openpgp_privkey_export_subkey_rsa_raw: * @pkey: Holds the certificate * @idx: Is the subkey index * @m: will hold the modulus * @e: will hold the public exponent * @d: will hold the private exponent * @p: will hold the first prime (p) * @q: will hold the second prime (q) * @u: will hold the coefficient * * This function will export the RSA private key's parameters found in * the given structure. The new parameters will be allocated using * gnutls_malloc() and will be stored in the appropriate datum. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_export_subkey_rsa_raw (gnutls_openpgp_privkey_t pkey, unsigned int idx, gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u) { uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; int ret; if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) ret = gnutls_openpgp_privkey_get_key_id (pkey, keyid); else ret = gnutls_openpgp_privkey_get_subkey_id (pkey, idx, keyid); if (ret < 0) { gnutls_assert (); return ret; } return _get_sk_rsa_raw (pkey, keyid, m, e, d, p, q, u); } /** * gnutls_openpgp_privkey_export_subkey_dsa_raw: * @pkey: Holds the certificate * @idx: Is the subkey index * @p: will hold the p * @q: will hold the q * @g: will hold the g * @y: will hold the y * @x: will hold the x * * This function will export the DSA private key's parameters found * in the given certificate. The new parameters will be allocated * using gnutls_malloc() and will be stored in the appropriate datum. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. * * Since: 2.4.0 **/ int gnutls_openpgp_privkey_export_subkey_dsa_raw (gnutls_openpgp_privkey_t pkey, unsigned int idx, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * g, gnutls_datum_t * y, gnutls_datum_t * x) { uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; int ret; if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) ret = gnutls_openpgp_privkey_get_key_id (pkey, keyid); else ret = gnutls_openpgp_privkey_get_subkey_id (pkey, idx, keyid); if (ret < 0) { gnutls_assert (); return ret; } return _get_sk_dsa_raw (pkey, keyid, p, q, g, y, x); } /** * gnutls_openpgp_privkey_get_preferred_key_id: * @key: the structure that contains the OpenPGP public key. * @keyid: the struct to save the keyid. * * Get the preferred key-id for the key. * * Returns: the 64-bit preferred keyID of the OpenPGP key, or if it * hasn't been set it returns %GNUTLS_E_INVALID_REQUEST. **/ int gnutls_openpgp_privkey_get_preferred_key_id (gnutls_openpgp_privkey_t key, gnutls_openpgp_keyid_t keyid) { if (!key->preferred_set) return gnutls_assert_val(GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR); if (!key || !keyid) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } memcpy (keyid, key->preferred_keyid, GNUTLS_OPENPGP_KEYID_SIZE); return 0; } /** * gnutls_openpgp_privkey_set_preferred_key_id: * @key: the structure that contains the OpenPGP public key. * @keyid: the selected keyid * * This allows setting a preferred key id for the given certificate. * This key will be used by functions that involve key handling. * * If the provided @keyid is %NULL then the master key is * set as preferred. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ int gnutls_openpgp_privkey_set_preferred_key_id (gnutls_openpgp_privkey_t key, const gnutls_openpgp_keyid_t keyid) { int ret; if (!key) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (keyid == NULL) /* set the master as preferred */ { uint8_t tmp[GNUTLS_OPENPGP_KEYID_SIZE]; ret = gnutls_openpgp_privkey_get_key_id (key, tmp); if (ret < 0) return gnutls_assert_val(ret); key->preferred_set = 1; memcpy (key->preferred_keyid, tmp, GNUTLS_OPENPGP_KEYID_SIZE); return 0; } /* check if the id is valid */ ret = gnutls_openpgp_privkey_get_subkey_idx (key, keyid); if (ret < 0) { _gnutls_debug_log ("the requested subkey does not exist\n"); gnutls_assert (); return ret; } key->preferred_set = 1; memcpy (key->preferred_keyid, keyid, GNUTLS_OPENPGP_KEYID_SIZE); return 0; } /** * gnutls_openpgp_privkey_sign_hash: * @key: Holds the key * @hash: holds the data to be signed * @signature: will contain newly allocated signature * * This function will sign the given hash using the private key. You * should use gnutls_openpgp_privkey_set_preferred_key_id() before * calling this function to set the subkey to use. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Deprecated: Use gnutls_privkey_sign_hash() instead. */ int gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature) { int result; gnutls_pk_params_st params; int pk_algorithm; uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; char buf[2*GNUTLS_OPENPGP_KEYID_SIZE+1]; if (key == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid); if (result == 0) { uint32_t kid[2]; int idx; KEYID_IMPORT (kid, keyid); _gnutls_hard_log("Signing using PGP key ID %s\n", _gnutls_bin2hex(keyid, GNUTLS_OPENPGP_KEYID_SIZE, buf, sizeof(buf), NULL)); idx = gnutls_openpgp_privkey_get_subkey_idx (key, keyid); pk_algorithm = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, idx, NULL); result = _gnutls_openpgp_privkey_get_mpis (key, kid, ¶ms); } else { _gnutls_hard_log("Signing using master PGP key\n"); pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL); result = _gnutls_openpgp_privkey_get_mpis (key, NULL, ¶ms); } if (result < 0) { gnutls_assert (); return result; } result = _gnutls_pk_sign (pk_algorithm, signature, hash, ¶ms); gnutls_pk_params_release(¶ms); if (result < 0) { gnutls_assert (); return result; } return 0; } /*- * _gnutls_openpgp_privkey_decrypt_data: * @key: Holds the key * @flags: (0) for now * @ciphertext: holds the data to be decrypted * @plaintext: will contain newly allocated plaintext * * This function will sign the given hash using the private key. You * should use gnutls_openpgp_privkey_set_preferred_key_id() before * calling this function to set the subkey to use. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key, unsigned int flags, const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext) { int result, i; gnutls_pk_params_st params; int pk_algorithm; uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE]; char buf[2*GNUTLS_OPENPGP_KEYID_SIZE+1]; if (key == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid); if (result == 0) { uint32_t kid[2]; KEYID_IMPORT (kid, keyid); _gnutls_hard_log("Decrypting using PGP key ID %s\n", _gnutls_bin2hex(keyid, GNUTLS_OPENPGP_KEYID_SIZE, buf, sizeof(buf), NULL)); result = _gnutls_openpgp_privkey_get_mpis (key, kid, ¶ms); i = gnutls_openpgp_privkey_get_subkey_idx (key, keyid); pk_algorithm = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, i, NULL); } else { _gnutls_hard_log("Decrypting using master PGP key\n"); pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL); result = _gnutls_openpgp_privkey_get_mpis (key, NULL, ¶ms); } if (result < 0) { gnutls_assert (); return result; } result = _gnutls_pk_decrypt (pk_algorithm, plaintext, ciphertext, ¶ms); gnutls_pk_params_release(¶ms); if (result < 0) return gnutls_assert_val(result); return 0; }