Esempio n. 1
0
/* Return the PK algorithm used by CERT as well as the length in bits
   of the public key at NBITS. */
int
gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
{
  gcry_sexp_t s_pkey;
  int rc;
  ksba_sexp_t p;
  size_t n;
  gcry_sexp_t l1, l2;
  const char *name;
  char namebuf[128];

  if (nbits)
    *nbits = 0;

  p = ksba_cert_get_public_key (cert);
  if (!p)
    return 0;
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    {
      xfree (p);
      return 0;
    }
  rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
  xfree (p);
  if (rc)
    return 0;

  if (nbits)
    *nbits = gcry_pk_get_nbits (s_pkey);

  /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
  l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
  if (!l1)
    {
      gcry_sexp_release (s_pkey);
      return 0;
    }
  l2 = gcry_sexp_cadr (l1);
  gcry_sexp_release (l1);
  l1 = l2;
  name = gcry_sexp_nth_data (l1, 0, &n);
  if (name)
    {
      if (n > sizeof namebuf -1)
        n = sizeof namebuf -1;
      memcpy (namebuf, name, n);
      namebuf[n] = 0;
    }
  else
    *namebuf = 0;
  gcry_sexp_release (l1);
  gcry_sexp_release (s_pkey);
  return gcry_pk_map_name (namebuf);
}
Esempio n. 2
0
/* Return the Secure Shell type fingerprint for KEY using digest ALGO.
   The length of the fingerprint is returned at R_LEN and the
   fingerprint itself at R_FPR.  In case of a error code is returned
   and NULL stored at R_FPR.  */
static gpg_error_t
get_fingerprint (gcry_sexp_t key, int algo,
                 void **r_fpr, size_t *r_len, int as_string)
{
  gpg_error_t err;
  gcry_sexp_t list = NULL;
  gcry_sexp_t l2 = NULL;
  const char *s;
  char *name = NULL;
  int idx;
  const char *elems;
  gcry_md_hd_t md = NULL;
  int blobmode = 0;

  *r_fpr = NULL;
  *r_len = 0;

  /* Check that the first element is valid. */
  list = gcry_sexp_find_token (key, "public-key", 0);
  if (!list)
    list = gcry_sexp_find_token (key, "private-key", 0);
  if (!list)
    list = gcry_sexp_find_token (key, "protected-private-key", 0);
  if (!list)
    list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
  if (!list)
    {
      err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_SEXP);
      goto leave;
    }

  l2 = gcry_sexp_cadr (list);
  gcry_sexp_release (list);
  list = l2;
  l2 = NULL;

  name = gcry_sexp_nth_string (list, 0);
  if (!name)
    {
      err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
      goto leave;
    }

  err = gcry_md_open (&md, algo, 0);
  if (err)
    goto leave;

  switch (gcry_pk_map_name (name))
    {
    case GCRY_PK_RSA:
      elems = "en";
      gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11);
      break;

    case GCRY_PK_DSA:
      elems = "pqgy";
      gcry_md_write (md, "\0\0\0\x07ssh-dss", 11);
      break;

    case GCRY_PK_ECC:
      if (is_eddsa (list))
        {
          elems = "q";
          blobmode = 1;
          /* For now there is just one curve, thus no need to switch
             on it.  */
          gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15);
        }
      else
        {
          /* We only support the 3 standard curves for now.  It is
             just a quick hack.  */
          elems = "q";
          gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
          l2 = gcry_sexp_find_token (list, "curve", 0);
          if (!l2)
            elems = "";
          else
            {
              gcry_free (name);
              name = gcry_sexp_nth_string (l2, 1);
              gcry_sexp_release (l2);
              l2 = NULL;
              if (!name)
                elems = "";
              else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256"))
                gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
              else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384"))
                gcry_md_write (md, "384\0\0\0\x08nistp384", 15);
              else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521"))
                gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
              else
                elems = "";
            }
          if (!*elems)
            err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
        }
      break;

    default:
      elems = "";
      err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO);
      break;
    }
  if (err)
    goto leave;


  for (idx = 0, s = elems; *s; s++, idx++)
    {
      l2 = gcry_sexp_find_token (list, s, 1);
      if (!l2)
        {
          err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
          goto leave;
        }
      if (blobmode)
        {
          const char *blob;
          size_t bloblen;
          unsigned char lenbuf[4];

          blob = gcry_sexp_nth_data (l2, 1, &bloblen);
          if (!blob)
            {
              err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
              goto leave;
            }
          blob++;
          bloblen--;
          lenbuf[0] = bloblen >> 24;
          lenbuf[1] = bloblen >> 16;
          lenbuf[2] = bloblen >>  8;
          lenbuf[3] = bloblen;
          gcry_md_write (md, lenbuf, 4);
          gcry_md_write (md, blob, bloblen);
        }
      else
        {
          gcry_mpi_t a;
          unsigned char *buf;
          size_t buflen;

          a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
          gcry_sexp_release (l2);
          l2 = NULL;
          if (!a)
            {
              err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
              goto leave;
            }

          err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
          gcry_mpi_release (a);
          if (err)
            goto leave;
          gcry_md_write (md, buf, buflen);
          gcry_free (buf);
        }
    }