KBNODE make_mpi_comment_node( const char *s, gcry_mpi_t a ) { PACKET *pkt; byte *buf, *pp; size_t n1, nb1; size_t n = strlen(s); nb1 = mpi_get_nbits( a ); if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &n1, a)) BUG (); /* fixme: allocate it on the stack */ buf = xmalloc (n1); if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf, n1, &n1, a)) BUG (); pkt = xcalloc (1, sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = xmalloc ( sizeof *pkt->pkt.comment + n + 2 + n1 ); pkt->pkt.comment->len = n+1+2+n1; pp = pkt->pkt.comment->data; memcpy(pp, s, n+1); memcpy(pp+n+1, buf, n1 ); xfree (buf); return new_kbnode( pkt ); }
KBNODE make_comment_node_from_buffer (const char *s, size_t n) { PACKET *pkt; pkt = gcry_xcalloc( 1, sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = gcry_xmalloc( sizeof *pkt->pkt.comment + n - 1 ); pkt->pkt.comment->len = n; strcpy(pkt->pkt.comment->data, s); return new_kbnode( pkt ); }
KBNODE make_comment_node( const char *s ) { PACKET *pkt; size_t n = strlen(s); pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n - 1 ); pkt->pkt.comment->len = n; strcpy(pkt->pkt.comment->data, s); return new_kbnode( pkt ); }
KBNODE make_mpi_comment_node( const char *s, MPI a ) { PACKET *pkt; byte *buf, *p, *pp; unsigned n1, nb1; size_t n = strlen(s); nb1 = mpi_get_nbits( a ); p = buf = mpi_get_buffer( a, &n1, NULL ); pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n + 2 + n1 ); pkt->pkt.comment->len = n+1+2+n1; pp = pkt->pkt.comment->data; memcpy(pp, s, n+1); pp[n+1] = nb1 >> 8; pp[n+2] = nb1 ; memcpy(pp+n+3, p, n1 ); m_free(buf); return new_kbnode( pkt ); }
/* * Return the last found keyring. Caller must free it. * The returned keyblock has the kbode flag bit 0 set for the node with * the public key used to locate the keyblock or flag bit 1 set for * the user ID node. */ int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) { PACKET *pkt; int rc; KBNODE keyblock = NULL, node, lastnode; IOBUF a; int in_cert = 0; int pk_no = 0; int uid_no = 0; int save_mode; if (ret_kb) *ret_kb = NULL; if (!hd->found.kr) return -1; /* no successful search */ a = iobuf_open (hd->found.kr->fname); if (!a) { log_error(_("can't open `%s'\n"), hd->found.kr->fname); return G10ERR_KEYRING_OPEN; } if (iobuf_seek (a, hd->found.offset) ) { log_error ("can't seek `%s'\n", hd->found.kr->fname); iobuf_close(a); return G10ERR_KEYRING_OPEN; } pkt = xmalloc (sizeof *pkt); init_packet (pkt); hd->found.n_packets = 0;; lastnode = NULL; save_mode = set_packet_list_mode(0); while ((rc=parse_packet (a, pkt)) != -1) { hd->found.n_packets++; if (rc == G10ERR_UNKNOWN_PACKET) { free_packet (pkt); init_packet (pkt); continue; } if (rc) { log_error ("keyring_get_keyblock: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; break; } if (pkt->pkttype == PKT_COMPRESSED) { log_error ("skipped compressed packet in keyring\n"); free_packet(pkt); init_packet(pkt); continue; } if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { hd->found.n_packets--; /* fix counter */ break; /* ready */ } in_cert = 1; if (pkt->pkttype == PKT_RING_TRUST) { /*(this code is duplicated after the loop)*/ if ( lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE && (pkt->pkt.ring_trust->sigcache & 1) ) { /* this is a ring trust packet with a checked signature * status cache following directly a signature paket. * Set the cache status into that signature packet */ PKT_signature *sig = lastnode->pkt->pkt.signature; sig->flags.checked = 1; sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2); } /* reset lastnode, so that we set the cache status only from * the ring trust packet immediately folling a signature */ lastnode = NULL; } else { node = lastnode = new_kbnode (pkt); if (!keyblock) keyblock = node; else add_kbnode (keyblock, node); if ( pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_PUBLIC_SUBKEY || pkt->pkttype == PKT_SECRET_KEY || pkt->pkttype == PKT_SECRET_SUBKEY) { if (++pk_no == hd->found.pk_no) node->flag |= 1; } else if ( pkt->pkttype == PKT_USER_ID) { if (++uid_no == hd->found.uid_no) node->flag |= 2; } } pkt = xmalloc (sizeof *pkt); init_packet(pkt); } set_packet_list_mode(save_mode); if (rc == -1 && keyblock) rc = 0; /* got the entire keyblock */ if (rc || !ret_kb) release_kbnode (keyblock); else { /*(duplicated form the loop body)*/ if ( pkt && pkt->pkttype == PKT_RING_TRUST && lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE && (pkt->pkt.ring_trust->sigcache & 1) ) { PKT_signature *sig = lastnode->pkt->pkt.signature; sig->flags.checked = 1; sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2); } *ret_kb = keyblock; } free_packet (pkt); xfree (pkt); iobuf_close(a); /* Make sure that future search operations fail immediately when * we know that we are working on a invalid keyring */ if (rc == G10ERR_INV_KEYRING) hd->current.error = rc; return rc; }
static gpg_error_t parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no, const u32 *sigstatus, kbnode_t *r_keyblock) { gpg_error_t err; PACKET *pkt; kbnode_t keyblock = NULL; kbnode_t node, *tail; int in_cert, save_mode; u32 n_sigs; int pk_count, uid_count; *r_keyblock = NULL; pkt = xtrymalloc (sizeof *pkt); if (!pkt) return gpg_error_from_syserror (); init_packet (pkt); save_mode = set_packet_list_mode (0); in_cert = 0; n_sigs = 0; tail = NULL; pk_count = uid_count = 0; while ((err = parse_packet (iobuf, pkt)) != -1) { if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET) { free_packet (pkt); init_packet (pkt); continue; } if (err) { log_error ("parse_keyblock_image: read error: %s\n", gpg_strerror (err)); err = gpg_error (GPG_ERR_INV_KEYRING); break; } if (pkt->pkttype == PKT_COMPRESSED) { log_error ("skipped compressed packet in keybox blob\n"); free_packet(pkt); init_packet(pkt); continue; } if (pkt->pkttype == PKT_RING_TRUST) { log_info ("skipped ring trust packet in keybox blob\n"); free_packet(pkt); init_packet(pkt); continue; } if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY) { log_error ("parse_keyblock_image: first packet in a keybox blob " "is not a public key packet\n"); err = gpg_error (GPG_ERR_INV_KEYRING); break; } if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { log_error ("parse_keyblock_image: " "multiple keyblocks in a keybox blob\n"); err = gpg_error (GPG_ERR_INV_KEYRING); break; } in_cert = 1; if (pkt->pkttype == PKT_SIGNATURE && sigstatus) { PKT_signature *sig = pkt->pkt.signature; n_sigs++; if (n_sigs > sigstatus[0]) { log_error ("parse_keyblock_image: " "more signatures than found in the meta data\n"); err = gpg_error (GPG_ERR_INV_KEYRING); break; } if (sigstatus[n_sigs]) { sig->flags.checked = 1; if (sigstatus[n_sigs] == 1 ) ; /* missing key */ else if (sigstatus[n_sigs] == 2 ) ; /* bad signature */ else if (sigstatus[n_sigs] < 0x10000000) ; /* bad flag */ else { sig->flags.valid = 1; /* Fixme: Shall we set the expired flag here? */ } } } node = new_kbnode (pkt); switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: if (++pk_count == pk_no) node->flag |= 1; break; case PKT_USER_ID: if (++uid_count == uid_no) node->flag |= 2; break; default: break; } if (!keyblock) keyblock = node; else *tail = node; tail = &node->next; pkt = xtrymalloc (sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); break; } init_packet (pkt); } set_packet_list_mode (save_mode); if (err == -1 && keyblock) err = 0; /* Got the entire keyblock. */ if (!err && sigstatus && n_sigs != sigstatus[0]) { log_error ("parse_keyblock_image: signature count does not match\n"); err = gpg_error (GPG_ERR_INV_KEYRING); } if (err) release_kbnode (keyblock); else *r_keyblock = keyblock; free_packet (pkt); xfree (pkt); return err; }
/* * Return the last found keyring. Caller must free it. * The returned keyblock has the kbode flag bit 0 set for the node with * the public key used to locate the keyblock or flag bit 1 set for * the user ID node. */ int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) { PACKET *pkt; int rc; KBNODE keyblock = NULL, node, lastnode; IOBUF a; int in_cert = 0; int pk_no = 0; int uid_no = 0; int save_mode; if (ret_kb) *ret_kb = NULL; if (!hd->found.kr) return -1; /* no successful search */ a = iobuf_open (hd->found.kr->fname); if (!a) { log_error(_("can't open `%s'\n"), hd->found.kr->fname); return G10ERR_KEYRING_OPEN; } if (iobuf_seek (a, hd->found.offset) ) { log_error ("can't seek `%s'\n", hd->found.kr->fname); iobuf_close(a); return G10ERR_KEYRING_OPEN; } pkt = xmalloc (sizeof *pkt); init_packet (pkt); hd->found.n_packets = 0;; lastnode = NULL; save_mode = set_packet_list_mode(0); while ((rc=parse_packet (a, pkt)) != -1) { hd->found.n_packets++; if (rc == G10ERR_UNKNOWN_PACKET) { free_packet (pkt); init_packet (pkt); continue; } if (rc) { log_error ("keyring_get_keyblock: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; break; } /* Filter allowed packets. */ switch (pkt->pkttype){ case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: case PKT_USER_ID: case PKT_ATTRIBUTE: case PKT_SIGNATURE: break; /* Allowed per RFC. */ case PKT_RING_TRUST: case PKT_OLD_COMMENT: case PKT_COMMENT: case PKT_GPG_CONTROL: break; /* Allowed by us. */ default: log_error ("skipped packet of type %d in keyring\n", (int)pkt->pkttype); free_packet(pkt); init_packet(pkt); continue; } if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { hd->found.n_packets--; /* fix counter */ break; /* ready */ } in_cert = 1; if (pkt->pkttype == PKT_RING_TRUST) { /*(this code is duplicated after the loop)*/ if ( lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE && (pkt->pkt.ring_trust->sigcache & 1) ) { /* This is a ring trust packet with a checked signature * status cache following directly a signature paket. * Set the cache status into that signature packet. * * We do not use cached signatures made with MD5 to * avoid using a cached status created with an older * version of gpg. */ PKT_signature *sig = lastnode->pkt->pkt.signature; if (sig->digest_algo != DIGEST_ALGO_MD5) { sig->flags.checked = 1; sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2); } } /* Reset LASTNODE, so that we set the cache status only from * the ring trust packet immediately following a signature. */ lastnode = NULL; free_packet(pkt); init_packet(pkt); continue; } node = lastnode = new_kbnode (pkt); if (!keyblock) keyblock = node; else add_kbnode (keyblock, node); switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: if (++pk_no == hd->found.pk_no) node->flag |= 1; break; case PKT_USER_ID: if (++uid_no == hd->found.uid_no) node->flag |= 2; break; default: break; } pkt = xmalloc (sizeof *pkt); init_packet(pkt); } set_packet_list_mode(save_mode); if (rc == -1 && keyblock) rc = 0; /* got the entire keyblock */ if (rc || !ret_kb) release_kbnode (keyblock); else { /*(duplicated from the loop body)*/ if ( pkt && pkt->pkttype == PKT_RING_TRUST && lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE && (pkt->pkt.ring_trust->sigcache & 1) ) { PKT_signature *sig = lastnode->pkt->pkt.signature; if (sig->digest_algo != DIGEST_ALGO_MD5) { sig->flags.checked = 1; sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2); } } *ret_kb = keyblock; } free_packet (pkt); xfree (pkt); iobuf_close(a); /* Make sure that future search operations fail immediately when * we know that we are working on a invalid keyring */ if (rc == G10ERR_INV_KEYRING) hd->current.error = rc; return rc; }
/* * Return the last found keyblock. Caller must free it. * The returned keyblock has the kbode flag bit 0 set for the node with * the public key used to locate the keyblock or flag bit 1 set for * the user ID node. */ int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) { PACKET *pkt; struct parse_packet_ctx_s parsectx; int rc; KBNODE keyblock = NULL, node, lastnode; IOBUF a; int in_cert = 0; int pk_no = 0; int uid_no = 0; int save_mode; if (ret_kb) *ret_kb = NULL; if (!hd->found.kr) return -1; /* no successful search */ a = iobuf_open (hd->found.kr->fname); if (!a) { log_error(_("can't open '%s'\n"), hd->found.kr->fname); return GPG_ERR_KEYRING_OPEN; } if (iobuf_seek (a, hd->found.offset) ) { log_error ("can't seek '%s'\n", hd->found.kr->fname); iobuf_close(a); return GPG_ERR_KEYRING_OPEN; } pkt = xmalloc (sizeof *pkt); init_packet (pkt); init_parse_packet (&parsectx, a); hd->found.n_packets = 0; lastnode = NULL; save_mode = set_packet_list_mode(0); while ((rc=parse_packet (&parsectx, pkt)) != -1) { hd->found.n_packets = parsectx.n_parsed_packets; if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) { free_packet (pkt, &parsectx); init_packet (pkt); continue; } if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY) { if (in_cert) /* It is not this key that is problematic, but the following key. */ { rc = 0; hd->found.n_packets --; } else /* Upper layer needs to handle this. */ { } break; } if (rc) { log_error ("keyring_get_keyblock: read error: %s\n", gpg_strerror (rc) ); rc = GPG_ERR_INV_KEYRING; break; } /* Filter allowed packets. */ switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: case PKT_USER_ID: case PKT_ATTRIBUTE: case PKT_SIGNATURE: break; /* Allowed per RFC. */ case PKT_RING_TRUST: case PKT_OLD_COMMENT: case PKT_COMMENT: case PKT_GPG_CONTROL: break; /* Allowed by us. */ default: log_info ("skipped packet of type %d in keyring\n", (int)pkt->pkttype); free_packet(pkt, &parsectx); init_packet(pkt); continue; } if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { hd->found.n_packets--; /* fix counter */ break; /* ready */ } in_cert = 1; node = lastnode = new_kbnode (pkt); if (!keyblock) keyblock = node; else add_kbnode (keyblock, node); switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: if (++pk_no == hd->found.pk_no) node->flag |= 1; break; case PKT_USER_ID: if (++uid_no == hd->found.uid_no) node->flag |= 2; break; default: break; } pkt = xmalloc (sizeof *pkt); init_packet(pkt); } set_packet_list_mode(save_mode); if (rc == -1 && keyblock) rc = 0; /* got the entire keyblock */ if (rc || !ret_kb) release_kbnode (keyblock); else { *ret_kb = keyblock; } free_packet (pkt, &parsectx); deinit_parse_packet (&parsectx); xfree (pkt); iobuf_close(a); /* Make sure that future search operations fail immediately when * we know that we are working on a invalid keyring */ if (gpg_err_code (rc) == GPG_ERR_INV_KEYRING) hd->current.error = rc; return rc; }