Exemple #1
0
static int
generate_subkey( cdk_keygen_ctx_t hd )
{
    gcry_sexp_t s_params = NULL, s_key;
    size_t n = hd->key[1].len;
    int rc;

    if( !hd )
        return CDK_Inv_Value;
  
    if( is_DSA( hd->key[1].algo) )
        rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n );
    else if( is_ELG( hd->key[1].algo) )
        rc = gcry_sexp_build( &s_params, NULL, "(genkey(elg(nbits %d)))", n );
    else if( is_RSA( hd->key[1].algo) )
        rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n );
    else
        rc = CDK_Inv_Algo;
    if( !rc )
        rc = gcry_pk_genkey( &s_key, s_params );
    gcry_sexp_release( s_params );
    if( !rc ) {
        if( is_DSA( hd->key[1].algo) )
            rc = read_dsa_key( s_key, hd->key[1].resarr );
        else if( is_ELG( hd->key[1].algo) )
            rc = read_elg_key( s_key, hd->key[1].resarr );
        else if( is_RSA( hd->key[1].algo) )
            rc = read_rsa_key( s_key, hd->key[1].resarr );
    }
    hd->key[1].n = cdk_pk_get_npkey( hd->key[1].algo );
    gcry_sexp_release( s_key );
    return rc;
}
Exemple #2
0
/* Hash all multi precision integers of the key PK with the given
   message digest context MD. */
static int
hash_mpibuf (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
{
  byte buf[MAX_MPI_BYTES];	/* FIXME: do not use hardcoded length. */
  size_t nbytes;
  size_t i, npkey;
  int err;

  /* We have to differ between two modes for v3 keys. To form the
     fingerprint, we hash the MPI values without the length prefix.
     But if we calculate the hash for verifying/signing we use all data. */
  npkey = cdk_pk_get_npkey (pk->pubkey_algo);
  for (i = 0; i < npkey; i++)
    {
      nbytes = MAX_MPI_BYTES;
      err = _gnutls_mpi_print_pgp (pk->mpi[i], buf, &nbytes);
      if (err < 0)
	return map_gnutls_error (err);
      if (!usefpr || pk->version == 4)
	_gnutls_hash (md, buf, nbytes);
      else			/* without the prefix. */
	_gnutls_hash (md, buf + 2, nbytes - 2);
    }
  return 0;
}
Exemple #3
0
/**
 * cdk_pk_get_mpi:
 * @pk: public key
 * @idx: index of the MPI to retrieve
 * @buf: buffer to hold the raw data
 * @r_nwritten: output how large the raw data is
 * @r_nbits: size of the MPI in bits.
 * 
 * Return the MPI with the given index of the public key.
 **/
cdk_error_t
cdk_pk_get_mpi (cdk_pubkey_t pk, size_t idx,
                byte *buf, size_t buflen, size_t *r_nwritten, size_t *r_nbits)
{
  if (!pk || !r_nwritten)
    return CDK_Inv_Value;
  if (idx > cdk_pk_get_npkey (pk->pubkey_algo))
    return CDK_Inv_Value;
  return mpi_to_buffer (pk->mpi[idx], buf, buflen, r_nwritten, r_nbits);
}
Exemple #4
0
/**
 * cdk_pk_get_nskey:
 * @algo: the public key algorithm
 * 
 * Return the number of multiprecision integers forming an
 * secret key with the given algorithm.
 **/
int
cdk_pk_get_nskey (int algo)
{  
  size_t bytes;
  
  if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &bytes))
    return 0;  
  bytes -= cdk_pk_get_npkey (algo);
  return bytes;  
}
Exemple #5
0
cdk_error_t _cdk_pubkey_compare(cdk_pkt_pubkey_t a, cdk_pkt_pubkey_t b)
{
	int na, nb, i;

	if (a->timestamp != b->timestamp
	    || a->pubkey_algo != b->pubkey_algo)
		return -1;
	if (a->version < 4 && a->expiredate != b->expiredate)
		return -1;
	na = cdk_pk_get_npkey(a->pubkey_algo);
	nb = cdk_pk_get_npkey(b->pubkey_algo);
	if (na != nb)
		return -1;

	for (i = 0; i < na; i++) {
		if (_gnutls_mpi_cmp(a->mpi[i], b->mpi[i]))
			return -1;
	}

	return 0;
}
Exemple #6
0
static void
hash_mpibuf( cdk_pkt_pubkey_t pk, cdk_md_hd_t md )
{
    cdk_mpi_t a;
    int i, npkey;

    npkey = cdk_pk_get_npkey( pk->pubkey_algo );
    for( i = 0; i < npkey; i++ ) {
        a = pk->mpi[i];
        if( pk->version == 4 ) {
            cdk_md_putc( md, a->bits >> 8 );
            cdk_md_putc( md, a->bits );
        }
        cdk_md_write( md, a->data + 2, a->bytes );
    }
Exemple #7
0
void cdk_pk_release(cdk_pubkey_t pk)
{
	size_t npkey;

	if (!pk)
		return;

	npkey = cdk_pk_get_npkey(pk->pubkey_algo);
	_cdk_free_userid(pk->uid);
	pk->uid = NULL;
	cdk_free(pk->prefs);
	pk->prefs = NULL;
	_cdk_free_mpibuf(npkey, pk->mpi);
	cdk_free(pk);
}
Exemple #8
0
static cdk_error_t
write_public_key (cdk_stream_t out, cdk_pkt_pubkey_t pk,
		  int is_subkey, int old_ctb)
{
  int pkttype, ndays = 0;
  size_t npkey = 0, size = 6;
  cdk_error_t rc;

  assert (out);
  assert (pk);

  if (pk->version < 2 || pk->version > 4)
    return CDK_Inv_Packet;

  if (DEBUG_PKT)
    _cdk_log_debug ("write_public_key: subkey=%d\n", is_subkey);

  pkttype = is_subkey ? CDK_PKT_PUBLIC_SUBKEY : CDK_PKT_PUBLIC_KEY;
  npkey = cdk_pk_get_npkey (pk->pubkey_algo);
  if (!npkey)
    return CDK_Inv_Algo;
  if (pk->version < 4)
    size += 2;			/* expire date */
  if (is_subkey)
    old_ctb = 0;
  size += calc_mpisize (pk->mpi, npkey);
  if (old_ctb)
    rc = pkt_write_head2 (out, size, pkttype);
  else
    rc = pkt_write_head (out, old_ctb, size, pkttype);
  if (!rc)
    rc = stream_putc (out, pk->version);
  if (!rc)
    rc = write_32 (out, pk->timestamp);
  if (!rc && pk->version < 4)
    {
      if (pk->expiredate)
	ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
      rc = write_16 (out, ndays);
    }
  if (!rc)
    rc = stream_putc (out, _cdk_pub_algo_to_pgp (pk->pubkey_algo));
  if (!rc)
    rc = write_mpibuf (out, pk->mpi, npkey);
  return rc;
}
Exemple #9
0
static cdk_error_t
read_public_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_t pk)
{
  size_t i, ndays, npkey;

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

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

  pk->is_invalid = 1;		/* default to detect missing self signatures */
  pk->is_revoked = 0;
  pk->has_expired = 0;

  pk->version = cdk_stream_getc (inp);
  if (pk->version < 2 || pk->version > 4)
    return CDK_Inv_Packet_Ver;
  pk->timestamp = read_32 (inp);
  if (pk->version < 4)
    {
      ndays = read_16 (inp);
      if (ndays)
	pk->expiredate = pk->timestamp + ndays * 86400L;
    }

  pk->pubkey_algo = _pgp_pub_algo_to_cdk (cdk_stream_getc (inp));
  npkey = cdk_pk_get_npkey (pk->pubkey_algo);
  if (!npkey)
    {
      gnutls_assert ();
      _cdk_log_debug ("invalid public key algorithm %d\n", pk->pubkey_algo);
      return CDK_Inv_Algo;
    }
  for (i = 0; i < npkey; i++)
    {
      cdk_error_t rc = read_mpi (inp, &pk->mpi[i], 0);
      if (rc)
	return rc;
    }

  /* This value is just for the first run and will be
     replaced with the actual key flags from the self signature. */
  pk->pubkey_usage = 0;
  return 0;
}
Exemple #10
0
/**
 * cdk_keygen_start: kick off the key generation
 * @hd: the keygen object
 *
 **/
cdk_error_t
cdk_keygen_start( cdk_keygen_ctx_t hd )
{
    gcry_sexp_t s_params = NULL, s_key = NULL;
    size_t n;
    int rc = 0;
  
    if( !hd || !hd->user_id )
        return CDK_Inv_Value;
    if( is_ELG( hd->key[0].algo ) )
        return CDK_Inv_Mode;
    if( !hd->key[0].len )
        hd->key[0].len = 1024;
    n = hd->key[0].len;

    if( !hd->sym_prefs )
        cdk_keygen_set_prefs( hd, CDK_PREFTYPE_SYM, NULL, 0 );
    if( !hd->hash_prefs )
        cdk_keygen_set_prefs( hd, CDK_PREFTYPE_HASH, NULL, 0 );
    if( !hd->zip_prefs )
        cdk_keygen_set_prefs( hd, CDK_PREFTYPE_ZIP, NULL, 0 );

    if( is_DSA( hd->key[0].algo ) )
        rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n );
    else if( is_RSA( hd->key[0].algo ) )
        rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n );
    else
        rc = CDK_Inv_Algo;
    if( !rc )
        rc = gcry_pk_genkey( &s_key, s_params );
    gcry_sexp_release( s_params );
    if( !rc ) {
        if( is_DSA( hd->key[0].algo ) )
            rc = read_dsa_key( s_key, hd->key[0].resarr );
        else if( is_RSA( hd->key[0].algo ) )
            rc = read_rsa_key( s_key, hd->key[0].resarr );
        hd->key[0].n = cdk_pk_get_npkey( hd->key[0].algo );
    }
    gcry_sexp_release( s_key );
    if( !rc ) {
        if( hd->key[1].algo && hd->key[1].len )
            rc = generate_subkey( hd );
    }
    return rc;
}
Exemple #11
0
/**
 * cdk_pk_get_nskey:
 * @algo: the public key algorithm
 * 
 * Return the number of multiprecision integers forming an
 * secret key with the given algorithm.
 **/
int cdk_pk_get_nskey(int algo)
{
	int ret;

	if (is_RSA(algo))
		ret = RSA_PRIVATE_PARAMS - 2;	/* we don't have exp1 and exp2 */
	else if (is_DSA(algo))
		ret = DSA_PRIVATE_PARAMS;
	else if (is_ELG(algo))
		ret = 4;
	else {
		gnutls_assert();
		return 0;
	}

	ret -= cdk_pk_get_npkey(algo);
	return ret;
}
Exemple #12
0
static int
gcry_mpi_to_native( cdk_keygen_ctx_t hd, size_t nkey, int type,
                    cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk )
{
    gcry_mpi_t * resarr;
    cdk_mpi_t a = NULL;
    size_t nbytes;
    int i = 0, j = 0, nbits;
    int rc = 0;

    if( !hd )
        return CDK_Inv_Value;
    if( !pk && !sk )
        return CDK_Inv_Value;
    if( type < 0 || type > 1 )
        return CDK_Inv_Value;

    resarr = hd->key[type].resarr;
    if( sk )
        i += cdk_pk_get_npkey( sk->pubkey_algo );
    while( j != nkey ) {
        nbits = gcry_mpi_get_nbits( resarr[i] );
        if( pk )
            a = cdk_calloc( 1, sizeof * a + (nbits + 7) / 8 + 2 + 1 );
        else if( sk )
            a = cdk_salloc( sizeof * a + (nbits + 7) / 8 + 2 + 1, 1 );
        a->bits = nbits;
        a->bytes = ( nbits + 7 ) / 8;
        nbytes = a->bytes;
        a->data[0] = nbits >> 8;
        a->data[1] = nbits;
        rc = gcry_mpi_print( GCRYMPI_FMT_USG, a->data+2, nbytes, &nbytes, resarr[i] );
        if( rc )
            break;
        if( pk )
            pk->mpi[j++] = a;
        else if( sk )
            sk->mpi[j++] = a;
        i++;
    }
    return rc;
}
Exemple #13
0
/* Hash an entire public key PK with the given message digest context
   MD. The @usefpr param is only valid for version 3 keys because of
   the different way to calculate the fingerprint. */
cdk_error_t
_cdk_hash_pubkey (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
{
  byte buf[12];
  size_t i, n, npkey;

  if (!pk || !md)
    return CDK_Inv_Value;

  if (usefpr && pk->version < 4 && is_RSA (pk->pubkey_algo))
    return hash_mpibuf (pk, md, 1);

  /* The version 4 public key packet does not have the 2 octets for
     the expiration date. */
  n = pk->version < 4 ? 8 : 6;
  npkey = cdk_pk_get_npkey (pk->pubkey_algo);
  for (i = 0; i < npkey; i++)
    n = n + (_gnutls_mpi_get_nbits (pk->mpi[i]) + 7) / 8 + 2;

  i = 0;
  buf[i++] = 0x99;
  buf[i++] = n >> 8;
  buf[i++] = n >> 0;
  buf[i++] = pk->version;
  buf[i++] = pk->timestamp >> 24;
  buf[i++] = pk->timestamp >> 16;
  buf[i++] = pk->timestamp >> 8;
  buf[i++] = pk->timestamp >> 0;

  if (pk->version < 4)
    {
      u16 a = 0;

      /* Convert the expiration date into days. */
      if (pk->expiredate)
	a = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
      buf[i++] = a >> 8;
      buf[i++] = a;
    }
Exemple #14
0
cdk_error_t _cdk_copy_pubkey(cdk_pkt_pubkey_t * dst, cdk_pkt_pubkey_t src)
{
	cdk_pkt_pubkey_t k;
	int i;

	if (!dst || !src)
		return CDK_Inv_Value;

	*dst = NULL;
	k = cdk_calloc(1, sizeof *k);
	if (!k)
		return CDK_Out_Of_Core;
	memcpy(k, src, sizeof *k);
	if (src->uid)
		_cdk_copy_userid(&k->uid, src->uid);
	if (src->prefs)
		k->prefs = _cdk_copy_prefs(src->prefs);
	for (i = 0; i < cdk_pk_get_npkey(src->pubkey_algo); i++)
		k->mpi[i] = _gnutls_mpi_copy(src->mpi[i]);
	*dst = k;

	return 0;
}
Exemple #15
0
static cdk_pkt_pubkey_t
pk_create( cdk_keygen_ctx_t hd, int type )
{
    cdk_pkt_pubkey_t pk;
    int rc = 0, npkey = 0;

    if( type < 0 || type > 1 )
        return NULL;
    pk = cdk_calloc( 1, sizeof * pk );
    if( !pk )
        return NULL;
    pk->version = 4;
    pk->pubkey_algo = hd->key[type].algo;
    pk->timestamp = _cdk_timestamp( );
    if( hd->key[type].expire_date )
        pk->expiredate = pk->timestamp + hd->key[type].expire_date;
    npkey = cdk_pk_get_npkey( pk->pubkey_algo );
    rc = gcry_mpi_to_native( hd, npkey, type, pk, NULL );
    if( rc ) {
        cdk_free( pk );
        pk = NULL;
    }
    return pk;
}
Exemple #16
0
/**
 * cdk_pk_verify:
 * @pk: the public key
 * @sig: signature
 * @md: the message digest
 *
 * Verify the signature in @sig and compare it with the message digest in @md.
 **/
cdk_error_t
cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md)
{
    gnutls_datum_t s_sig;
    byte *encmd = NULL;
    size_t enclen;
    cdk_error_t rc;
    int ret, algo;
    unsigned int i;
    gnutls_datum_t data;
    gnutls_pk_params_st params;

    if (!pk || !sig || !md)
    {
        gnutls_assert ();
        return CDK_Inv_Value;
    }

    if (is_DSA (pk->pubkey_algo))
        algo = GNUTLS_PK_DSA;
    else if (is_RSA (pk->pubkey_algo))
        algo = GNUTLS_PK_RSA;
    else
    {
        gnutls_assert ();
        return CDK_Inv_Value;
    }

    rc = sig_to_datum (&s_sig, sig);
    if (rc)
    {
        gnutls_assert ();
        goto leave;
    }

    rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, pk->pubkey_algo, md,
                                   sig->digest_algo, cdk_pk_get_nbits (pk));
    if (rc)
    {
        gnutls_assert ();
        goto leave;
    }

    data.data = encmd;
    data.size = enclen;

    params.params_nr = cdk_pk_get_npkey (pk->pubkey_algo);
    for (i = 0; i < params.params_nr; i++)
        params.params[i] = pk->mpi[i];
    params.flags = 0;
    ret = _gnutls_pk_verify (algo, &data, &s_sig, &params);

    if (ret < 0)
    {
        gnutls_assert ();
        rc = map_gnutls_error (ret);
        goto leave;
    }

    rc = 0;

leave:
    _gnutls_free_datum (&s_sig);
    cdk_free (encmd);
    return rc;
}
Exemple #17
0
static cdk_error_t
write_secret_key (cdk_stream_t out, cdk_pkt_seckey_t sk,
		  int is_subkey, int old_ctb)
{
  cdk_pkt_pubkey_t pk = NULL;
  size_t size = 6, npkey, nskey;
  int pkttype, s2k_mode;
  cdk_error_t rc;

  assert (out);
  assert (sk);

  if (!sk->pk)
    return CDK_Inv_Value;
  pk = sk->pk;
  if (pk->version < 2 || pk->version > 4)
    return CDK_Inv_Packet;

  if (DEBUG_PKT)
    _cdk_log_debug ("write_secret_key:\n");

  npkey = cdk_pk_get_npkey (pk->pubkey_algo);
  nskey = cdk_pk_get_nskey (pk->pubkey_algo);
  if (!npkey || !nskey)
    {
      gnutls_assert ();
      return CDK_Inv_Algo;
    }
  if (pk->version < 4)
    size += 2;
  /* If the key is unprotected, the 1 extra byte:
     1 octet  - cipher algorithm byte (0x00)
     the other bytes depend on the mode:
     a) simple checksum -  2 octets
     b) sha-1 checksum  - 20 octets */
  size = !sk->is_protected ? size + 1 : size + 1 + calc_s2ksize (sk);
  size += calc_mpisize (pk->mpi, npkey);
  if (sk->version == 3 || !sk->is_protected)
    {
      if (sk->version == 3)
	{
	  size += 2;		/* force simple checksum */
	  sk->protect.sha1chk = 0;
	}
      else
	size += sk->protect.sha1chk ? 20 : 2;
      size += calc_mpisize (sk->mpi, nskey);
    }
  else				/* We do not know anything about the encrypted mpi's so we
				   treat the data as opaque. */
    size += sk->enclen;

  pkttype = is_subkey ? CDK_PKT_SECRET_SUBKEY : CDK_PKT_SECRET_KEY;
  rc = pkt_write_head (out, old_ctb, size, pkttype);
  if (!rc)
    rc = stream_putc (out, pk->version);
  if (!rc)
    rc = write_32 (out, pk->timestamp);
  if (!rc && pk->version < 4)
    {
      u16 ndays = 0;
      if (pk->expiredate)
	ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
      rc = write_16 (out, ndays);
    }
  if (!rc)
    rc = stream_putc (out, _cdk_pub_algo_to_pgp (pk->pubkey_algo));

  if (!rc)
    rc = write_mpibuf (out, pk->mpi, npkey);

  if (!rc) 
    {
      if (sk->is_protected == 0)
        rc = stream_putc (out, 0x00);
      else
        {
          if (is_RSA (pk->pubkey_algo) && pk->version < 4)
   	    rc = stream_putc (out, _gnutls_cipher_to_pgp (sk->protect.algo));
          else if (sk->protect.s2k)
            {
              s2k_mode = sk->protect.s2k->mode;
              rc = stream_putc (out, sk->protect.sha1chk ? 0xFE : 0xFF);
              if (!rc)
                rc = stream_putc (out, _gnutls_cipher_to_pgp (sk->protect.algo));
              if (!rc)
                rc = stream_putc (out, sk->protect.s2k->mode);
              if (!rc)
                rc = stream_putc (out, sk->protect.s2k->hash_algo);
              if (!rc && (s2k_mode == 1 || s2k_mode == 3))
                {
                  rc = stream_write (out, sk->protect.s2k->salt, 8);
                  if (!rc && s2k_mode == 3)
                    rc = stream_putc (out, sk->protect.s2k->count);
                }
            }
          else
            return CDK_Inv_Value;
          if (!rc)
          rc = stream_write (out, sk->protect.iv, sk->protect.ivlen);
        }
    }
  if (!rc && sk->is_protected && pk->version == 4)
    {
      if (sk->encdata && sk->enclen)
	rc = stream_write (out, sk->encdata, sk->enclen);
    }
  else
    {
      if (!rc)
	rc = write_mpibuf (out, sk->mpi, nskey);
      if (!rc)
	{
	  if (!sk->csum)
	    sk->csum = _cdk_sk_get_csum (sk);
	  rc = write_16 (out, sk->csum);
	}
    }

  return rc;
}
Exemple #18
0
/**
 * cdk_pk_verify:
 * @pk: the public key
 * @sig: signature
 * @md: the message digest
 *
 * Verify the signature in @sig and compare it with the message digest in @md.
 **/
cdk_error_t
cdk_pk_verify(cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md)
{
	gnutls_datum_t s_sig = { NULL, 0 }, di = {
	NULL, 0};
	byte *encmd = NULL;
	cdk_error_t rc;
	int ret, algo;
	unsigned int i;
	gnutls_pk_params_st params;
	const mac_entry_st *me;

	if (!pk || !sig || !md) {
		gnutls_assert();
		return CDK_Inv_Value;
	}

	if (is_DSA(pk->pubkey_algo))
		algo = GNUTLS_PK_DSA;
	else if (is_RSA(pk->pubkey_algo))
		algo = GNUTLS_PK_RSA;
	else {
		gnutls_assert();
		return CDK_Inv_Value;
	}

	rc = sig_to_datum(&s_sig, sig);
	if (rc) {
		gnutls_assert();
		goto leave;
	}

	me = mac_to_entry(sig->digest_algo);
	rc = _gnutls_set_datum(&di, md, _gnutls_hash_get_algo_len(me));
	if (rc < 0) {
		rc = gnutls_assert_val(CDK_Out_Of_Core);
		goto leave;
	}

	rc = pk_prepare_hash(algo, me, &di);
	if (rc < 0) {
		rc = gnutls_assert_val(CDK_General_Error);
		goto leave;
	}

	params.params_nr = cdk_pk_get_npkey(pk->pubkey_algo);
	for (i = 0; i < params.params_nr; i++)
		params.params[i] = pk->mpi[i];
	params.flags = 0;
	ret = _gnutls_pk_verify(algo, &di, &s_sig, &params);

	if (ret < 0) {
		gnutls_assert();
		rc = map_gnutls_error(ret);
		goto leave;
	}

	rc = 0;

      leave:
	_gnutls_free_datum(&s_sig);
	_gnutls_free_datum(&di);
	cdk_free(encmd);
	return rc;
}