Provide compatibility inline functions for gnutls_session_get_server_random() and...
[gnutls.git] / lib / opencdk / kbnode.c
blob8a93e9b87d407affa539e63c4eedf09eb014c215
1 /* kbnode.c - keyblock node utility functions
2 * Copyright (C) 1998-2012 Free Software Foundation, Inc.
4 * Author: Timo Schulz
6 * This file is part of OpenCDK.
8 * The OpenCDK 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 3 of
11 * the License, or (at your option) any later version.
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.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include "opencdk.h"
31 #include "main.h"
32 #include "packet.h"
35 /**
36 * cdk_kbnode_new:
37 * @pkt: the packet to add
39 * Allocates a new key node and adds a packet.
40 **/
41 cdk_kbnode_t
42 cdk_kbnode_new (cdk_packet_t pkt)
44 cdk_kbnode_t n;
46 n = cdk_calloc (1, sizeof *n);
47 if (!n)
48 return NULL;
49 n->pkt = pkt;
50 return n;
54 void
55 _cdk_kbnode_clone (cdk_kbnode_t node)
57 /* Mark the node as clone which means that the packet
58 will not be freed, just the node itself. */
59 if (node)
60 node->is_cloned = 1;
64 /**
65 * cdk_kbnode_release:
66 * @n: the key node
68 * Releases the memory of the node.
69 **/
70 void
71 cdk_kbnode_release (cdk_kbnode_t node)
73 cdk_kbnode_t n2;
75 while (node)
77 n2 = node->next;
78 if (!node->is_cloned)
79 cdk_pkt_release (node->pkt);
80 cdk_free (node);
81 node = n2;
86 /**
87 * cdk_kbnode_delete:
88 * @node: the key node
90 * Marks the given node as deleted.
91 **/
92 void
93 cdk_kbnode_delete (cdk_kbnode_t node)
95 if (node)
96 node->is_deleted = 1;
100 /* Append NODE to ROOT. ROOT must exist! */
101 void
102 _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node)
104 cdk_kbnode_t n1;
106 for (n1 = root; n1->next; n1 = n1->next)
108 n1->next = node;
113 * cdk_kbnode_insert:
114 * @root: the root key node
115 * @node: the node to add
116 * @pkttype: packet type
118 * Inserts @node into the list after @root but before a packet which is not of
119 * type @pkttype (only if @pkttype != 0).
121 void
122 cdk_kbnode_insert (cdk_kbnode_t root, cdk_kbnode_t node,
123 cdk_packet_type_t pkttype)
125 if (!pkttype)
127 node->next = root->next;
128 root->next = node;
130 else
132 cdk_kbnode_t n1;
134 for (n1 = root; n1->next; n1 = n1->next)
135 if (pkttype != n1->next->pkt->pkttype)
137 node->next = n1->next;
138 n1->next = node;
139 return;
141 /* No such packet, append */
142 node->next = NULL;
143 n1->next = node;
149 * cdk_kbnode_find_prev:
150 * @root: the root key node
151 * @node: the key node
152 * @pkttype: packet type
154 * Finds the previous node (if @pkttype = 0) or the previous node
155 * with pkttype @pkttype in the list starting with @root of @node.
157 cdk_kbnode_t
158 cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node,
159 cdk_packet_type_t pkttype)
161 cdk_kbnode_t n1;
163 for (n1 = NULL; root && root != node; root = root->next)
165 if (!pkttype || root->pkt->pkttype == pkttype)
166 n1 = root;
168 return n1;
173 * cdk_kbnode_find_next:
174 * @node: the key node
175 * @pkttype: packet type
177 * Ditto, but find the next packet. The behaviour is trivial if
178 * @pkttype is 0 but if it is specified, the next node with a packet
179 * of this type is returned. The function has some knowledge about
180 * the valid ordering of packets: e.g. if the next signature packet
181 * is requested, the function will not return one if it encounters
182 * a user-id.
184 cdk_kbnode_t
185 cdk_kbnode_find_next (cdk_kbnode_t node, cdk_packet_type_t pkttype)
187 for (node = node->next; node; node = node->next)
189 if (!pkttype)
190 return node;
191 else if (pkttype == CDK_PKT_USER_ID &&
192 (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
193 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
194 return NULL;
195 else if (pkttype == CDK_PKT_SIGNATURE &&
196 (node->pkt->pkttype == CDK_PKT_USER_ID ||
197 node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
198 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
199 return NULL;
200 else if (node->pkt->pkttype == pkttype)
201 return node;
203 return NULL;
208 * cdk_kbnode_find:
209 * @node: the key node
210 * @pkttype: packet type
212 * Tries to find the next node with the packettype @pkttype.
214 cdk_kbnode_t
215 cdk_kbnode_find (cdk_kbnode_t node, cdk_packet_type_t pkttype)
217 for (; node; node = node->next)
219 if (node->pkt->pkttype == pkttype)
220 return node;
222 return NULL;
227 * cdk_kbnode_find_packet:
228 * @node: the key node
229 * @pkttype: packet type
231 * Same as cdk_kbnode_find but it returns the packet instead of the node.
233 cdk_packet_t
234 cdk_kbnode_find_packet (cdk_kbnode_t node, cdk_packet_type_t pkttype)
236 cdk_kbnode_t res;
238 res = cdk_kbnode_find (node, pkttype);
239 return res ? res->pkt : NULL;
244 * cdk_kbnode_walk:
246 * Walks through a list of kbnodes. This function returns
247 * the next kbnode for each call; before using the function the first
248 * time, the caller must set CONTEXT to NULL (This has simply the effect
249 * to start with ROOT).
251 cdk_kbnode_t
252 cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * ctx, int all)
254 cdk_kbnode_t n;
258 if (!*ctx)
260 *ctx = root;
261 n = root;
263 else
265 n = (*ctx)->next;
266 *ctx = n;
269 while (!all && n && n->is_deleted);
270 return n;
275 * cdk_kbnode_commit:
276 * @root: the nodes
278 * Commits changes made to the kblist at ROOT. Note that ROOT my change,
279 * and it is therefore passed by reference.
280 * The function has the effect of removing all nodes marked as deleted.
282 * Returns: true if any node has been changed
285 cdk_kbnode_commit (cdk_kbnode_t * root)
287 cdk_kbnode_t n, nl;
288 int changed = 0;
290 for (n = *root, nl = NULL; n; n = nl->next)
292 if (n->is_deleted)
294 if (n == *root)
295 *root = nl = n->next;
296 else
297 nl->next = n->next;
298 if (!n->is_cloned)
299 cdk_pkt_release (n->pkt);
300 cdk_free (n);
301 changed = 1;
303 else
304 nl = n;
306 return changed;
311 * cdk_kbnode_remove:
312 * @root: the root node
313 * @node: the node to delete
315 * Removes a node from the root node.
317 void
318 cdk_kbnode_remove (cdk_kbnode_t * root, cdk_kbnode_t node)
320 cdk_kbnode_t n, nl;
322 for (n = *root, nl = NULL; n; n = nl->next)
324 if (n == node)
326 if (n == *root)
327 *root = nl = n->next;
328 else
329 nl->next = n->next;
330 if (!n->is_cloned)
331 cdk_pkt_release (n->pkt);
332 cdk_free (n);
334 else
335 nl = n;
342 * cdk_cdknode_move:
343 * @root: root node
344 * @node: the node to move
345 * @where: destination place where to move the node.
347 * Moves NODE behind right after WHERE or to the beginning if WHERE is NULL.
349 void
350 cdk_kbnode_move (cdk_kbnode_t * root, cdk_kbnode_t node, cdk_kbnode_t where)
352 cdk_kbnode_t tmp, prev;
354 if (!root || !*root || !node)
355 return;
356 for (prev = *root; prev && prev->next != node; prev = prev->next)
358 if (!prev)
359 return; /* Node is not in the list */
361 if (!where)
362 { /* Move node before root */
363 if (node == *root)
364 return;
365 prev->next = node->next;
366 node->next = *root;
367 *root = node;
368 return;
370 if (node == where) /* Move it after where. */
371 return;
372 tmp = node->next;
373 node->next = where->next;
374 where->next = node;
375 prev->next = tmp;
380 * cdk_kbnode_get_packet:
381 * @node: the key node
383 * Get packet in node.
385 * Returns: the packet which is stored inside the node in @node.
387 cdk_packet_t
388 cdk_kbnode_get_packet (cdk_kbnode_t node)
390 if (node)
391 return node->pkt;
392 return NULL;
397 * cdk_kbnode_read_from_mem:
398 * @ret_node: the new key node
399 * @armor: whether base64 or not
400 * @buf: the buffer which stores the key sequence
401 * @buflen: the length of the buffer
403 * Tries to read a key node from the memory buffer @buf.
405 cdk_error_t
406 cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
407 int armor,
408 const byte * buf, size_t buflen)
410 cdk_stream_t inp;
411 cdk_error_t rc;
413 if (!ret_node || !buf)
414 return CDK_Inv_Value;
416 *ret_node = NULL;
417 if (!buflen)
418 return CDK_Too_Short;
420 rc = cdk_stream_tmp_from_mem (buf, buflen, &inp);
421 if (rc)
422 return rc;
424 if (armor)
425 cdk_stream_set_armor_flag (inp, 0);
427 rc = cdk_keydb_get_keyblock (inp, ret_node);
428 if (rc)
429 gnutls_assert ();
430 cdk_stream_close (inp);
431 return rc;
436 * cdk_kbnode_write_to_mem_alloc:
437 * @node: the key node
438 * @r_buf: buffer to hold the raw data
439 * @r_buflen: buffer length of the allocated raw data.
441 * The function acts similar to cdk_kbnode_write_to_mem but
442 * it allocates the buffer to avoid the lengthy second run.
444 cdk_error_t
445 cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
446 byte ** r_buf, size_t * r_buflen)
448 cdk_kbnode_t n;
449 cdk_stream_t s;
450 cdk_error_t rc;
451 size_t len;
453 if (!node || !r_buf || !r_buflen)
455 gnutls_assert ();
456 return CDK_Inv_Value;
459 *r_buf = NULL;
460 *r_buflen = 0;
462 rc = cdk_stream_tmp_new (&s);
463 if (rc)
465 gnutls_assert ();
466 return rc;
469 for (n = node; n; n = n->next)
471 /* Skip all packets which cannot occur in a key composition. */
472 if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
473 n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
474 n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
475 n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
476 n->pkt->pkttype != CDK_PKT_SIGNATURE &&
477 n->pkt->pkttype != CDK_PKT_USER_ID &&
478 n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
479 continue;
480 rc = cdk_pkt_write (s, n->pkt);
481 if (rc)
483 cdk_stream_close (s);
484 gnutls_assert ();
485 return rc;
489 cdk_stream_seek (s, 0);
490 len = cdk_stream_get_length (s);
491 *r_buf = cdk_calloc (1, len);
492 *r_buflen = cdk_stream_read (s, *r_buf, len);
493 cdk_stream_close (s);
494 return 0;
499 * cdk_kbnode_write_to_mem:
500 * @node: the key node
501 * @buf: the buffer to store the node data
502 * @r_nbytes: the new length of the buffer.
504 * Tries to write the contents of the key node to the buffer @buf and
505 * return the length of it in @r_nbytes. If buf is (0), only the
506 * length of the node is calculated and returned in @r_nbytes.
507 * Whenever it is possible, the cdk_kbnode_write_to_mem_alloc should be used.
509 cdk_error_t
510 cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes)
512 cdk_kbnode_t n;
513 cdk_stream_t s;
514 cdk_error_t rc;
515 size_t len;
517 if (!node || !r_nbytes)
519 gnutls_assert ();
520 return CDK_Inv_Value;
523 rc = cdk_stream_tmp_new (&s);
524 if (rc)
526 gnutls_assert ();
527 return rc;
530 for (n = node; n; n = n->next)
532 /* Skip all packets which cannot occur in a key composition. */
533 if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY &&
534 n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY &&
535 n->pkt->pkttype != CDK_PKT_SECRET_KEY &&
536 n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY &&
537 n->pkt->pkttype != CDK_PKT_SIGNATURE &&
538 n->pkt->pkttype != CDK_PKT_USER_ID &&
539 n->pkt->pkttype != CDK_PKT_ATTRIBUTE)
540 continue;
541 rc = cdk_pkt_write (s, n->pkt);
542 if (rc)
544 cdk_stream_close (s);
545 gnutls_assert ();
546 return rc;
550 cdk_stream_seek (s, 0);
551 len = cdk_stream_get_length (s);
552 if (!buf)
554 *r_nbytes = len; /* Only return the length of the buffer */
555 cdk_stream_close (s);
556 return 0;
558 if (*r_nbytes < len)
560 *r_nbytes = len;
561 rc = CDK_Too_Short;
563 if (!rc)
564 *r_nbytes = cdk_stream_read (s, buf, len);
565 else
566 gnutls_assert ();
567 cdk_stream_close (s);
568 return rc;
573 * cdk_kbnode_hash:
574 * @node: the key node
575 * @hashctx: uint8_t pointer to the hash context
576 * @is_v4: OpenPGP signature (yes=1, no=0)
577 * @pkttype: packet type to hash (if (0) use the packet type from the node)
578 * @flags: flags which depend on the operation
580 * Hashes the key node contents. Two modes are supported. If the packet
581 * type is used (!= 0) then the function searches the first node with
582 * this type. Otherwise the node is seen as a single node and the type
583 * is extracted from it.
585 cdk_error_t
586 cdk_kbnode_hash (cdk_kbnode_t node, digest_hd_st * md, int is_v4,
587 cdk_packet_type_t pkttype, int flags)
589 cdk_packet_t pkt;
591 if (!node || !md)
593 gnutls_assert ();
594 return CDK_Inv_Value;
596 if (!pkttype)
598 pkt = cdk_kbnode_get_packet (node);
599 pkttype = pkt->pkttype;
601 else
603 pkt = cdk_kbnode_find_packet (node, pkttype);
604 if (!pkt)
606 gnutls_assert ();
607 return CDK_Inv_Packet;
611 switch (pkttype)
613 case CDK_PKT_PUBLIC_KEY:
614 case CDK_PKT_PUBLIC_SUBKEY:
615 _cdk_hash_pubkey (pkt->pkt.public_key, md, flags & 1);
616 break;
618 case CDK_PKT_USER_ID:
619 _cdk_hash_userid (pkt->pkt.user_id, is_v4, md);
620 break;
622 case CDK_PKT_SIGNATURE:
623 _cdk_hash_sig_data (pkt->pkt.signature, md);
624 break;
626 default:
627 gnutls_assert ();
628 return CDK_Inv_Mode;
630 return 0;