Example #1
0
/****************
 * Make a hash value from the public key certificate
 */
void
hash_public_key( MD_HANDLE md, PKT_public_key *pk )
{
    PACKET pkt;
    int rc = 0;
    int ctb;
    ulong pktlen;
    int c;
    IOBUF a = iobuf_temp();
  #if 0
    FILE *fp = fopen("dump.pk", "a");
    int i=0;

    fprintf(fp, "\nHashing PK (v%d):\n", pk->version);
  #endif

    /* build the packet */
    init_packet(&pkt);
    pkt.pkttype = PKT_PUBLIC_KEY;
    pkt.pkt.public_key = pk;
    if( (rc = build_packet( a, &pkt )) )
	log_fatal("build public_key for hashing failed: %s\n", g10_errstr(rc));

    if( !(pk->version == 3 && pk->pubkey_algo == 16) ) {
	/* skip the constructed header but don't do this for our very old
	 * v3 ElG keys */
	ctb = iobuf_get_noeof(a);
	pktlen = 0;
	if( (ctb & 0x40) ) {
	    c = iobuf_get_noeof(a);
	    if( c < 192 )
		pktlen = c;
	    else if( c < 224 ) {
		pktlen = (c - 192) * 256;
		c = iobuf_get_noeof(a);
		pktlen += c + 192;
	    }
	    else if( c == 255 ) {
		pktlen	= iobuf_get_noeof(a) << 24;
		pktlen |= iobuf_get_noeof(a) << 16;
		pktlen |= iobuf_get_noeof(a) << 8;
		pktlen |= iobuf_get_noeof(a);
	    }
	}
	else {
	    int lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
	    for( ; lenbytes; lenbytes-- ) {
		pktlen <<= 8;
		pktlen |= iobuf_get_noeof(a);
	    }
	}
	/* hash a header */
	md_putc( md, 0x99 );
	pktlen &= 0xffff; /* can't handle longer packets */
	md_putc( md, pktlen >> 8 );
	md_putc( md, pktlen & 0xff );
    }
Example #2
0
/****************
 * This filter is used to en/de-cipher data with a conventional algorithm
 */
int
cipher_filter( void *opaque, int control,
               IOBUF a, byte *buf, size_t *ret_len)
{
    size_t size = *ret_len;
    cipher_filter_context_t *cfx = opaque;
    int rc=0;

    if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
        rc = -1; /* not yet used */
    }
    else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
        assert(a);
        if( !cfx->header ) {
            write_header( cfx, a );
        }
        if( cfx->mdc_hash )
            md_write( cfx->mdc_hash, buf, size );
        cipher_encrypt( cfx->cipher_hd, buf, buf, size);
        if( iobuf_write( a, buf, size ) )
            rc = G10ERR_WRITE_FILE;
    }
    else if( control == IOBUFCTRL_FREE ) {
        if( cfx->mdc_hash ) {
            byte *hash;
            int hashlen = md_digest_length( md_get_algo( cfx->mdc_hash ) );
            byte temp[22];

            assert( hashlen == 20 );
            /* we must hash the prefix of the MDC packet here */
            temp[0] = 0xd3;
            temp[1] = 0x14;
            md_putc( cfx->mdc_hash, temp[0] );
            md_putc( cfx->mdc_hash, temp[1] );

            md_final( cfx->mdc_hash );
            hash = md_read( cfx->mdc_hash, 0 );
            memcpy(temp+2, hash, 20);
            cipher_encrypt( cfx->cipher_hd, temp, temp, 22 );
            md_close( cfx->mdc_hash );
            cfx->mdc_hash = NULL;
            if( iobuf_write( a, temp, 22 ) )
                log_error("writing MDC packet failed\n" );
        }
        cipher_close(cfx->cipher_hd);
    }
    else if( control == IOBUFCTRL_DESC ) {
        *(char**)buf = "cipher_filter";
    }
    return rc;
}
/* This function is useful for v4 fingerprints and v3 or v4 key
   signing. */
void
hash_public_key( MD_HANDLE md, PKT_public_key *pk )
{
  unsigned n=6;
  unsigned nb[PUBKEY_MAX_NPKEY];
  unsigned nn[PUBKEY_MAX_NPKEY];
  byte *pp[PUBKEY_MAX_NPKEY];
  int i;
  int npkey = pubkey_get_npkey( pk->pubkey_algo );

  /* Two extra bytes for the expiration date in v3 */
  if(pk->version<4)
    n+=2;

  if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0]))
    {
      pp[0]=mpi_get_opaque(pk->pkey[0],&nn[0]);
      n+=nn[0];
    }
  else
    for(i=0; i < npkey; i++ )
      {
	nb[i] = mpi_get_nbits(pk->pkey[i]);
	pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
	n += 2 + nn[i];
      }

  md_putc( md, 0x99 );     /* ctb */
  /* What does it mean if n is greater than than 0xFFFF ? */
  md_putc( md, n >> 8 );   /* 2 byte length header */
  md_putc( md, n );
  md_putc( md, pk->version );

  md_putc( md, pk->timestamp >> 24 );
  md_putc( md, pk->timestamp >> 16 );
  md_putc( md, pk->timestamp >>  8 );
  md_putc( md, pk->timestamp       );

  if(pk->version<4)
    {
      u16 days=0;
      if(pk->expiredate)
	days=(u16)((pk->expiredate - pk->timestamp) / 86400L);
 
      md_putc( md, days >> 8 );
      md_putc( md, days );
    }
Example #4
0
static MD_HANDLE
do_fingerprint_md( PKT_public_key *pk )
{
    MD_HANDLE md;
    unsigned n;
    unsigned nb[PUBKEY_MAX_NPKEY];
    unsigned nn[PUBKEY_MAX_NPKEY];
    byte *pp[PUBKEY_MAX_NPKEY];
    int i;
    int npkey = pubkey_get_npkey( pk->pubkey_algo );

    md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0);
    n = pk->version < 4 ? 8 : 6;
    for(i=0; i < npkey; i++ ) {
	nb[i] = mpi_get_nbits(pk->pkey[i]);
	pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
	n += 2 + nn[i];
    }

    md_putc( md, 0x99 );     /* ctb */
    md_putc( md, n >> 8 );   /* 2 byte length header */
    md_putc( md, n );
    if( pk->version < 4 )
	md_putc( md, 3 );
    else
	md_putc( md, 4 );

    {	u32 a = pk->timestamp;
	md_putc( md, a >> 24 );
	md_putc( md, a >> 16 );
	md_putc( md, a >>  8 );
	md_putc( md, a	     );
    }
    if( pk->version < 4 ) {
	u16 a;

	if( pk->expiredate )
	    a = (u16)((pk->expiredate - pk->timestamp) / 86400L);
	else
	    a = 0;
	md_putc( md, a >> 8 );
	md_putc( md, a	    );
    }
Example #5
0
int
signature_check2( PKT_signature *sig, MD_HANDLE digest,
		  u32 *r_expiredate, int *r_expired )
{
    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
    int rc=0;

    *r_expiredate = 0;

    /* Sanity check that the md has a context for the hash that the
       sig is expecting.  This can happen if a onepass sig header does
       not match the actual sig, and also if the clearsign "Hash:"
       header is missing or does not match the actual sig. */

    if(!md_algo_present(digest,sig->digest_algo)) {
        log_info(_("WARNING: signature digest conflict in message\n"));
	rc=G10ERR_BAD_SIGN;
    }
    else if( get_pubkey( pk, sig->keyid ) )
	rc = G10ERR_NO_PUBKEY;
    else if(!pk->is_valid && !pk->is_primary)
        rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
				 invalid subkey */
    else {
	*r_expiredate = pk->expiredate;
	rc = do_check( pk, sig, digest, r_expired );
    }

    free_public_key( pk );

    if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
	/* This signature id works best with DLP algorithms because
	 * they use a random parameter for every signature.  Instead of
	 * this sig-id we could have also used the hash of the document
	 * and the timestamp, but the drawback of this is, that it is
	 * not possible to sign more than one identical document within
	 * one second.	Some remote batch processing applications might
	 * like this feature here */
	MD_HANDLE md;
	u32 a = sig->timestamp;
	int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
	byte *p, *buffer;

	md = md_open( DIGEST_ALGO_RMD160, 0);
	md_putc( digest, sig->pubkey_algo );
	md_putc( digest, sig->digest_algo );
	md_putc( digest, (a >> 24) & 0xff );
	md_putc( digest, (a >> 16) & 0xff );
	md_putc( digest, (a >>	8) & 0xff );
	md_putc( digest,  a	   & 0xff );
	for(i=0; i < nsig; i++ ) {
	    unsigned n = mpi_get_nbits( sig->data[i]);

	    md_putc( md, n>>8);
	    md_putc( md, n );
	    p = mpi_get_buffer( sig->data[i], &n, NULL );
	    md_write( md, p, n );
	    m_free(p);
	}
	md_final( md );
	p = make_radix64_string( md_read( md, 0 ), 20 );
	buffer = m_alloc( strlen(p) + 60 );
	sprintf( buffer, "%s %s %lu",
		 p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
	write_status_text( STATUS_SIG_ID, buffer );
	m_free(buffer);
	m_free(p);
	md_close(md);
    }
int
signature_check2( PKT_signature *sig, MD_HANDLE digest, u32 *r_expiredate, 
		  int *r_expired, int *r_revoked, PKT_public_key *ret_pk )
{
    PKT_public_key *pk = xmalloc_clear( sizeof *pk );
    int rc=0;

    if( (rc=check_digest_algo(sig->digest_algo)) )
      ; /* we don't have this digest */
    else if((rc=check_pubkey_algo(sig->pubkey_algo)))
      ; /* we don't have this pubkey algo */
    else if(!md_algo_present(digest,sig->digest_algo))
      {
	/* Sanity check that the md has a context for the hash that the
	   sig is expecting.  This can happen if a onepass sig header does
	   not match the actual sig, and also if the clearsign "Hash:"
	   header is missing or does not match the actual sig. */

        log_info(_("WARNING: signature digest conflict in message\n"));
	rc=G10ERR_GENERAL;
      }
    else if( get_pubkey( pk, sig->keyid ) )
	rc = G10ERR_NO_PUBKEY;
    else if(!pk->is_valid && !pk->is_primary)
        rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
				 invalid subkey */
    else
      {
        if(r_expiredate)
	  *r_expiredate = pk->expiredate;

	rc = do_check( pk, sig, digest, r_expired, r_revoked, ret_pk );

	/* Check the backsig.  This is a 0x19 signature from the
	   subkey on the primary key.  The idea here is that it should
	   not be possible for someone to "steal" subkeys and claim
	   them as their own.  The attacker couldn't actually use the
	   subkey, but they could try and claim ownership of any
	   signaures issued by it. */
	if(rc==0 && !pk->is_primary && pk->backsig<2)
	  {
	    if(pk->backsig==0)
	      {
		log_info(_("WARNING: signing subkey %s is not"
			   " cross-certified\n"),keystr_from_pk(pk));
		log_info(_("please see %s for more information\n"),
			 "http://www.gnupg.org/faq/subkey-cross-certify.html");
		/* --require-cross-certification makes this warning an
                     error.  TODO: change the default to require this
                     after more keys have backsigs. */
		if(opt.flags.require_cross_cert)
		  rc=G10ERR_GENERAL;
	      }
	    else if(pk->backsig==1)
	      {
		log_info(_("WARNING: signing subkey %s has an invalid"
			   " cross-certification\n"),keystr_from_pk(pk));
		rc=G10ERR_GENERAL;
	      }
	  }
      }

    free_public_key( pk );

    if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
	/* This signature id works best with DLP algorithms because
	 * they use a random parameter for every signature.  Instead of
	 * this sig-id we could have also used the hash of the document
	 * and the timestamp, but the drawback of this is, that it is
	 * not possible to sign more than one identical document within
	 * one second.	Some remote batch processing applications might
	 * like this feature here */
	MD_HANDLE md;
	u32 a = sig->timestamp;
	int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
	byte *p, *buffer;

	md = md_open( DIGEST_ALGO_RMD160, 0);
	md_putc( digest, sig->pubkey_algo );
	md_putc( digest, sig->digest_algo );
	md_putc( digest, (a >> 24) & 0xff );
	md_putc( digest, (a >> 16) & 0xff );
	md_putc( digest, (a >>	8) & 0xff );
	md_putc( digest,  a	   & 0xff );
	for(i=0; i < nsig; i++ ) {
	    unsigned n = mpi_get_nbits( sig->data[i]);

	    md_putc( md, n>>8);
	    md_putc( md, n );
	    p = mpi_get_buffer( sig->data[i], &n, NULL );
	    md_write( md, p, n );
	    xfree(p);
	}
	md_final( md );
	p = make_radix64_string( md_read( md, 0 ), 20 );
	buffer = xmalloc( strlen(p) + 60 );
	sprintf( buffer, "%s %s %lu",
		 p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
	write_status_text( STATUS_SIG_ID, buffer );
	xfree(buffer);
	xfree(p);
	md_close(md);
    }