Exemple #1
0
/**
 * 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;
}
Exemple #2
0
/* 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;
}
Exemple #3
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 *s, size_t count )
{
    unsigned off;
    int nbytes, rc;

    if( !inp || !s )
        return CDK_Inv_Value;
    off = cdk_stream_tell( inp );
    nbytes = _cdk_stream_gets( inp, s, count );
    rc = cdk_stream_seek( inp, off );
    if( rc )
        return 0;
    return nbytes;
}
Exemple #4
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;
}
Exemple #5
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;
}
Exemple #6
0
/**
 * cdk_pkt_read:
 * @inp: the input stream
 * @pkt: allocated packet handle to store the packet
 *
 * Parse the next packet on the @inp stream and return its contents in @pkt.
 **/
cdk_error_t
cdk_pkt_read (cdk_stream_t inp, cdk_packet_t pkt)
{
  int ctb, is_newctb;
  int pkttype;
  size_t pktlen = 0, pktsize = 0, is_partial = 0;
  cdk_error_t rc;

  if (!inp || !pkt)
    return CDK_Inv_Value;

  ctb = cdk_stream_getc (inp);
  if (cdk_stream_eof (inp) || ctb == EOF)
    return CDK_EOF;
  else if (!ctb)
    return CDK_Inv_Packet;

  pktsize++;
  if (!(ctb & 0x80))
    {
      _cdk_log_info ("cdk_pkt_read: no openpgp data found. "
		     "(ctb=%02X; fpos=%02X)\n", ctb, cdk_stream_tell (inp));
      return CDK_Inv_Packet;
    }

  if (ctb & 0x40)		/* RFC2440 packet format. */
    {
      pkttype = ctb & 0x3f;
      is_newctb = 1;
    }
  else				/* the old RFC1991 packet format. */
    {
      pkttype = ctb & 0x3f;
      pkttype >>= 2;
      is_newctb = 0;
    }

  if (pkttype > 63)
    {
      _cdk_log_info ("cdk_pkt_read: unknown type %d\n", pkttype);
      return CDK_Inv_Packet;
    }

  if (is_newctb)
    read_new_length (inp, &pktlen, &pktsize, &is_partial);
  else
    read_old_length (inp, ctb, &pktlen, &pktsize);

  pkt->pkttype = pkttype;
  pkt->pktlen = pktlen;
  pkt->pktsize = pktsize + pktlen;
  pkt->old_ctb = is_newctb ? 0 : 1;

  rc = 0;
  switch (pkt->pkttype)
    {
    case CDK_PKT_ATTRIBUTE:
      pkt->pkt.user_id = cdk_calloc (1, sizeof *pkt->pkt.user_id
				     + pkt->pktlen + 16 + 1);
      if (!pkt->pkt.user_id)
	return CDK_Out_Of_Core;
      pkt->pkt.user_id->name = (char*)pkt->pkt.user_id + sizeof(*pkt->pkt.user_id);

      rc = read_attribute (inp, pktlen, pkt->pkt.user_id);
      pkt->pkttype = CDK_PKT_ATTRIBUTE;
      break;

    case CDK_PKT_USER_ID:
      pkt->pkt.user_id = cdk_calloc (1, sizeof *pkt->pkt.user_id
				     + pkt->pktlen + 1);
      if (!pkt->pkt.user_id)
	return CDK_Out_Of_Core;
      pkt->pkt.user_id->name = (char*)pkt->pkt.user_id + sizeof(*pkt->pkt.user_id);
      rc = read_user_id (inp, pktlen, pkt->pkt.user_id);
      break;

    case CDK_PKT_PUBLIC_KEY:
      pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
      if (!pkt->pkt.public_key)
	return CDK_Out_Of_Core;
      rc = read_public_key (inp, pktlen, pkt->pkt.public_key);
      break;

    case CDK_PKT_PUBLIC_SUBKEY:
      pkt->pkt.public_key = cdk_calloc (1, sizeof *pkt->pkt.public_key);
      if (!pkt->pkt.public_key)
	return CDK_Out_Of_Core;
      rc = read_public_subkey (inp, pktlen, pkt->pkt.public_key);
      break;

    case CDK_PKT_SECRET_KEY:
      pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
      if (!pkt->pkt.secret_key)
	return CDK_Out_Of_Core;
      pkt->pkt.secret_key->pk = cdk_calloc (1,
					    sizeof *pkt->pkt.secret_key->pk);
      if (!pkt->pkt.secret_key->pk)
	return CDK_Out_Of_Core;
      rc = read_secret_key (inp, pktlen, pkt->pkt.secret_key);
      break;

    case CDK_PKT_SECRET_SUBKEY:
      pkt->pkt.secret_key = cdk_calloc (1, sizeof *pkt->pkt.secret_key);
      if (!pkt->pkt.secret_key)
	return CDK_Out_Of_Core;
      pkt->pkt.secret_key->pk = cdk_calloc (1,
					    sizeof *pkt->pkt.secret_key->pk);
      if (!pkt->pkt.secret_key->pk)
	return CDK_Out_Of_Core;
      rc = read_secret_subkey (inp, pktlen, pkt->pkt.secret_key);
      break;

    case CDK_PKT_LITERAL:
      pkt->pkt.literal = cdk_calloc (1, sizeof *pkt->pkt.literal);
      if (!pkt->pkt.literal)
	return CDK_Out_Of_Core;
      rc = read_literal (inp, pktlen, &pkt->pkt.literal, is_partial);
      break;

    case CDK_PKT_ONEPASS_SIG:
      pkt->pkt.onepass_sig = cdk_calloc (1, sizeof *pkt->pkt.onepass_sig);
      if (!pkt->pkt.onepass_sig)
	return CDK_Out_Of_Core;
      rc = read_onepass_sig (inp, pktlen, pkt->pkt.onepass_sig);
      break;

    case CDK_PKT_SIGNATURE:
      pkt->pkt.signature = cdk_calloc (1, sizeof *pkt->pkt.signature);
      if (!pkt->pkt.signature)
	return CDK_Out_Of_Core;
      rc = read_signature (inp, pktlen, pkt->pkt.signature);
      break;

    case CDK_PKT_PUBKEY_ENC:
      pkt->pkt.pubkey_enc = cdk_calloc (1, sizeof *pkt->pkt.pubkey_enc);
      if (!pkt->pkt.pubkey_enc)
	return CDK_Out_Of_Core;
      rc = read_pubkey_enc (inp, pktlen, pkt->pkt.pubkey_enc);
      break;

    case CDK_PKT_COMPRESSED:
      pkt->pkt.compressed = cdk_calloc (1, sizeof *pkt->pkt.compressed);
      if (!pkt->pkt.compressed)
	return CDK_Out_Of_Core;
      rc = read_compressed (inp, pktlen, pkt->pkt.compressed);
      break;

    case CDK_PKT_MDC:
      pkt->pkt.mdc = cdk_calloc (1, sizeof *pkt->pkt.mdc);
      if (!pkt->pkt.mdc)
	return CDK_Out_Of_Core;
      rc = read_mdc (inp, pkt->pkt.mdc);
      break;

    default:
      /* Skip all packets we don't understand */
      skip_packet (inp, pktlen);
      break;
    }

  return rc;
}
Exemple #7
0
static cdk_error_t
read_secret_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_seckey_t sk)
{
  size_t p1, p2, nread;
  int i, nskey;
  int rc;

  if (!inp || !sk || !sk->pk)
    return CDK_Inv_Value;

  if (DEBUG_PKT)
    _cdk_log_debug ("read_secret_key: %d octets\n", pktlen);

  p1 = cdk_stream_tell (inp);
  rc = read_public_key (inp, pktlen, sk->pk);
  if (rc)
    return rc;

  sk->s2k_usage = cdk_stream_getc (inp);
  sk->protect.sha1chk = 0;
  if (sk->s2k_usage == 254 || sk->s2k_usage == 255)
    {
      sk->protect.sha1chk = (sk->s2k_usage == 254);
      sk->protect.algo = _pgp_cipher_to_gnutls (cdk_stream_getc (inp));
      sk->protect.s2k = cdk_calloc (1, sizeof *sk->protect.s2k);
      if (!sk->protect.s2k)
	return CDK_Out_Of_Core;
      rc = read_s2k (inp, sk->protect.s2k);
      if (rc)
	return rc;
      /* refer to --export-secret-subkeys in gpg(1) */
      if (sk->protect.s2k->mode == CDK_S2K_GNU_EXT)
	sk->protect.ivlen = 0;
      else
	{
	  sk->protect.ivlen =
	    _gnutls_cipher_get_block_size (sk->protect.algo);
	  if (!sk->protect.ivlen)
	    return CDK_Inv_Packet;
	  rc = stream_read (inp, sk->protect.iv, sk->protect.ivlen, &nread);
	  if (rc)
	    return rc;
	  if (nread != sk->protect.ivlen)
	    return CDK_Inv_Packet;
	}
    }
  else
    sk->protect.algo = _pgp_cipher_to_gnutls (sk->s2k_usage);
  if (sk->protect.algo == GNUTLS_CIPHER_NULL)
    {
      sk->csum = 0;
      nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
      if (!nskey)
	{
	  gnutls_assert ();
	  return CDK_Inv_Algo;
	}
      for (i = 0; i < nskey; i++)
	{
	  rc = read_mpi (inp, &sk->mpi[i], 1);
	  if (rc)
	    return rc;
	}
      sk->csum = read_16 (inp);
      sk->is_protected = 0;
    }
  else if (sk->pk->version < 4)
    {
      /* The length of each multiprecision integer is stored in plaintext. */
      nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
      if (!nskey)
	{
	  gnutls_assert ();
	  return CDK_Inv_Algo;
	}
      for (i = 0; i < nskey; i++)
	{
	  rc = read_mpi (inp, &sk->mpi[i], 1);
	  if (rc)
	    return rc;
	}
      sk->csum = read_16 (inp);
      sk->is_protected = 1;
    }
  else
    {
      /* We need to read the rest of the packet because we do not
         have any information how long the encrypted mpi's are */
      p2 = cdk_stream_tell (inp);
      p2 -= p1;
      sk->enclen = pktlen - p2;
      if (sk->enclen < 2)
	return CDK_Inv_Packet;	/* at least 16 bits for the checksum! */
      sk->encdata = cdk_calloc (1, sk->enclen + 1);
      if (!sk->encdata)
	return CDK_Out_Of_Core;
      if (stream_read (inp, sk->encdata, sk->enclen, &nread))
	return CDK_Inv_Packet;
      /* Handle the GNU S2K extensions we know (just gnu-dummy right now): */
      if (sk->protect.s2k->mode == CDK_S2K_GNU_EXT)
	{
	  unsigned char gnumode;
	  if ((sk->enclen < strlen ("GNU") + 1) ||
	      (0 != memcmp ("GNU", sk->encdata, strlen ("GNU"))))
	    return CDK_Inv_Packet;
	  gnumode = sk->encdata[strlen ("GNU")];
	  /* we only handle gnu-dummy (mode 1).
	     mode 2 should refer to external smart cards.
	   */
	  if (gnumode != 1)
	    return CDK_Inv_Packet;
	  /* gnu-dummy should have no more data */
	  if (sk->enclen != strlen ("GNU") + 1)
	    return CDK_Inv_Packet;
	}
      nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
      if (!nskey)
	{
	  gnutls_assert ();
	  return CDK_Inv_Algo;
	}
      /* We mark each MPI entry with NULL to indicate a protected key. */
      for (i = 0; i < nskey; i++)
	sk->mpi[i] = NULL;
      sk->is_protected = 1;
    }

  sk->is_primary = 1;
  _cdk_copy_pk_to_sk (sk->pk, sk);
  return 0;
}
Exemple #8
0
/**
 * cdk_keydb_search:
 * @hd: the keydb object
 * @ks: the keydb search object
 * @ret_key: kbnode object to store the key
 *
 * Search for a key in the given keyring. The search mode is handled
 * via @ks. If the key was found, @ret_key contains the key data.
 **/
cdk_error_t
cdk_keydb_search( cdk_keydb_hd_t hd, cdk_kbnode_t * ret_key )
{
    cdk_stream_t kr = NULL;
    cdk_kbnode_t knode = NULL;
    cdk_dbsearch_t ks;
    u32 off = 0;
    size_t pos = 0;
    int key_found = 0, cache_hit = 0;
    int rc = 0;

    if( !hd || !ret_key )
        return CDK_Inv_Value;

    *ret_key = NULL;
    hd->search = 1;
    rc = cdk_keydb_open( hd, &kr );
    if( rc )
        return rc;
    rc = keydb_pos_from_cache( hd, hd->dbs, &cache_hit, &off );
    if( rc )
        return rc;
    
    ks = hd->dbs;
    while( !key_found && !rc ) {
        if( cache_hit && ks->type != CDK_DBSEARCH_NEXT )
            cdk_stream_seek( kr, off );
        pos = cdk_stream_tell( kr );
        rc = cdk_keydb_get_keyblock( kr, &knode );
        if( rc ) {
            if( rc == CDK_EOF && knode )
                rc = 0;
            if( !knode && rc == CDK_EOF )
                rc = CDK_Error_No_Key;
            if( rc )
                break;
        }

        switch( ks->type ) {
        case CDK_DBSEARCH_SHORT_KEYID:
        case CDK_DBSEARCH_KEYID:
            key_found = find_by_keyid( knode, ks );
            break;

        case CDK_DBSEARCH_FPR:
            key_found = find_by_fpr( knode, ks );
            break;
          
	case CDK_DBSEARCH_EXACT:
	case CDK_DBSEARCH_SUBSTR:
            key_found = find_by_pattern( knode, ks );
            break;

        case CDK_DBSEARCH_NEXT:
            key_found = knode? 1 : 0;
            break;
	}

        if( key_found ) {
            if( !keydb_cache_find( hd->cache, ks ) )
                keydb_cache_add( hd, ks, pos );
            break;
        }

        cdk_kbnode_release( knode );
        knode = NULL;
    }

    hd->search = 0;
    *ret_key = key_found? knode : NULL;
    return rc;
}
Exemple #9
0
cdk_error_t
cdk_keydb_get_keyblock( cdk_stream_t inp, cdk_kbnode_t * r_knode )
{
    cdk_packet_t pkt = NULL;
    cdk_kbnode_t knode = NULL, node = NULL;
    cdk_desig_revoker_t revkeys = NULL;
    u32 keyid[2], main_keyid[2];
    int rc = 0, old_off;
    int key_seen = 0, got_key = 0;

    if( !inp || !r_knode )
        return CDK_Inv_Value;

    memset( keyid, 0, sizeof keyid );
    memset( main_keyid, 0, sizeof main_keyid );
  
    while( 1 ) {
        pkt = cdk_calloc( 1, sizeof *pkt );
        if( !pkt )
            return CDK_Out_Of_Core;
        old_off = 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
            || pkt->pkttype == CDK_PKT_SECRET_KEY
            || pkt->pkttype == CDK_PKT_SECRET_SUBKEY) {
            if (key_seen && (pkt->pkttype == CDK_PKT_PUBLIC_KEY
                             || pkt->pkttype == CDK_PKT_SECRET_KEY) ) {
                cdk_stream_seek( inp, old_off );
                break;
	    }
            if( pkt->pkttype == CDK_PKT_PUBLIC_KEY
                || pkt->pkttype == CDK_PKT_SECRET_KEY ) {
                _cdk_pkt_get_keyid( pkt, main_keyid );
                key_seen = 1;
            }
            else if( pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY
                     || pkt->pkttype == CDK_PKT_SECRET_SUBKEY ) {
                if( pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ) {
                    pkt->pkt.public_key->main_keyid[0] = main_keyid[0];
                    pkt->pkt.public_key->main_keyid[1] = main_keyid[1];
		}
                else {
                    pkt->pkt.secret_key->main_keyid[0] = main_keyid[0];
                    pkt->pkt.secret_key->main_keyid[1] = main_keyid[1];
		}
	    }
            /* we save this for the signature */
            _cdk_pkt_get_keyid( pkt, keyid );
            got_key = 1;
	}
        else if( pkt->pkttype == CDK_PKT_USER_ID )
            ;
        else if( pkt->pkttype == CDK_PKT_SIGNATURE ) {
            pkt->pkt.signature->key[0] = keyid[0];
            pkt->pkt.signature->key[1] = keyid[1];
            if( pkt->pkt.signature->sig_class == 0x1F &&
                pkt->pkt.signature->revkeys )
                revkeys = pkt->pkt.signature->revkeys;
	}
        node = cdk_kbnode_new( pkt );
        if( !knode )
            knode = node;
        else
            _cdk_kbnode_add( knode, node );
    }

    if( got_key ) {
        keydb_merge_selfsig( knode, main_keyid );
        rc = keydb_parse_allsigs( knode, NULL, 0 );
        if( revkeys ) {
            node = cdk_kbnode_find( knode, CDK_PKT_PUBLIC_KEY );
            if( node )
                node->pkt->pkt.public_key->revkeys = revkeys;
        }
    }
    *r_knode = got_key ? knode : NULL;
    return rc;
}