/* * Copyright (C) 2003-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos, Timo Schulz * * 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 2.1 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 keyring parsing */ #include #include #include #include #include #include #include /* Keyring stuff. */ /** * gnutls_openpgp_keyring_init: * @keyring: The structure to be initialized * * This function will initialize an keyring structure. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_keyring_init (gnutls_openpgp_keyring_t * keyring) { *keyring = gnutls_calloc (1, sizeof (gnutls_openpgp_keyring_int)); if (*keyring) return 0; /* success */ return GNUTLS_E_MEMORY_ERROR; } /** * gnutls_openpgp_keyring_deinit: * @keyring: The structure to be initialized * * This function will deinitialize a keyring structure. **/ void gnutls_openpgp_keyring_deinit (gnutls_openpgp_keyring_t keyring) { if (!keyring) return; if (keyring->db) { cdk_keydb_free (keyring->db); keyring->db = NULL; } gnutls_free (keyring); } /** * gnutls_openpgp_keyring_check_id: * @ring: holds the keyring to check against * @keyid: will hold the keyid to check for. * @flags: unused (should be 0) * * Check if a given key ID exists in the keyring. * * Returns: %GNUTLS_E_SUCCESS on success (if keyid exists) and a * negative error code on failure. **/ int gnutls_openpgp_keyring_check_id (gnutls_openpgp_keyring_t ring, const gnutls_openpgp_keyid_t keyid, unsigned int flags) { cdk_pkt_pubkey_t pk; uint32_t id[2]; id[0] = _gnutls_read_uint32 (keyid); id[1] = _gnutls_read_uint32 (&keyid[4]); if (!cdk_keydb_get_pk (ring->db, id, &pk)) { cdk_pk_release (pk); return 0; } _gnutls_debug_log ("PGP: key not found %08lX\n", (unsigned long) id[1]); return GNUTLS_E_NO_CERTIFICATE_FOUND; } /** * gnutls_openpgp_keyring_import: * @keyring: The structure to store the parsed key. * @data: The RAW or BASE64 encoded keyring. * @format: One of #gnutls_openpgp_keyring_fmt elements. * * This function will convert the given RAW or Base64 encoded keyring * to the native #gnutls_openpgp_keyring_t format. The output will be * stored in 'keyring'. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_keyring_import (gnutls_openpgp_keyring_t keyring, const gnutls_datum_t * data, gnutls_openpgp_crt_fmt_t format) { cdk_error_t err; cdk_stream_t input = NULL; size_t raw_len = 0; uint8_t *raw_data = NULL; if (data->data == NULL || data->size == 0) { gnutls_assert (); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } _gnutls_debug_log ("PGP: keyring import format '%s'\n", format == GNUTLS_OPENPGP_FMT_RAW ? "raw" : "base64"); /* Create a new stream from the given data, decode it, and import * the raw database. This to avoid using opencdk streams which are * not thread safe. */ if (format == GNUTLS_OPENPGP_FMT_BASE64) { size_t written = 0; err = cdk_stream_tmp_from_mem (data->data, data->size, &input); if (err == 0) err = cdk_stream_set_armor_flag (input, 0); if (err) { gnutls_assert (); err = _gnutls_map_cdk_rc (err); goto error; } raw_len = cdk_stream_get_length (input); if (raw_len == 0) { gnutls_assert (); err = GNUTLS_E_BASE64_DECODING_ERROR; goto error; } raw_data = gnutls_malloc (raw_len); if (raw_data == NULL) { gnutls_assert (); err = GNUTLS_E_MEMORY_ERROR; goto error; } do { err = cdk_stream_read (input, raw_data + written, raw_len - written); if (err > 0) written += err; } while (written < raw_len && err != EOF && err > 0); raw_len = written; } else { /* RAW */ raw_len = data->size; raw_data = data->data; } err = cdk_keydb_new_from_mem (&keyring->db, 0, 0, raw_data, raw_len); if (err) gnutls_assert (); return _gnutls_map_cdk_rc (err); error: gnutls_free (raw_data); cdk_stream_close (input); return err; } #define knode_is_pkey(node) \ cdk_kbnode_find_packet (node, CDK_PKT_PUBLIC_KEY)!=NULL /** * gnutls_openpgp_keyring_get_crt_count: * @ring: is an OpenPGP key ring * * This function will return the number of OpenPGP certificates * present in the given keyring. * * Returns: the number of subkeys, or a negative error code on error. **/ int gnutls_openpgp_keyring_get_crt_count (gnutls_openpgp_keyring_t ring) { cdk_kbnode_t knode; cdk_error_t err; cdk_keydb_search_t st; int ret = 0; err = cdk_keydb_search_start (&st, ring->db, CDK_DBSEARCH_NEXT, NULL); if (err != CDK_Success) { gnutls_assert (); return _gnutls_map_cdk_rc (err); } do { err = cdk_keydb_search (st, ring->db, &knode); if (err != CDK_Error_No_Key && err != CDK_Success) { gnutls_assert (); cdk_keydb_search_release (st); return _gnutls_map_cdk_rc (err); } if (knode_is_pkey (knode)) ret++; cdk_kbnode_release (knode); } while (err != CDK_Error_No_Key); cdk_keydb_search_release (st); return ret; } /** * gnutls_openpgp_keyring_get_crt: * @ring: Holds the keyring. * @idx: the index of the certificate to export * @cert: An uninitialized #gnutls_openpgp_crt_t structure * * This function will extract an OpenPGP certificate from the given * keyring. If the index given is out of range * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned. The * returned structure needs to be deinited. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_keyring_get_crt (gnutls_openpgp_keyring_t ring, unsigned int idx, gnutls_openpgp_crt_t * cert) { cdk_kbnode_t knode; cdk_error_t err; int ret = 0; unsigned int count = 0; cdk_keydb_search_t st; err = cdk_keydb_search_start (&st, ring->db, CDK_DBSEARCH_NEXT, NULL); if (err != CDK_Success) { gnutls_assert (); return _gnutls_map_cdk_rc (err); } do { err = cdk_keydb_search (st, ring->db, &knode); if (err != CDK_EOF && err != CDK_Success) { gnutls_assert (); cdk_keydb_search_release (st); return _gnutls_map_cdk_rc (err); } if (idx == count && err == CDK_Success) { ret = gnutls_openpgp_crt_init (cert); if (ret == 0) (*cert)->knode = knode; cdk_keydb_search_release (st); return ret; } if (knode_is_pkey (knode)) count++; cdk_kbnode_release (knode); } while (err != CDK_EOF); cdk_keydb_search_release (st); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; }