1 /* kbnode.c - keyblock node utility functions
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, 2010
3 * Free Software Foundation, Inc.
7 * This file is part of OpenCDK.
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.
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.
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,
39 * @pkt: the packet to add
41 * Allocates a new key node and adds a packet.
44 cdk_kbnode_new (cdk_packet_t pkt)
48 n = cdk_calloc (1, sizeof *n);
57 _cdk_kbnode_clone (cdk_kbnode_t node)
59 /* Mark the node as clone which means that the packet
60 will not be freed, just the node itself. */
70 * Releases the memory of the node.
73 cdk_kbnode_release (cdk_kbnode_t node)
81 cdk_pkt_release (node->pkt);
92 * Marks the given node as deleted.
95 cdk_kbnode_delete (cdk_kbnode_t node)
102 /* Append NODE to ROOT. ROOT must exist! */
104 _cdk_kbnode_add (cdk_kbnode_t root, cdk_kbnode_t node)
108 for (n1 = root; n1->next; n1 = n1->next)
116 * @root: the root key node
117 * @node: the node to add
118 * @pkttype: packet type
120 * Inserts @node into the list after @root but before a packet which is not of
121 * type @pkttype (only if @pkttype != 0).
124 cdk_kbnode_insert (cdk_kbnode_t root, cdk_kbnode_t node,
125 cdk_packet_type_t pkttype)
129 node->next = root->next;
136 for (n1 = root; n1->next; n1 = n1->next)
137 if (pkttype != n1->next->pkt->pkttype)
139 node->next = n1->next;
143 /* No such packet, append */
151 * cdk_kbnode_find_prev:
152 * @root: the root key node
153 * @node: the key node
154 * @pkttype: packet type
156 * Finds the previous node (if @pkttype = 0) or the previous node
157 * with pkttype @pkttype in the list starting with @root of @node.
160 cdk_kbnode_find_prev (cdk_kbnode_t root, cdk_kbnode_t node,
161 cdk_packet_type_t pkttype)
165 for (n1 = NULL; root && root != node; root = root->next)
167 if (!pkttype || root->pkt->pkttype == pkttype)
175 * cdk_kbnode_find_next:
176 * @node: the key node
177 * @pkttype: packet type
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
187 cdk_kbnode_find_next (cdk_kbnode_t node, cdk_packet_type_t pkttype)
189 for (node = node->next; node; node = node->next)
193 else if (pkttype == CDK_PKT_USER_ID &&
194 (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
195 node->pkt->pkttype == CDK_PKT_SECRET_KEY))
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))
202 else if (node->pkt->pkttype == pkttype)
211 * @node: the key node
212 * @pkttype: packet type
214 * Tries to find the next node with the packettype @pkttype.
217 cdk_kbnode_find (cdk_kbnode_t node, cdk_packet_type_t pkttype)
219 for (; node; node = node->next)
221 if (node->pkt->pkttype == pkttype)
229 * cdk_kbnode_find_packet:
230 * @node: the key node
231 * @pkttype: packet type
233 * Same as cdk_kbnode_find but it returns the packet instead of the node.
236 cdk_kbnode_find_packet (cdk_kbnode_t node, cdk_packet_type_t pkttype)
240 res = cdk_kbnode_find (node, pkttype);
241 return res ? res->pkt : NULL;
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).
254 cdk_kbnode_walk (cdk_kbnode_t root, cdk_kbnode_t * ctx, int all)
271 while (!all && n && n->is_deleted);
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.
284 * Returns: true if any node has been changed
287 cdk_kbnode_commit (cdk_kbnode_t * root)
292 for (n = *root, nl = NULL; n; n = nl->next)
297 *root = nl = n->next;
301 cdk_pkt_release (n->pkt);
314 * @root: the root node
315 * @node: the node to delete
317 * Removes a node from the root node.
320 cdk_kbnode_remove (cdk_kbnode_t * root, cdk_kbnode_t node)
324 for (n = *root, nl = NULL; n; n = nl->next)
329 *root = nl = n->next;
333 cdk_pkt_release (n->pkt);
346 * @node: the node to move
347 * @where: destination place where to move the node.
349 * Moves NODE behind right after WHERE or to the beginning if WHERE is NULL.
352 cdk_kbnode_move (cdk_kbnode_t * root, cdk_kbnode_t node, cdk_kbnode_t where)
354 cdk_kbnode_t tmp, prev;
356 if (!root || !*root || !node)
358 for (prev = *root; prev && prev->next != node; prev = prev->next)
361 return; /* Node is not in the list */
364 { /* Move node before root */
367 prev->next = node->next;
372 if (node == where) /* Move it after where. */
375 node->next = where->next;
382 * cdk_kbnode_get_packet:
383 * @node: the key node
385 * Get packet in node.
387 * Returns: the packet which is stored inside the node in @node.
390 cdk_kbnode_get_packet (cdk_kbnode_t node)
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
404 * Tries to read a key node from the memory buffer @buf.
407 cdk_kbnode_read_from_mem (cdk_kbnode_t * ret_node,
408 const byte * buf, size_t buflen)
413 if (!ret_node || !buf)
414 return CDK_Inv_Value;
418 return CDK_Too_Short;
420 rc = cdk_stream_tmp_from_mem (buf, buflen, &inp);
423 rc = cdk_keydb_get_keyblock (inp, ret_node);
426 cdk_stream_close (inp);
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.
437 * The function acts similar to cdk_kbnode_write_to_mem but
438 * it allocates the buffer to avoid the lengthy second run.
441 cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node,
442 byte ** r_buf, size_t * r_buflen)
449 if (!node || !r_buf || !r_buflen)
452 return CDK_Inv_Value;
458 rc = cdk_stream_tmp_new (&s);
465 for (n = node; n; n = n->next)
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)
476 rc = cdk_pkt_write (s, n->pkt);
479 cdk_stream_close (s);
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);
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.
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.
506 cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes)
513 if (!node || !r_nbytes)
516 return CDK_Inv_Value;
519 rc = cdk_stream_tmp_new (&s);
526 for (n = node; n; n = n->next)
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)
537 rc = cdk_pkt_write (s, n->pkt);
540 cdk_stream_close (s);
546 cdk_stream_seek (s, 0);
547 len = cdk_stream_get_length (s);
550 *r_nbytes = len; /* Only return the length of the buffer */
551 cdk_stream_close (s);
560 *r_nbytes = cdk_stream_read (s, buf, len);
563 cdk_stream_close (s);
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
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.
582 cdk_kbnode_hash (cdk_kbnode_t node, digest_hd_st * md, int is_v4,
583 cdk_packet_type_t pkttype, int flags)
590 return CDK_Inv_Value;
594 pkt = cdk_kbnode_get_packet (node);
595 pkttype = pkt->pkttype;
599 pkt = cdk_kbnode_find_packet (node, pkttype);
603 return CDK_Inv_Packet;
609 case CDK_PKT_PUBLIC_KEY:
610 case CDK_PKT_PUBLIC_SUBKEY:
611 _cdk_hash_pubkey (pkt->pkt.public_key, md, flags & 1);
614 case CDK_PKT_USER_ID:
615 _cdk_hash_userid (pkt->pkt.user_id, is_v4, md);
618 case CDK_PKT_SIGNATURE:
619 _cdk_hash_sig_data (pkt->pkt.signature, md);