/** * cdk_file_verify: * @hd: the session handle * @file: the input file * @data_file: for detached signature this is the data file and @file is the sig. * @output: the output file * * Verify a signature. **/ cdk_error_t cdk_file_verify (cdk_ctx_t hd, const char *file, const char *data_file, const char *output) { struct stat stbuf; cdk_stream_t inp, data; char buf[4096]; int n; cdk_error_t rc; if (!hd || !file) return CDK_Inv_Value; if (output && !hd->opt.overwrite && !stat (output, &stbuf)) return CDK_Inv_Mode; rc = cdk_stream_open (file, &inp); if (rc) return rc; if (cdk_armor_filter_use (inp)) { n = cdk_stream_peek (inp, (byte *) buf, DIM (buf) - 1); if (!n || n == -1) return CDK_EOF; buf[n] = '\0'; if (strstr (buf, "BEGIN PGP SIGNED MESSAGE")) { cdk_stream_close (inp); return file_verify_clearsign (hd, file, output); } cdk_stream_set_armor_flag (inp, 0); } if (data_file) { rc = cdk_stream_open (data_file, &data); if (rc) { cdk_stream_close (inp); return rc; } } else data = NULL; rc = _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL); if (data != NULL) cdk_stream_close (data); cdk_stream_close (inp); return rc; }
/* This functions builds an index of the keyring into a separate file with the name keyring.ext.idx. It contains the offset of all public- and public subkeys. The format of the file is: -------- 4 octets offset of the packet 8 octets keyid 20 octets fingerprint -------- We store the keyid and the fingerprint due to the fact we can't get the keyid from a v3 fingerprint directly. */ static int keydb_idx_build( const char * file ) { cdk_packet_t pkt; cdk_stream_t inp, out = NULL; byte buf[8], fpr[20]; char * fname; u32 keyid[2]; int rc, pos; if( !file ) return CDK_Inv_Value; pkt = cdk_calloc( 1, sizeof * pkt ); if( !pkt ) return CDK_Out_Of_Core; fname = keydb_idx_mkname( file ); if( !fname ) { rc = CDK_Out_Of_Core; goto leave; } rc = cdk_stream_open( file, &inp ); if( !rc ) rc = cdk_stream_create( fname, &out ); if( rc ) goto leave; while( !cdk_stream_eof( inp ) ) { pos = cdk_stream_tell( inp ); rc = cdk_pkt_read( inp, pkt ); if( rc ) break; if( pkt->pkttype == CDK_PKT_PUBLIC_KEY || pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) { _cdk_u32tobuf( pos, buf ); cdk_stream_write( out, buf, 4 ); cdk_pk_get_keyid( pkt->pkt.public_key, keyid ); _cdk_u32tobuf( keyid[0], buf ); _cdk_u32tobuf( keyid[1], buf + 4 ); cdk_stream_write( out, buf, 8 ); cdk_pk_get_fingerprint( pkt->pkt.public_key, fpr ); cdk_stream_write( out, fpr, 20 ); } cdk_pkt_free( pkt ); cdk_pkt_init( pkt ); } cdk_stream_close( out ); leave: cdk_stream_close( inp ); cdk_free( fname ); cdk_free( pkt ); return rc; }
/** * cdk_keydb_idx_rebuild: * @hd: key database handle * * Rebuild the key index files for the given key database. **/ cdk_error_t cdk_keydb_idx_rebuild( cdk_keydb_hd_t hd ) { int rc; if( !hd || !hd->name ) return CDK_Inv_Value; if( hd->secret ) return 0; cdk_stream_close( hd->idx ); if( !hd->idx_name ) { hd->idx_name = keydb_idx_mkname( hd->name ); if( !hd->idx_name ) return CDK_Out_Of_Core; } rc = keydb_idx_build( hd->name ); if( !rc ) rc = cdk_stream_open( hd->idx_name, &hd->idx ); return rc; }
cdk_error_t _cdk_stream_append( const char * file, cdk_stream_t * ret_s ) { cdk_stream_t s; FILE * fp; int rc; if( !ret_s ) return CDK_Inv_Value; rc = cdk_stream_open( file, &s ); if( rc ) return rc; fp = fopen( file, "a+b" ); if( !fp ) { cdk_stream_close( s ); return CDK_File_Error; } fclose( s->fp ); s->fp = fp; s->flags.write = 1; *ret_s = s; return 0; }
static cdk_error_t file_verify_clearsign (cdk_ctx_t hd, const char *file, const char *output) { cdk_stream_t inp = NULL, out = NULL, tmp = NULL; digest_hd_st md; char buf[512], chk[512]; const char *s; int i, is_signed = 0, nbytes; int digest_algo = 0; int err; cdk_error_t rc; memset(&md, 0, sizeof(md)); if (output) { rc = cdk_stream_create (output, &out); if (rc) return rc; } rc = cdk_stream_open (file, &inp); if (rc) { if (output) cdk_stream_close (out); return rc; } s = "-----BEGIN PGP SIGNED MESSAGE-----"; while (!cdk_stream_eof (inp)) { nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1); if (!nbytes || nbytes == -1) break; if (!strncmp (buf, s, strlen (s))) { is_signed = 1; break; } } if (cdk_stream_eof (inp) && !is_signed) { rc = CDK_Armor_Error; goto leave; } while (!cdk_stream_eof (inp)) { nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1); if (!nbytes || nbytes == -1) break; if (nbytes == 1) /* Empty line */ break; else if (!strncmp (buf, "Hash: ", 6)) { for (i = 0; digest_table[i].name; i++) { if (!strcmp (buf + 6, digest_table[i].name)) { digest_algo = digest_table[i].algo; break; } } } } if (digest_algo && _gnutls_hash_get_algo_len (digest_algo) <= 0) { rc = CDK_Inv_Algo; goto leave; } if (!digest_algo) digest_algo = GNUTLS_DIG_MD5; err = _gnutls_hash_init (&md, digest_algo); if (err < 0) { rc = map_gnutls_error (err); goto leave; } s = "-----BEGIN PGP SIGNATURE-----"; while (!cdk_stream_eof (inp)) { nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1); if (!nbytes || nbytes == -1) break; if (!strncmp (buf, s, strlen (s))) break; else { cdk_stream_peek (inp, (byte *) chk, DIM (chk) - 1); i = strncmp (chk, s, strlen (s)); if (strlen (buf) == 0 && i == 0) continue; /* skip last '\n' */ _cdk_trim_string (buf, i == 0 ? 0 : 1); _gnutls_hash (&md, buf, strlen (buf)); } if (!strncmp (buf, "- ", 2)) /* FIXME: handle it recursive. */ memmove (buf, buf + 2, nbytes - 2); if (out) { if (strstr (buf, "\r\n")) buf[strlen (buf) - 2] = '\0'; cdk_stream_write (out, buf, strlen (buf)); _cdk_stream_puts (out, _cdk_armor_get_lineend ()); } } /* We create a temporary stream object to store the signature data in there. */ rc = cdk_stream_tmp_new (&tmp); if (rc) goto leave; s = "-----BEGIN PGP SIGNATURE-----\n"; _cdk_stream_puts (tmp, s); while (!cdk_stream_eof (inp)) { nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1); if (!nbytes || nbytes == -1) break; if (nbytes < (int) (DIM (buf) - 3)) { buf[nbytes - 1] = '\n'; buf[nbytes] = '\0'; } cdk_stream_write (tmp, buf, nbytes); } /* FIXME: This code is not very elegant. */ cdk_stream_tmp_set_mode (tmp, STREAMCTL_READ); cdk_stream_seek (tmp, 0); cdk_stream_set_armor_flag (tmp, 0); cdk_stream_read (tmp, NULL, 0); /* the digest handle will be closed there. */ rc = _cdk_proc_packets (hd, tmp, NULL, NULL, NULL, &md); leave: _gnutls_hash_deinit (&md, NULL); cdk_stream_close (out); cdk_stream_close (tmp); cdk_stream_close (inp); return rc; }
/** * cdk_keydb_open: * @hd: keydb object * @ret_kr: the STREAM object which contains the data of the keyring * * Open a STREAM with the contents of the keyring from @hd **/ cdk_error_t cdk_keydb_open( cdk_keydb_hd_t hd, cdk_stream_t * ret_kr ) { int rc = 0, ec; if( !hd || !ret_kr ) return CDK_Inv_Value; if( hd->type == CDK_DBTYPE_DATA && hd->buf ) cdk_stream_seek( hd->buf, 0 ); else if( hd->type == CDK_DBTYPE_PK_KEYRING || hd->type == CDK_DBTYPE_SK_KEYRING ) { if( !hd->isopen && hd->name ) { rc = cdk_stream_open( hd->name, &hd->buf ); if( rc ) goto leave; if( cdk_armor_filter_use( hd->buf ) ) cdk_stream_set_armor_flag( hd->buf, 0 ); hd->isopen = 1; cdk_free( hd->idx_name ); hd->idx_name = keydb_idx_mkname( hd->name ); if( !hd->idx_name ) { rc = CDK_Out_Of_Core; goto leave; } ec = cdk_stream_open( hd->idx_name, &hd->idx ); if( ec && !hd->secret ) { rc = keydb_idx_build( hd->name ); if( !rc ) rc = cdk_stream_open( hd->idx_name, &hd->idx ); if( !rc ) _cdk_log_debug( "create key index table\n" ); if( rc ) { /* this is no real error, it just means we can't create the index at the given directory. maybe we've no write access. in this case, we simply disable the index. */ _cdk_log_debug( "disable key index table\n" ); rc = 0; hd->no_cache = 1; } } } else { /* We use the cache to search keys, so we always rewind the STREAM. Except when the _NEXT search mode is used because this mode is an enumeration and no seeking is needed. */ if( !hd->search || (hd->search && hd->dbs->type != CDK_DBSEARCH_NEXT) ) cdk_stream_seek( hd->buf, 0 ); } } else return CDK_Inv_Mode; leave: if( rc ) { cdk_stream_close( hd->buf ); hd->buf = NULL; } *ret_kr = hd->buf; return rc; }