Doc fixes.
[gnutls:gnutls.git] / lib / openpgp / extras.c
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation
3  *
4  * Author: Nikos Mavrogiannopoulos, Timo Schulz
5  *
6  * This file is part of GNUTLS.
7  *
8  * The GNUTLS library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301, USA
22  *
23  */
24
25 /* Functions on keyring parsing
26  */
27
28 #include <gnutls_int.h>
29 #include <gnutls_datum.h>
30 #include <gnutls_global.h>
31 #include <gnutls_errors.h>
32 #include <openpgp_int.h>
33 #include <gnutls_openpgp.h>
34 #include <gnutls_num.h>
35
36 /* Keyring stuff.
37  */
38
39 /**
40  * gnutls_openpgp_keyring_init - initializes a #gnutls_openpgp_keyring_t structure
41  * @keyring: The structure to be initialized
42  *
43  * This function will initialize an keyring structure.
44  *
45  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
46  **/
47 int
48 gnutls_openpgp_keyring_init (gnutls_openpgp_keyring_t * keyring)
49 {
50   *keyring = gnutls_calloc (1, sizeof (gnutls_openpgp_keyring_int));
51
52   if (*keyring)
53     return 0;                   /* success */
54   return GNUTLS_E_MEMORY_ERROR;
55 }
56
57
58 /**
59  * gnutls_openpgp_keyring_deinit - deinitializes memory used by a #gnutls_openpgp_keyring_t structure
60  * @keyring: The structure to be initialized
61  *
62  * This function will deinitialize a keyring structure.
63  **/
64 void
65 gnutls_openpgp_keyring_deinit (gnutls_openpgp_keyring_t keyring)
66 {
67   if (!keyring)
68     return;
69
70   if (keyring->db)
71     {
72       cdk_keydb_free (keyring->db);
73       keyring->db = NULL;
74     }
75
76   gnutls_free (keyring);
77 }
78
79 /**
80  * gnutls_openpgp_keyring_check_id - Check if a key id exists in the keyring
81  * @ring: holds the keyring to check against
82  * @keyid: will hold the keyid to check for.
83  * @flags: unused (should be 0)
84  *
85  * Check if a given key ID exists in the keyring.
86  *
87  * Returns: %GNUTLS_E_SUCCESS on success (if keyid exists) and a
88  *   negative error code on failure.
89  **/
90 int
91 gnutls_openpgp_keyring_check_id (gnutls_openpgp_keyring_t ring,
92                                  const gnutls_openpgp_keyid_t keyid,
93                                  unsigned int flags)
94 {
95   cdk_pkt_pubkey_t pk;
96   uint32_t id[2];
97
98   id[0] = _gnutls_read_uint32 (keyid);
99   id[1] = _gnutls_read_uint32 (&keyid[4]);
100
101   if (!cdk_keydb_get_pk (ring->db, id, &pk))
102     {
103       cdk_pk_release (pk);
104       return 0;
105     }
106
107   _gnutls_debug_log ("PGP: key not found %08lX\n", (unsigned long) id[1]);
108   return GNUTLS_E_NO_CERTIFICATE_FOUND;
109 }
110
111 /**
112  * gnutls_openpgp_keyring_import - Import a raw- or Base64-encoded keyring
113  * @keyring: The structure to store the parsed key.
114  * @data: The RAW or BASE64 encoded keyring.
115  * @format: One of #gnutls_openpgp_keyring_fmt elements.
116  *
117  * This function will convert the given RAW or Base64 encoded keyring
118  * to the native #gnutls_openpgp_keyring_t format.  The output will be
119  * stored in 'keyring'.
120  *
121  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
122  **/
123 int
124 gnutls_openpgp_keyring_import (gnutls_openpgp_keyring_t keyring,
125                                const gnutls_datum_t * data,
126                                gnutls_openpgp_crt_fmt_t format)
127 {
128   cdk_error_t err;
129   cdk_stream_t input = NULL;
130   size_t raw_len = 0;
131   opaque *raw_data = NULL;
132
133   if (data->data == NULL || data->size == 0)
134     {
135       gnutls_assert();
136       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
137     }
138
139   _gnutls_debug_log ("PGP: keyring import format '%s'\n",
140                      format == GNUTLS_OPENPGP_FMT_RAW ? "raw" : "base64");
141
142   /* Create a new stream from the given data, decode it, and import
143    * the raw database. This to avoid using opencdk streams which are
144    * not thread safe.
145    */
146   if (format == GNUTLS_OPENPGP_FMT_BASE64)
147     {
148       err = cdk_stream_tmp_from_mem (data->data, data->size, &input);
149       if (!err)
150         err = cdk_stream_set_armor_flag (input, 0);
151       if (err)
152         {
153           gnutls_assert ();
154           err = _gnutls_map_cdk_rc (err);
155           goto error;
156         }
157
158       raw_len = cdk_stream_get_length (input);
159       if (raw_len == 0)
160         {
161           gnutls_assert ();
162           err = GNUTLS_E_BASE64_DECODING_ERROR;
163           goto error;
164         }
165
166       raw_data = gnutls_malloc (raw_len);
167       if (raw_data == NULL)
168         {
169           gnutls_assert ();
170           err = GNUTLS_E_MEMORY_ERROR;
171           goto error;
172         }
173
174 #if 0
175       i = 0;
176       do {
177           err = cdk_stream_getc( input);
178           if (err != EOF) raw_data[i++] = err;
179       } while( err != EOF);
180
181       raw_len = i;
182 #else
183       ssize_t written=0;
184       do 
185         {
186           err = cdk_stream_read (input, raw_data+written, raw_len-written);
187
188           if (err > 0) written += err;
189         }
190       while( written < raw_len && err != EOF && err > 0);
191       
192       raw_len = written;
193 #endif
194       
195     }
196   else
197     {                           /* RAW */
198       raw_len = data->size;
199       raw_data = data->data;
200     }
201
202   err = cdk_keydb_new (&keyring->db, CDK_DBTYPE_DATA, raw_data, raw_len);
203   if (err)
204     gnutls_assert ();
205
206   return _gnutls_map_cdk_rc (err);
207
208 error:
209   gnutls_free (raw_data);
210   cdk_stream_close (input);
211
212   return err;
213 }
214
215 #define knode_is_pkey(node) \
216   cdk_kbnode_find_packet (node, CDK_PKT_PUBLIC_KEY)!=NULL
217
218 /**
219  * gnutls_openpgp_keyring_get_crt_count - return the number of certificates
220  * @ring: is an OpenPGP key ring
221  *
222  * This function will return the number of OpenPGP certificates
223  * present in the given keyring.
224  *
225  * Returns: the number of subkeys, or a negative value on error.
226  **/
227 int
228 gnutls_openpgp_keyring_get_crt_count (gnutls_openpgp_keyring_t ring)
229 {
230   cdk_kbnode_t knode;
231   cdk_error_t err;
232   cdk_keydb_search_t st;
233   int ret = 0;
234
235   err = cdk_keydb_search_start (&st, ring->db, CDK_DBSEARCH_NEXT, NULL);
236   if (err != CDK_Success)
237     {
238       gnutls_assert ();
239       return _gnutls_map_cdk_rc (err);
240     }
241
242   do
243     {
244       err = cdk_keydb_search (st, ring->db, &knode);
245       if (err != CDK_Error_No_Key && err != CDK_Success)
246         {
247           gnutls_assert ();
248           cdk_keydb_search_release (st);
249           return _gnutls_map_cdk_rc (err);
250         }
251
252       if (knode_is_pkey (knode))
253         ret++;
254
255       cdk_kbnode_release (knode);
256
257     }
258   while (err != CDK_Error_No_Key);
259
260   cdk_keydb_search_release (st);
261   return ret;
262 }
263
264 /**
265  * gnutls_openpgp_keyring_get_crt - export an openpgp certificate from a keyring
266  * @key: Holds the key.
267  * @idx: the index of the certificate to export
268  * @crt: An uninitialized &gnutls_openpgp_crt_t structure
269  *
270  * This function will extract an OpenPGP certificate from the given
271  * keyring.  If the index given is out of range
272  * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned. The
273  * returned structure needs to be deinited.
274  *
275  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
276  **/
277 int
278 gnutls_openpgp_keyring_get_crt (gnutls_openpgp_keyring_t ring,
279                                 unsigned int idx,
280                                 gnutls_openpgp_crt_t * cert)
281 {
282   cdk_kbnode_t knode;
283   cdk_error_t err;
284   int ret = 0, count = 0;
285   cdk_keydb_search_t st;
286
287   err = cdk_keydb_search_start (&st, ring->db, CDK_DBSEARCH_NEXT, NULL);
288   if (err != CDK_Success)
289     {
290       gnutls_assert ();
291       return _gnutls_map_cdk_rc (err);
292     }
293
294   do
295     {
296       err = cdk_keydb_search (st, ring->db, &knode);
297       if (err != CDK_EOF && err != CDK_Success)
298         {
299           gnutls_assert ();
300           cdk_keydb_search_release (st);
301           return _gnutls_map_cdk_rc (err);
302         }
303
304       if (idx == count && err == CDK_Success)
305         {
306           ret = gnutls_openpgp_crt_init (cert);
307           if (ret == 0)
308             (*cert)->knode = knode;
309           cdk_keydb_search_release (st);
310           return ret;
311         }
312
313       if (knode_is_pkey (knode))
314         count++;
315
316       cdk_kbnode_release (knode);
317
318     }
319   while (err != CDK_EOF);
320
321   cdk_keydb_search_release (st);
322   return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
323 }