static gboolean
compare_keys (gcry_sexp_t key, gcry_sexp_t sexp)
{
	guchar hash1[20], hash2[20];
	guchar *p;

	/* Now compare them */
	p = gcry_pk_get_keygrip (key, hash1);
	g_assert ("couldn't get key id for private key" && p == hash1);
	p = gcry_pk_get_keygrip (sexp, hash2);
	g_assert ("couldn't get key id for parsed private key" && p == hash2);

	return memcmp (hash1, hash2, 20) == 0;
}
Exemple #2
0
static void
check_pubkey_grip (int n, const unsigned char *grip,
		   gcry_sexp_t skey, gcry_sexp_t pkey)
{
  unsigned char sgrip[20], pgrip[20];

  if (!gcry_pk_get_keygrip (skey, sgrip))
    die ("get keygrip for private RSA key failed\n");
  if (!gcry_pk_get_keygrip (pkey, pgrip))
    die ("[%i] get keygrip for public RSA key failed\n", n);
  if (memcmp (sgrip, pgrip, 20))
    fail ("[%i] keygrips don't match\n", n);
  if (memcmp (sgrip, grip, 20))
    fail ("wrong keygrip for RSA key\n");
}
/** Calculate hex-encoded keygrip of public key in sexp. */
char *keyutil_get_cert_hexgrip (gcry_sexp_t sexp)
{
	char *ret = NULL;
	unsigned char grip[20];
	
	if (gcry_pk_get_keygrip (sexp, grip)) {
		ret = encoding_bin2hex (grip, sizeof (grip));
	}

	return ret;
}
Exemple #4
0
/* Return the so called "keygrip" which is the SHA-1 hash of the
   public key parameters expressed in a way depended on the algorithm.

   KEY is expected to be an canonical encoded S-expression with a
   public or private key. KEYLEN is the length of that buffer.

   GRIP must be at least 20 bytes long.  On success 0 is returned, on
   error an error code. */
gpg_error_t
keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
                         unsigned char *grip)
{
    gpg_error_t err;
    gcry_sexp_t sexp;

    if (!grip)
        return gpg_error (GPG_ERR_INV_VALUE);
    err = gcry_sexp_sscan (&sexp, NULL, (const char *)key, keylen);
    if (err)
        return err;
    if (!gcry_pk_get_keygrip (sexp, grip))
        err = gpg_error (GPG_ERR_INTERNAL);
    gcry_sexp_release (sexp);
    return err;
}
Exemple #5
0
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
   key parameters expressed as an canoncial encoded S-Exp.  ARRAY must
   be 20 bytes long.  Returns ARRAY or a newly allocated buffer if ARRAY was
   given as NULL.  May return NULL on error.  */
unsigned char *
gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
{
  gcry_sexp_t s_pkey;
  int rc;
  ksba_sexp_t p;
  size_t n;

  p = ksba_cert_get_public_key (cert);
  if (!p)
    return NULL; /* oops */

  if (DBG_X509)
    log_debug ("get_keygrip for public key\n");
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    {
      log_error ("libksba did not return a proper S-Exp\n");
      return NULL;
    }
  rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
  xfree (p);
  if (rc)
    {
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
      return NULL;
    }
  array = gcry_pk_get_keygrip (s_pkey, array);
  gcry_sexp_release (s_pkey);
  if (!array)
    {
      rc = gpg_error (GPG_ERR_GENERAL);
      log_error ("can't calculate keygrip\n");
      return NULL;
    }
  if (DBG_X509)
    log_printhex ("keygrip=", array, 20);

  return array;
}
Exemple #6
0
/* Get the keygrip from CERT, return 0 on success */
int
card_help_get_keygrip (ksba_cert_t cert, unsigned char *array)
{
  gcry_sexp_t s_pkey;
  int rc;
  ksba_sexp_t p;
  size_t n;

  p = ksba_cert_get_public_key (cert);
  if (!p)
    return -1; /* oops */
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    return -1; /* libksba did not return a proper S-expression */
  rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
  xfree (p);
  if (rc)
    return -1; /* can't parse that S-expression */
  array = gcry_pk_get_keygrip (s_pkey, array);
  gcry_sexp_release (s_pkey);
  if (!array)
    return -1; /* failed to calculate the keygrip */
  return 0;
}
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
   We don't have the keygrips as meta data, thus we need to parse the
   certificate. Fixme: We might want to return proper error codes
   instead of failing a search for invalid certificates etc.  */
static int
blob_x509_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
{
  int rc;
  const unsigned char *buffer;
  size_t length;
  size_t cert_off, cert_len;
  ksba_reader_t reader = NULL;
  ksba_cert_t cert = NULL;
  ksba_sexp_t p = NULL;
  gcry_sexp_t s_pkey;
  unsigned char array[20];
  unsigned char *rcp;
  size_t n;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 40)
    return 0; /* Too short. */
  cert_off = get32 (buffer+8);
  cert_len = get32 (buffer+12);
  if (cert_off+cert_len > length)
    return 0; /* Too short.  */

  rc = ksba_reader_new (&reader);
  if (rc)
    return 0; /* Problem with ksba. */
  rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
  if (rc)
    goto failed;
  rc = ksba_cert_new (&cert);
  if (rc)
    goto failed;
  rc = ksba_cert_read_der (cert, reader);
  if (rc)
    goto failed;
  p = ksba_cert_get_public_key (cert);
  if (!p)
    goto failed;
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    goto failed;
  rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
  if (rc)
    {
      gcry_sexp_release (s_pkey);
      goto failed;
    }
  rcp = gcry_pk_get_keygrip (s_pkey, array);
  gcry_sexp_release (s_pkey);
  if (!rcp)
    goto failed; /* Can't calculate keygrip. */

  xfree (p);
  ksba_cert_release (cert);
  ksba_reader_release (reader);
  return !memcmp (array, grip, 20);
 failed:
  xfree (p);
  ksba_cert_release (cert);
  ksba_reader_release (reader);
  return 0;
}
Exemple #8
0
/* Assume that the reader is at a pkcs#12 message and try to import
   certificates from that stupid format.  We will transfer secret
   keys to the agent.  */
static gpg_error_t
parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
{
  gpg_error_t err = 0;
  char buffer[1024];
  size_t ntotal, nread;
  membuf_t p12mbuf;
  char *p12buffer = NULL;
  size_t p12buflen;
  size_t p12bufoff;
  gcry_mpi_t *kparms = NULL;
  struct rsa_secret_key_s sk;
  char *passphrase = NULL;
  unsigned char *key = NULL;
  size_t keylen;
  void *kek = NULL;
  size_t keklen;
  unsigned char *wrappedkey = NULL;
  size_t wrappedkeylen;
  gcry_cipher_hd_t cipherhd = NULL;
  gcry_sexp_t s_key = NULL;
  unsigned char grip[20];
  int bad_pass = 0;
  int i;
  struct store_cert_parm_s store_cert_parm;

  memset (&store_cert_parm, 0, sizeof store_cert_parm);
  store_cert_parm.ctrl = ctrl;
  store_cert_parm.stats = stats;

  init_membuf (&p12mbuf, 4096);
  ntotal = 0;
  while (!(err = ksba_reader_read (reader, buffer, sizeof buffer, &nread)))
    {
      if (ntotal >= MAX_P12OBJ_SIZE*1024)
        {
          /* Arbitrary limit to avoid DoS attacks. */
          err = gpg_error (GPG_ERR_TOO_LARGE);
          log_error ("pkcs#12 object is larger than %dk\n", MAX_P12OBJ_SIZE);
          break;
        }
      put_membuf (&p12mbuf, buffer, nread);
      ntotal += nread;
    }
  if (gpg_err_code (err) == GPG_ERR_EOF)
    err = 0;
  if (!err)
    {
      p12buffer = get_membuf (&p12mbuf, &p12buflen);
      if (!p12buffer)
        err = gpg_error_from_syserror ();
    }
  if (err)
    {
      log_error (_("error reading input: %s\n"), gpg_strerror (err));
      goto leave;
    }

  /* GnuPG 2.0.4 accidently created binary P12 files with the string
     "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data.
     We fix that here.  */
  if (p12buflen > 29 && !memcmp (p12buffer, "The passphrase is ", 18))
    {
      for (p12bufoff=18;
           p12bufoff < p12buflen && p12buffer[p12bufoff] != '\n';
           p12bufoff++)
        ;
      p12bufoff++;
      if (p12bufoff < p12buflen && p12buffer[p12bufoff] == '\n')
        p12bufoff++;
    }
  else
    p12bufoff = 0;


  err = gpgsm_agent_ask_passphrase
    (ctrl,
     i18n_utf8 ("Please enter the passphrase to unprotect the PKCS#12 object."),
     0, &passphrase);
  if (err)
    goto leave;

  kparms = p12_parse (p12buffer + p12bufoff, p12buflen - p12bufoff,
                      passphrase, store_cert_cb, &store_cert_parm, &bad_pass);

  xfree (passphrase);
  passphrase = NULL;

  if (!kparms)
    {
      log_error ("error parsing or decrypting the PKCS#12 file\n");
      err = gpg_error (GPG_ERR_INV_OBJ);
      goto leave;
    }

/*    print_mpi ("   n", kparms[0]); */
/*    print_mpi ("   e", kparms[1]); */
/*    print_mpi ("   d", kparms[2]); */
/*    print_mpi ("   p", kparms[3]); */
/*    print_mpi ("   q", kparms[4]); */
/*    print_mpi ("dmp1", kparms[5]); */
/*    print_mpi ("dmq1", kparms[6]); */
/*    print_mpi ("   u", kparms[7]); */

  sk.n = kparms[0];
  sk.e = kparms[1];
  sk.d = kparms[2];
  sk.q = kparms[3];
  sk.p = kparms[4];
  sk.u = kparms[7];
  err = rsa_key_check (&sk);
  if (err)
    goto leave;
/*    print_mpi ("   n", sk.n); */
/*    print_mpi ("   e", sk.e); */
/*    print_mpi ("   d", sk.d); */
/*    print_mpi ("   p", sk.p); */
/*    print_mpi ("   q", sk.q); */
/*    print_mpi ("   u", sk.u); */

  /* Create an S-expresion from the parameters. */
  err = gcry_sexp_build (&s_key, NULL,
                         "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
                         sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
  for (i=0; i < 8; i++)
    gcry_mpi_release (kparms[i]);
  gcry_free (kparms);
  kparms = NULL;
  if (err)
    {
      log_error ("failed to create S-expression from key: %s\n",
                 gpg_strerror (err));
      goto leave;
    }

  /* Compute the keygrip. */
  if (!gcry_pk_get_keygrip (s_key, grip))
    {
      err = gpg_error (GPG_ERR_GENERAL);
      log_error ("can't calculate keygrip\n");
      goto leave;
    }
  log_printhex ("keygrip=", grip, 20);

  /* Convert to canonical encoding using a function which pads it to a
     multiple of 64 bits.  We need this padding for AESWRAP.  */
  err = make_canon_sexp_pad (s_key, 1, &key, &keylen);
  if (err)
    {
      log_error ("error creating canonical S-expression\n");
      goto leave;
    }
  gcry_sexp_release (s_key);
  s_key = NULL;

  /* Get the current KEK.  */
  err = gpgsm_agent_keywrap_key (ctrl, 0, &kek, &keklen);
  if (err)
    {
      log_error ("error getting the KEK: %s\n", gpg_strerror (err));
      goto leave;
    }

  /* Wrap the key.  */
  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
                          GCRY_CIPHER_MODE_AESWRAP, 0);
  if (err)
    goto leave;
  err = gcry_cipher_setkey (cipherhd, kek, keklen);
  if (err)
    goto leave;
  xfree (kek);
  kek = NULL;

  wrappedkeylen = keylen + 8;
  wrappedkey = xtrymalloc (wrappedkeylen);
  if (!wrappedkey)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }

  err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
  if (err)
    goto leave;
  xfree (key);
  key = NULL;
  gcry_cipher_close (cipherhd);
  cipherhd = NULL;

  /* Send the wrapped key to the agent.  */
  err = gpgsm_agent_import_key (ctrl, wrappedkey, wrappedkeylen);
  if (!err)
    {
      stats->count++;
      stats->secret_read++;
      stats->secret_imported++;
    }
  else if ( gpg_err_code (err) == GPG_ERR_EEXIST )
    {
      err = 0;
      stats->count++;
      stats->secret_read++;
      stats->secret_dups++;
    }

  /* If we did not get an error from storing the secret key we return
     a possible error from parsing the certificates.  We do this after
     storing the secret keys so that a bad certificate does not
     inhibit our chance to store the secret key.  */
  if (!err && store_cert_parm.err)
    err = store_cert_parm.err;

 leave:
  if (kparms)
    {
      for (i=0; i < 8; i++)
        gcry_mpi_release (kparms[i]);
      gcry_free (kparms);
      kparms = NULL;
    }
  xfree (key);
  gcry_sexp_release (s_key);
  xfree (passphrase);
  gcry_cipher_close (cipherhd);
  xfree (wrappedkey);
  xfree (kek);
  xfree (get_membuf (&p12mbuf, NULL));
  xfree (p12buffer);

  if (bad_pass)
    {
      /* We only write a plain error code and not direct
         BAD_PASSPHRASE because the pkcs12 parser might issue this
         message multiple times, BAD_PASSPHRASE in general requires a
         keyID and parts of the import might actually succeed so that
         IMPORT_PROBLEM is also not appropriate. */
      gpgsm_status_with_err_code (ctrl, STATUS_ERROR,
                                  "import.parsep12", GPG_ERR_BAD_PASSPHRASE);
    }

  return err;
}