static int keydb_idx_parse( cdk_stream_t inp, key_idx_t * r_idx ) { key_idx_t idx; byte buf[4]; int i; if( !inp || !r_idx ) return CDK_Inv_Value; idx = cdk_calloc( 1, sizeof * idx ); if( !idx ) return CDK_Out_Of_Core; while( !cdk_stream_eof( inp ) ) { i = cdk_stream_read( inp, buf, 4 ); if( i == CDK_EOF ) break; idx->offset = _cdk_buftou32( buf ); cdk_stream_read( inp, buf, 4 ); idx->keyid[0] = _cdk_buftou32( buf ); cdk_stream_read( inp, buf, 4 ); idx->keyid[1] = _cdk_buftou32( buf ); cdk_stream_read( inp, idx->fpr, 20 ); #if 0 _cdk_log_debug( "%08lu: keyid=%08lX fpr=", idx->offset,idx->keyid[1] ); for( i = 0; i < 20; i++ ) _cdk_log_debug( "%02X", idx->fpr[i] ); _cdk_log_debug( "\n" ); #endif break; } *r_idx = idx; return cdk_stream_eof( inp )? CDK_EOF : 0; }
/** * cdk_stream_kick_off: * @inp: the input stream * @out: the output stream. * * Passes the entire data from @inp into the output stream @out * with all the activated filters. */ cdk_error_t cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out) { byte buf[BUFSIZE]; int nread, nwritten; cdk_error_t rc; if (!inp || !out) { gnutls_assert (); return CDK_Inv_Value; } rc = CDK_Success; while (!cdk_stream_eof (inp)) { nread = cdk_stream_read (inp, buf, DIM (buf)); if (!nread || nread == EOF) break; nwritten = cdk_stream_write (out, buf, nread); if (!nwritten || nwritten == EOF) { /* In case of errors, we leave the loop. */ rc = inp->error; break; } } wipemem (buf, sizeof (buf)); return rc; }
/** * cdk_stream_mmap: * @s: the stream * @ret_buf: the buffer to store the content * @ret_count: length of the buffer * * Map the data of the given stream into a memory section. @ret_count * contains the length of the buffer. **/ cdk_error_t cdk_stream_mmap( cdk_stream_t s, byte ** ret_buf, size_t * ret_count ) { const u32 max_filesize = 16777216; u32 len, oldpos; int n, rc; char * p; if( !s || !ret_buf || !ret_count ) return CDK_Inv_Value; *ret_count = 0; *ret_buf = NULL; oldpos = cdk_stream_tell( s ); rc = cdk_stream_flush( s ); if( !rc ) rc = cdk_stream_seek( s, 0 ); if( rc ) return rc; len = cdk_stream_get_length( s ); if( !len || len > max_filesize ) return 0; p = *ret_buf = cdk_calloc( 1, len+1 ); if( !p ) return 0; *ret_count = len; n = cdk_stream_read( s, p, len ); if( n != len ) *ret_count = n; rc = cdk_stream_seek( s, oldpos ); return rc; }
/** * cdk_kbnode_write_to_mem_alloc: * @node: the key node * @r_buf: buffer to hold the raw data * @r_buflen: buffer length of the allocated raw data. * * The function acts similar to cdk_kbnode_write_to_mem but * it allocates the buffer to avoid the lengthy second run. */ cdk_error_t cdk_kbnode_write_to_mem_alloc (cdk_kbnode_t node, byte ** r_buf, size_t * r_buflen) { cdk_kbnode_t n; cdk_stream_t s; cdk_error_t rc; size_t len; if (!node || !r_buf || !r_buflen) { gnutls_assert (); return CDK_Inv_Value; } *r_buf = NULL; *r_buflen = 0; rc = cdk_stream_tmp_new (&s); if (rc) { gnutls_assert (); return rc; } for (n = node; n; n = n->next) { /* Skip all packets which cannot occur in a key composition. */ if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY && n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY && n->pkt->pkttype != CDK_PKT_SECRET_KEY && n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY && n->pkt->pkttype != CDK_PKT_SIGNATURE && n->pkt->pkttype != CDK_PKT_USER_ID && n->pkt->pkttype != CDK_PKT_ATTRIBUTE) continue; rc = cdk_pkt_write (s, n->pkt); if (rc) { cdk_stream_close (s); gnutls_assert (); return rc; } } cdk_stream_seek (s, 0); len = cdk_stream_get_length (s); *r_buf = cdk_calloc (1, len); *r_buflen = cdk_stream_read (s, *r_buf, len); cdk_stream_close (s); return 0; }
static int stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t * r_nread) { int nread; assert (r_nread); nread = cdk_stream_read (s, buf, buflen); if (nread == EOF) return _cdk_stream_get_errno (s); *r_nread = nread; return 0; }
int cdk_stream_getc( cdk_stream_t s ) { unsigned char buf[2]; int nread; if( !s ) return EOF; nread = cdk_stream_read( s, buf, 1 ); if( nread == EOF ) { s->error = CDK_File_Error; return EOF; } return buf[0]; }
/** * cdk_stream_peek: * @inp: the input stream handle * @s: buffer * @count: number of bytes to peek * * The function acts like cdk_stream_read with the difference that * the file pointer is moved to the old position after the bytes were read. **/ int cdk_stream_peek (cdk_stream_t inp, byte * buf, size_t buflen) { off_t off; int nbytes; if (!inp || !buf) return 0; if (inp->cbs_hd) return 0; off = cdk_stream_tell (inp); nbytes = cdk_stream_read (inp, buf, buflen); if (nbytes == -1) return 0; if (cdk_stream_seek (inp, off)) return 0; return nbytes; }
cdk_error_t cdk_stream_kick_off( cdk_stream_t inp, cdk_stream_t out ) { byte buf[8192]; int nread, nwritten; int rc = 0; if( !inp || !out ) return CDK_Inv_Value; while( !cdk_stream_eof( inp ) ) { nread = cdk_stream_read( inp, buf, sizeof buf-1 ); if( nread == EOF ) break; nwritten = cdk_stream_write( out, buf, nread ); if( nwritten == EOF ) rc = CDK_File_Error; } wipemem( buf, sizeof buf ); return rc; }
int cdk_stream_getc (cdk_stream_t s) { unsigned char buf[2]; int nread; if (!s) { s->error = CDK_Inv_Value; gnutls_assert(); return EOF; } nread = cdk_stream_read (s, buf, 1); if (nread == EOF) { s->error = CDK_File_Error; gnutls_assert(); return EOF; } return buf[0]; }
/** * gnutls_openpgp_keyring_import: * @keyring: The structure to store the parsed key. * @data: The RAW or BASE64 encoded keyring. * @format: One of #gnutls_openpgp_keyring_fmt elements. * * This function will convert the given RAW or Base64 encoded keyring * to the native #gnutls_openpgp_keyring_t format. The output will be * stored in 'keyring'. * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_openpgp_keyring_import(gnutls_openpgp_keyring_t keyring, const gnutls_datum_t * data, gnutls_openpgp_crt_fmt_t format) { cdk_error_t err; cdk_stream_t input = NULL; size_t raw_len = 0; uint8_t *raw_data = NULL; unsigned free_data = 0; if (data->data == NULL || data->size == 0) { gnutls_assert(); return GNUTLS_E_OPENPGP_GETKEY_FAILED; } _gnutls_debug_log("PGP: keyring import format '%s'\n", format == GNUTLS_OPENPGP_FMT_RAW ? "raw" : "base64"); /* Create a new stream from the given data, decode it, and import * the raw database. This to avoid using opencdk streams which are * not thread safe. */ if (format == GNUTLS_OPENPGP_FMT_BASE64) { size_t seen = 0; err = cdk_stream_tmp_from_mem(data->data, data->size, &input); if (err == 0) err = cdk_stream_set_armor_flag(input, 0); if (err) { gnutls_assert(); err = _gnutls_map_cdk_rc(err); goto error; } raw_len = cdk_stream_get_length(input); if (raw_len == 0) { gnutls_assert(); err = GNUTLS_E_BASE64_DECODING_ERROR; goto error; } raw_data = gnutls_malloc(raw_len); if (raw_data == NULL) { gnutls_assert(); err = GNUTLS_E_MEMORY_ERROR; goto error; } do { err = cdk_stream_read(input, raw_data + seen, raw_len - seen); if (err > 0) seen += err; } while (seen < raw_len && err != EOF && err > 0); raw_len = seen; if (raw_len == 0) { gnutls_assert(); err = GNUTLS_E_BASE64_DECODING_ERROR; goto error; } free_data = 1; } else { /* RAW */ raw_len = data->size; raw_data = data->data; } err = cdk_keydb_new_from_mem(&keyring->db, 0, 0, raw_data, raw_len); if (err) gnutls_assert(); if (free_data) { err = _gnutls_map_cdk_rc(err); goto error; } return _gnutls_map_cdk_rc(err); error: gnutls_free(raw_data); cdk_stream_close(input); return err; }
/** * gnutls_openpgp_key_export - This function will export a RAW or BASE64 encoded key * @key: Holds the key. * @format: One of gnutls_openpgp_key_fmt_t elements. * @output_data: will contain the key base64 encoded or raw * @output_data_size: holds the size of output_data (and will be replaced by the actual size of parameters) * * This function will convert the given key to RAW or Base64 format. * If the buffer provided is not long enough to hold the output, then * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned. * * Returns 0 on success. * **/ int gnutls_openpgp_key_export (gnutls_openpgp_key_t key, gnutls_openpgp_key_fmt_t format, void *output_data, size_t * output_data_size) { int rc; size_t input_data_size = *output_data_size; rc = cdk_kbnode_write_to_mem (key->knode, output_data, output_data_size); if (rc) { rc = _gnutls_map_cdk_rc (rc); gnutls_assert (); return rc; } if (format == GNUTLS_OPENPGP_FMT_BASE64) { cdk_stream_t s; s = cdk_stream_tmp_from_mem (output_data, *output_data_size); if (s == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } cdk_stream_tmp_set_mode (s, 1); rc = cdk_stream_set_armor_flag (s, CDK_ARMOR_PUBKEY); if (rc) { rc = _gnutls_map_cdk_rc (rc); gnutls_assert (); cdk_stream_close (s); return rc; } *output_data_size = input_data_size; rc = cdk_stream_read (s, output_data, *output_data_size); if (rc == EOF) { gnutls_assert (); cdk_stream_close (s); return GNUTLS_E_INTERNAL_ERROR; } *output_data_size = rc; if (*output_data_size != cdk_stream_get_length (s)) { *output_data_size = cdk_stream_get_length (s); cdk_stream_close (s); gnutls_assert (); return GNUTLS_E_SHORT_MEMORY_BUFFER; } cdk_stream_close (s); } return 0; }
/** * cdk_stream_mmap_part: * @s: the stream * @off: the offset where to start * @len: how much bytes shall be mapped * @ret_buf: the buffer to store the content * @ret_buflen: length of the buffer * * Maps the data of the given stream into a memory section. @ret_count * contains the length of the buffer. **/ cdk_error_t cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len, byte ** ret_buf, size_t * ret_buflen) { cdk_error_t rc; off_t oldpos; unsigned int n; if (!ret_buf || !ret_buflen) { gnutls_assert (); return CDK_Inv_Value; } *ret_buf = NULL; *ret_buflen = 0; if (!s) { gnutls_assert (); return CDK_Inv_Value; } /* Memory mapping is not supported on custom I/O objects. */ if (s->cbs_hd) { _cdk_log_debug ("cdk_stream_mmap_part: not supported on callbacks\n"); gnutls_assert (); return CDK_Inv_Mode; } oldpos = cdk_stream_tell (s); rc = cdk_stream_flush (s); if (rc) { gnutls_assert (); return rc; } rc = cdk_stream_seek (s, off); if (rc) { gnutls_assert (); return rc; } if (!len) len = cdk_stream_get_length (s); if (!len) { _cdk_log_debug ("cdk_stream_mmap_part: invalid file size %lu\n", len); gnutls_assert (); return s->error; } if (len > MAX_MAP_SIZE) { gnutls_assert (); return CDK_Too_Short; } *ret_buf = cdk_calloc (1, len + 1); *ret_buflen = len; n = cdk_stream_read (s, *ret_buf, len); if (n != len) *ret_buflen = n; rc = cdk_stream_seek (s, oldpos); if (rc) gnutls_assert (); return rc; }
static int stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t * r_nread) { *r_nread = cdk_stream_read (s, buf, buflen); return *r_nread > 0 ? 0 : _cdk_stream_get_errno (s); }
static int literal_decode( void * opaque, FILE * in, FILE * out ) { literal_filter_t * pfx = opaque; cdk_stream_t si, so; CDK_PACKET pkt; cdk_pkt_literal_t pt; byte buf[8192]; size_t nread; int rc, bufsize; _cdk_log_debug( "literal filter: decode\n" ); if (!pfx || !in || !out) return CDK_Inv_Value; si = _cdk_stream_fpopen( in, STREAMCTL_READ ); if (!si) return CDK_Out_Of_Core; so = _cdk_stream_fpopen( out, STREAMCTL_WRITE ); if( !so ) { cdk_stream_close( si ); return CDK_Out_Of_Core; } cdk_pkt_init( &pkt ); rc = cdk_pkt_read( si, &pkt ); if( pkt.pkttype != CDK_PKT_LITERAL ) { if( pkt.pkttype ) cdk_pkt_free( &pkt ); return rc; } pt = pkt.pkt.literal; pfx->mode = pt->mode; pfx->filename = cdk_strdup( pt->name? pt->name : " " ); if( !pfx->filename ) { cdk_pkt_free( &pkt ); return CDK_Out_Of_Core; } while( !feof( in ) ) { _cdk_log_debug( "partial on=%d size=%lu\n", pfx->blkmode.on, pfx->blkmode.size ); if( pfx->blkmode.on ) bufsize = pfx->blkmode.size; else bufsize = pt->len < sizeof buf-1? pt->len : sizeof buf-1; nread = cdk_stream_read( pt->buf, buf, bufsize ); if( nread == EOF ) { rc = CDK_File_Error; break; } if( pfx->md ) cdk_md_write (pfx->md, buf, nread); cdk_stream_write( so, buf, nread ); pt->len -= nread; if( pfx->blkmode.on ) { pfx->blkmode.size = _cdk_pkt_read_len( in, &pfx->blkmode.on ); if( pfx->blkmode.size == (size_t)EOF ) return CDK_Inv_Packet; } if( pt->len <= 0 && !pfx->blkmode.on ) break; } cdk_stream_close( si ); cdk_stream_close( so ); cdk_pkt_free( &pkt ); return rc; }
static cdk_error_t literal_decode (void *data, FILE * in, FILE * out) { literal_filter_t *pfx = data; cdk_stream_t si, so; cdk_packet_t pkt; cdk_pkt_literal_t pt; byte buf[BUFSIZE]; ssize_t nread; int bufsize; cdk_error_t rc; _cdk_log_debug ("literal filter: decode\n"); if (!pfx || !in || !out) return CDK_Inv_Value; rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si); if (rc) return rc; cdk_pkt_new (&pkt); rc = cdk_pkt_read (si, pkt); if (rc || pkt->pkttype != CDK_PKT_LITERAL) { cdk_pkt_release (pkt); cdk_stream_close (si); return !rc ? CDK_Inv_Packet : rc; } rc = _cdk_stream_fpopen (out, STREAMCTL_WRITE, &so); if (rc) { cdk_pkt_release (pkt); cdk_stream_close (si); return rc; } pt = pkt->pkt.literal; pfx->mode = pt->mode; if (pfx->filename && pt->namelen > 0) { /* The name in the literal packet is more authorative. */ cdk_free (pfx->filename); pfx->filename = dup_trim_filename (pt->name); } else if (!pfx->filename && pt->namelen > 0) pfx->filename = dup_trim_filename (pt->name); else if (!pt->namelen && !pfx->filename && pfx->orig_filename) { /* In this case, we need to derrive the output file name from the original name and cut off the OpenPGP extension. If this is not possible, we return an error. */ if (!stristr (pfx->orig_filename, ".gpg") && !stristr (pfx->orig_filename, ".pgp") && !stristr (pfx->orig_filename, ".asc")) { cdk_pkt_release (pkt); cdk_stream_close (si); cdk_stream_close (so); _cdk_log_debug ("literal filter: no file name and no PGP extension\n"); return CDK_Inv_Mode; } _cdk_log_debug ("literal filter: derrive file name from original\n"); pfx->filename = dup_trim_filename (pfx->orig_filename); pfx->filename[strlen (pfx->filename) - 4] = '\0'; } while (!feof (in)) { _cdk_log_debug ("literal_decode: part on %d size %lu\n", (int) pfx->blkmode.on, (unsigned long)pfx->blkmode.size); if (pfx->blkmode.on) bufsize = pfx->blkmode.size; else bufsize = pt->len < DIM (buf) ? pt->len : DIM (buf); nread = cdk_stream_read (pt->buf, buf, bufsize); if (nread == EOF) { rc = CDK_File_Error; break; } if (pfx->md_initialized) _gnutls_hash (&pfx->md, buf, nread); cdk_stream_write (so, buf, nread); pt->len -= nread; if (pfx->blkmode.on) { pfx->blkmode.size = _cdk_pkt_read_len (in, &pfx->blkmode.on); if ((ssize_t) pfx->blkmode.size == EOF) return CDK_Inv_Packet; } if (pt->len <= 0 && !pfx->blkmode.on) break; } cdk_stream_close (si); cdk_stream_close (so); cdk_pkt_release (pkt); return rc; }
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_kbnode_write_to_mem: * @node: the key node * @buf: the buffer to store the node data * @r_nbytes: the new length of the buffer. * * Tries to write the contents of the key node to the buffer @buf and * return the length of it in @r_nbytes. If buf is zero, only the * length of the node is calculated and returned in @r_nbytes. * Whenever it is possible, the cdk_kbnode_write_to_mem_alloc should be used. **/ cdk_error_t cdk_kbnode_write_to_mem (cdk_kbnode_t node, byte * buf, size_t * r_nbytes) { cdk_kbnode_t n; cdk_stream_t s; cdk_error_t rc; size_t len; if (!node || !r_nbytes) { gnutls_assert (); return CDK_Inv_Value; } rc = cdk_stream_tmp_new (&s); if (rc) { gnutls_assert (); return rc; } for (n = node; n; n = n->next) { /* Skip all packets which cannot occur in a key composition. */ if (n->pkt->pkttype != CDK_PKT_PUBLIC_KEY && n->pkt->pkttype != CDK_PKT_PUBLIC_SUBKEY && n->pkt->pkttype != CDK_PKT_SECRET_KEY && n->pkt->pkttype != CDK_PKT_SECRET_SUBKEY && n->pkt->pkttype != CDK_PKT_SIGNATURE && n->pkt->pkttype != CDK_PKT_USER_ID && n->pkt->pkttype != CDK_PKT_ATTRIBUTE) continue; rc = cdk_pkt_write (s, n->pkt); if (rc) { cdk_stream_close (s); gnutls_assert (); return rc; } } cdk_stream_seek (s, 0); len = cdk_stream_get_length (s); if (!buf) { *r_nbytes = len; /* Only return the length of the buffer */ cdk_stream_close (s); return 0; } if (*r_nbytes < len) { *r_nbytes = len; rc = CDK_Too_Short; } if (!rc) *r_nbytes = cdk_stream_read (s, buf, len); else gnutls_assert (); cdk_stream_close (s); return rc; }