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