/* 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); }
/* 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); } }