Tizen 2.0 Release
[external/libgnutls26.git] / lib / opencdk / kbnode.c
1 /* kbnode.c -  keyblock node utility functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, 2010
3  * Free Software Foundation, Inc.
4  *
5  * Author: Timo Schulz
6  *
7  * This file is part of OpenCDK.
8  *
9  * The OpenCDK library 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 02110-1301,
22  * USA
23  *
24  */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "opencdk.h"
33 #include "main.h"
34 #include "packet.h"
35
36
37 /**
38  * cdk_kbnode_new:
39  * @pkt: the packet to add
40  *
41  * Allocates a new key node and adds a packet.
42  **/
43 cdk_kbnode_t
44 cdk_kbnode_new (cdk_packet_t pkt)
45 {
46   cdk_kbnode_t n;
47
48   n = cdk_calloc (1, sizeof *n);
49   if (!n)
50     return NULL;
51   n->pkt = pkt;
52   return n;
53 }
54
55
56 void
57 _cdk_kbnode_clone (cdk_kbnode_t node)
58 {
59   /* Mark the node as clone which means that the packet
60      will not be freed, just the node itself. */
61   if (node)
62     node->is_cloned = 1;
63 }
64
65
66 /**
67  * cdk_kbnode_release:
68  * @n: the key node
69  *
70  * Releases the memory of the node.
71  **/
72 void
73 cdk_kbnode_release (cdk_kbnode_t node)
74 {
75   cdk_kbnode_t n2;
76
77   while (node)
78     {
79       n2 = node->next;
80       if (!node->is_cloned)
81         cdk_pkt_release (node->pkt);
82       cdk_free (node);
83       node = n2;
84     }
85 }
86
87
88 /**
89  * cdk_kbnode_delete:
90  * @node: the key node
91  *
92  * Marks the given node as deleted.
93  **/
94 void
95 cdk_kbnode_delete (cdk_kbnode_t node)
96 {
97   if (node)
98     node->is_deleted = 1;
99 }
100
101
102 /* Append NODE to ROOT.  ROOT must exist! */
103 void
104 _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node)
105 {
106   cdk_kbnode_t n1;
107
108   for (n1 = root; n1->next; n1 = n1->next)
109     ;
110   n1->next = node;
111 }
112
113
114 /**
115  * cdk_kbnode_insert:
116  * @root: the root key node
117  * @node: the node to add
118  * @pkttype: packet type
119  *
120  * Inserts @node into the list after @root but before a packet which is not of
121  * type @pkttype (only if @pkttype != 0).
122  **/
123 void
124 cdk_kbnode_insert (cdk_kbnode_t root, cdk_kbnode_t node,
125                    cdk_packet_type_t pkttype)
126 {
127   if (!pkttype)
128     {
129       node->next = root->next;
130       root->next = node;
131     }
132   else
133     {
134       cdk_kbnode_t n1;
135
136       for (n1 = root; n1->next; n1 = n1->next)
137         if (pkttype != n1->next->pkt->pkttype)
138           {
139             node->next = n1->next;
140             n1->next = node;
141             return;
142           }
143       /* No such packet, append */
144       node->next = NULL;
145       n1->next = node;
146     }
147 }
148
149
150 /**
151  * cdk_kbnode_find_prev:
152  * @root: the root key node
153  * @node: the key node
154  * @pkttype: packet type
155  *
156  * Finds the previous node (if @pkttype = 0) or the previous node
157  * with pkttype @pkttype in the list starting with @root of @node.
158  **/
159 cdk_kbnode_t
160 cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node,
161                       cdk_packet_type_t pkttype)
162 {
163   cdk_kbnode_t n1;
164
165   for (n1 = NULL; root && root != node; root = root->next)
166     {
167       if (!pkttype || root->pkt->pkttype == pkttype)
168         n1 = root;
169     }
170   return n1;
171 }
172
173
174 /**
175  * cdk_kbnode_find_next:
176  * @node: the key node
177  * @pkttype: packet type
178  *
179  * Ditto, but find the next packet.  The behaviour is trivial if
180  * @pkttype is 0 but if it is specified, the next node with a packet
181  * of this type is returned.  The function has some knowledge about
182  * the valid ordering of packets: e.g. if the next signature packet
183  * is requested, the function will not return one if it encounters
184  * a user-id.
185  **/
186 cdk_kbnode_t
187 cdk_kbnode_find_next (cdk_kbnode_t node, cdk_packet_type_t pkttype)
188 {
189   for (node = node->next; node; node = node->next)
190     {
191       if (!pkttype)
192         return node;
193       else if (pkttype == CDK_PKT_USER_ID &&
194                (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
195                 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
196         return NULL;
197       else if (pkttype == CDK_PKT_SIGNATURE &&
198                (node->pkt->pkttype == CDK_PKT_USER_ID ||
199                 node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
200                 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
201         return NULL;
202       else if (node->pkt->pkttype == pkttype)
203         return node;
204     }
205   return NULL;
206 }
207
208
209 /**
210  * cdk_kbnode_find:
211  * @node: the key node
212  * @pkttype: packet type
213  *
214  * Tries to find the next node with the packettype @pkttype.
215  **/
216 cdk_kbnode_t
217 cdk_kbnode_find (cdk_kbnode_t node, cdk_packet_type_t pkttype)
218 {
219   for (; node; node = node->next)
220     {
221       if (node->pkt->pkttype == pkttype)
222         return node;
223     }
224   return NULL;
225 }
226
227
228 /**
229  * cdk_kbnode_find_packet:
230  * @node: the key node
231  * @pkttype: packet type
232  *
233  * Same as cdk_kbnode_find but it returns the packet instead of the node.
234  **/
235 cdk_packet_t
236 cdk_kbnode_find_packet (cdk_kbnode_t node, cdk_packet_type_t pkttype)
237 {
238   cdk_kbnode_t res;
239
240   res = cdk_kbnode_find (node, pkttype);
241   return res ? res->pkt : NULL;
242 }
243
244
245 /**
246  * cdk_kbnode_walk:
247  * 
248  * Walks through a list of kbnodes. This function returns
249  * the next kbnode for each call; before using the function the first
250  * time, the caller must set CONTEXT to NULL (This has simply the effect
251  * to start with ROOT).
252  */
253 cdk_kbnode_t
254 cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * ctx, int all)
255 {
256   cdk_kbnode_t n;
257
258   do
259     {
260       if (!*ctx)
261         {
262           *ctx = root;
263           n = root;
264         }
265       else
266         {
267           n = (*ctx)->next;
268           *ctx = n;
269         }
270     }
271   while (!all && n && n->is_deleted);
272   return n;
273 }
274
275
276 /**
277  * cdk_kbnode_commit:
278  * @root: the nodes
279  * 
280  * Commits changes made to the kblist at ROOT. Note that ROOT my change,
281  * and it is therefore passed by reference.
282  * The function has the effect of removing all nodes marked as deleted.
283  *
284  * Returns: true if any node has been changed
285  */
286 int
287 cdk_kbnode_commit (cdk_kbnode_t * root)
288 {
289   cdk_kbnode_t n, nl;
290   int changed = 0;
291
292   for (n = *root, nl = NULL; n; n = nl->next)
293     {
294       if (n->is_deleted)
295         {
296           if (n == *root)
297             *root = nl = n->next;
298           else
299             nl->next = n->next;
300           if (!n->is_cloned)
301             cdk_pkt_release (n->pkt);
302           cdk_free (n);
303           changed = 1;
304         }
305       else
306         nl = n;
307     }
308   return changed;
309 }
310
311
312 /**
313  * cdk_kbnode_remove:
314  * @root: the root node
315  * @node: the node to delete
316  * 
317  * Removes a node from the root node.
318  */
319 void
320 cdk_kbnode_remove (cdk_kbnode_t * root, cdk_kbnode_t node)
321 {
322   cdk_kbnode_t n, nl;
323
324   for (n = *root, nl = NULL; n; n = nl->next)
325     {
326       if (n == node)
327         {
328           if (n == *root)
329             *root = nl = n->next;
330           else
331             nl->next = n->next;
332           if (!n->is_cloned)
333             cdk_pkt_release (n->pkt);
334           cdk_free (n);
335         }
336       else
337         nl = n;
338     }
339 }
340
341
342
343 /**
344  * cdk_cdknode_move:
345  * @root: root node
346  * @node: the node to move
347  * @where: destination place where to move the node.
348  * 
349  * Moves NODE behind right after WHERE or to the beginning if WHERE is NULL.
350  */
351 void
352 cdk_kbnode_move (cdk_kbnode_t * root, cdk_kbnode_t node, cdk_kbnode_t where)
353 {
354   cdk_kbnode_t tmp, prev;
355
356   if (!root || !*root || !node)
357     return;
358   for (prev = *root; prev && prev->next != node; prev = prev->next)
359     ;
360   if (!prev)
361     return;                     /* Node is not in the list */
362
363   if (!where)
364     {                           /* Move node before root */
365       if (node == *root)
366         return;
367       prev->next = node->next;
368       node->next = *root;
369       *root = node;
370       return;
371     }
372   if (node == where)            /* Move it after where. */
373     return;
374   tmp = node->next;
375   node->next = where->next;
376   where->next = node;
377   prev->next = tmp;
378 }
379
380
381 /**
382  * cdk_kbnode_get_packet:
383  * @node: the key node
384  *
385  * Get packet in node.
386  *
387  * Returns: the packet which is stored inside the node in @node.
388  **/
389 cdk_packet_t
390 cdk_kbnode_get_packet (cdk_kbnode_t node)
391 {
392   if (node)
393     return node->pkt;
394   return NULL;
395 }
396
397
398 /**
399  * cdk_kbnode_read_from_mem:
400  * @ret_node: the new key node
401  * @buf: the buffer which stores the key sequence
402  * @buflen: the length of the buffer
403  *
404  * Tries to read a key node from the memory buffer @buf.
405  **/
406 cdk_error_t
407 cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
408                           const byte * buf, size_t buflen)
409 {
410   cdk_stream_t inp;
411   cdk_error_t rc;
412
413   if (!ret_node || !buf)
414     return CDK_Inv_Value;
415
416   *ret_node = NULL;
417   if (!buflen)
418     return CDK_Too_Short;
419
420   rc = cdk_stream_tmp_from_mem (buf, buflen, &inp);
421   if (rc)
422     return rc;
423   rc = cdk_keydb_get_keyblock (inp, ret_node);
424   if (rc)
425     gnutls_assert ();
426   cdk_stream_close (inp);
427   return rc;
428 }
429
430
431 /**
432  * cdk_kbnode_write_to_mem_alloc:
433  * @node: the key node
434  * @r_buf: buffer to hold the raw data
435  * @r_buflen: buffer length of the allocated raw data.
436  * 
437  * The function acts similar to cdk_kbnode_write_to_mem but
438  * it allocates the buffer to avoid the lengthy second run.
439  */
440 cdk_error_t
441 cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
442                                byte ** r_buf, size_t * r_buflen)
443 {
444   cdk_kbnode_t n;
445   cdk_stream_t s;
446   cdk_error_t rc;
447   size_t len;
448
449   if (!node || !r_buf || !r_buflen)
450     {
451       gnutls_assert ();
452       return CDK_Inv_Value;
453     }
454
455   *r_buf = NULL;
456   *r_buflen = 0;
457
458   rc = cdk_stream_tmp_new (&s);
459   if (rc)
460     {
461       gnutls_assert ();
462       return rc;
463     }
464
465   for (n = node; n; n = n->next)
466     {
467       /* Skip all packets which cannot occur in a key composition. */
468       if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
469           n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
470           n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
471           n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
472           n->pkt->pkttype != CDK_PKT_SIGNATURE &&
473           n->pkt->pkttype != CDK_PKT_USER_ID &&
474           n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
475         continue;
476       rc = cdk_pkt_write (s, n->pkt);
477       if (rc)
478         {
479           cdk_stream_close (s);
480           gnutls_assert ();
481           return rc;
482         }
483     }
484
485   cdk_stream_seek (s, 0);
486   len = cdk_stream_get_length (s);
487   *r_buf = cdk_calloc (1, len);
488   *r_buflen = cdk_stream_read (s, *r_buf, len);
489   cdk_stream_close (s);
490   return 0;
491 }
492
493
494 /**
495  * cdk_kbnode_write_to_mem:
496  * @node: the key node
497  * @buf: the buffer to store the node data
498  * @r_nbytes: the new length of the buffer.
499  *
500  * Tries to write the contents of the key node to the buffer @buf and
501  * return the length of it in @r_nbytes. If buf is zero, only the
502  * length of the node is calculated and returned in @r_nbytes.
503  * Whenever it is possible, the cdk_kbnode_write_to_mem_alloc should be used.
504  **/
505 cdk_error_t
506 cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes)
507 {
508   cdk_kbnode_t n;
509   cdk_stream_t s;
510   cdk_error_t rc;
511   size_t len;
512
513   if (!node || !r_nbytes)
514     {
515       gnutls_assert ();
516       return CDK_Inv_Value;
517     }
518
519   rc = cdk_stream_tmp_new (&s);
520   if (rc)
521     {
522       gnutls_assert ();
523       return rc;
524     }
525
526   for (n = node; n; n = n->next)
527     {
528       /* Skip all packets which cannot occur in a key composition. */
529       if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
530           n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
531           n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
532           n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
533           n->pkt->pkttype != CDK_PKT_SIGNATURE &&
534           n->pkt->pkttype != CDK_PKT_USER_ID &&
535           n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
536         continue;
537       rc = cdk_pkt_write (s, n->pkt);
538       if (rc)
539         {
540           cdk_stream_close (s);
541           gnutls_assert ();
542           return rc;
543         }
544     }
545
546   cdk_stream_seek (s, 0);
547   len = cdk_stream_get_length (s);
548   if (!buf)
549     {
550       *r_nbytes = len;          /* Only return the length of the buffer */
551       cdk_stream_close (s);
552       return 0;
553     }
554   if (*r_nbytes < len)
555     {
556       *r_nbytes = len;
557       rc = CDK_Too_Short;
558     }
559   if (!rc)
560     *r_nbytes = cdk_stream_read (s, buf, len);
561   else
562     gnutls_assert ();
563   cdk_stream_close (s);
564   return rc;
565 }
566
567
568 /**
569  * cdk_kbnode_hash:
570  * @node: the key node
571  * @hashctx: opaque pointer to the hash context
572  * @is_v4: OpenPGP signature (yes=1, no=0)
573  * @pkttype: packet type to hash (if zero use the packet type from the node)
574  * @flags: flags which depend on the operation
575  *
576  * Hashes the key node contents. Two modes are supported. If the packet
577  * type is used (!= 0) then the function searches the first node with
578  * this type. Otherwise the node is seen as a single node and the type
579  * is extracted from it.
580  **/
581 cdk_error_t
582 cdk_kbnode_hash (cdk_kbnode_t node, digest_hd_st * md, int is_v4,
583                  cdk_packet_type_t pkttype, int flags)
584 {
585   cdk_packet_t pkt;
586
587   if (!node || !md)
588     {
589       gnutls_assert ();
590       return CDK_Inv_Value;
591     }
592   if (!pkttype)
593     {
594       pkt = cdk_kbnode_get_packet (node);
595       pkttype = pkt->pkttype;
596     }
597   else
598     {
599       pkt = cdk_kbnode_find_packet (node, pkttype);
600       if (!pkt)
601         {
602           gnutls_assert ();
603           return CDK_Inv_Packet;
604         }
605     }
606
607   switch (pkttype)
608     {
609     case CDK_PKT_PUBLIC_KEY:
610     case CDK_PKT_PUBLIC_SUBKEY:
611       _cdk_hash_pubkey (pkt->pkt.public_key, md, flags & 1);
612       break;
613
614     case CDK_PKT_USER_ID:
615       _cdk_hash_userid (pkt->pkt.user_id, is_v4, md);
616       break;
617
618     case CDK_PKT_SIGNATURE:
619       _cdk_hash_sig_data (pkt->pkt.signature, md);
620       break;
621
622     default:
623       gnutls_assert ();
624       return CDK_Inv_Mode;
625     }
626   return 0;
627 }