1 /* pkglue.c - public key operations glue code
2 * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
3 * Copyright (C) 2014 Werner Koch
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
34 /* FIXME: Better chnage the fucntion name because mpi_ is used by
37 get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
42 list = gcry_sexp_find_token (sexp, item, 0);
44 data = gcry_sexp_nth_mpi (list, 1, mpifmt);
46 gcry_sexp_release (list);
53 * Emulate our old PK interface here - sometime in the future we might
54 * change the internal design to directly fit to libgcrypt.
57 pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
58 gcry_mpi_t *data, gcry_mpi_t *pkey)
60 gcry_sexp_t s_sig, s_hash, s_pkey;
63 /* Make a sexp from pkey. */
64 if (pkalgo == PUBKEY_ALGO_DSA)
66 rc = gcry_sexp_build (&s_pkey, NULL,
67 "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
68 pkey[0], pkey[1], pkey[2], pkey[3]);
70 else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL)
72 rc = gcry_sexp_build (&s_pkey, NULL,
73 "(public-key(elg(p%m)(g%m)(y%m)))",
74 pkey[0], pkey[1], pkey[2]);
76 else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
78 rc = gcry_sexp_build (&s_pkey, NULL,
79 "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
81 else if (pkalgo == PUBKEY_ALGO_ECDSA)
83 char *curve = openpgp_oid_to_str (pkey[0]);
85 rc = gpg_error_from_syserror ();
88 rc = gcry_sexp_build (&s_pkey, NULL,
89 "(public-key(ecdsa(curve %s)(q%m)))",
94 else if (pkalgo == PUBKEY_ALGO_EDDSA)
96 char *curve = openpgp_oid_to_str (pkey[0]);
98 rc = gpg_error_from_syserror ();
101 rc = gcry_sexp_build (&s_pkey, NULL,
102 "(public-key(ecc(curve %s)"
103 "(flags eddsa)(q%m)))",
109 return GPG_ERR_PUBKEY_ALGO;
112 BUG (); /* gcry_sexp_build should never fail. */
114 /* Put hash into a S-Exp s_hash. */
115 if (pkalgo == PUBKEY_ALGO_EDDSA)
117 if (gcry_sexp_build (&s_hash, NULL,
118 "(data(flags eddsa)(hash-algo sha512)(value %m))",
120 BUG (); /* gcry_sexp_build should never fail. */
124 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
125 BUG (); /* gcry_sexp_build should never fail. */
128 /* Put data into a S-Exp s_sig. */
130 if (pkalgo == PUBKEY_ALGO_DSA)
132 if (!data[0] || !data[1])
133 rc = gpg_error (GPG_ERR_BAD_MPI);
135 rc = gcry_sexp_build (&s_sig, NULL,
136 "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
138 else if (pkalgo == PUBKEY_ALGO_ECDSA)
140 if (!data[0] || !data[1])
141 rc = gpg_error (GPG_ERR_BAD_MPI);
143 rc = gcry_sexp_build (&s_sig, NULL,
144 "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
146 else if (pkalgo == PUBKEY_ALGO_EDDSA)
148 if (!data[0] || !data[1])
149 rc = gpg_error (GPG_ERR_BAD_MPI);
151 rc = gcry_sexp_build (&s_sig, NULL,
152 "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]);
154 else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
156 if (!data[0] || !data[1])
157 rc = gpg_error (GPG_ERR_BAD_MPI);
159 rc = gcry_sexp_build (&s_sig, NULL,
160 "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
162 else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
165 rc = gpg_error (GPG_ERR_BAD_MPI);
167 rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
173 rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
175 gcry_sexp_release (s_sig);
176 gcry_sexp_release (s_hash);
177 gcry_sexp_release (s_pkey);
185 * Emulate our old PK interface here - sometime in the future we might
186 * change the internal design to directly fit to libgcrypt.
187 * PK is only required to compute the fingerprint for ECDH.
190 pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
191 PKT_public_key *pk, gcry_mpi_t *pkey)
193 gcry_sexp_t s_ciph = NULL;
194 gcry_sexp_t s_data = NULL;
195 gcry_sexp_t s_pkey = NULL;
198 /* Make a sexp from pkey. */
199 if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
201 rc = gcry_sexp_build (&s_pkey, NULL,
202 "(public-key(elg(p%m)(g%m)(y%m)))",
203 pkey[0], pkey[1], pkey[2]);
204 /* Put DATA into a simplified S-expression. */
206 rc = gcry_sexp_build (&s_data, NULL, "%m", data);
208 else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
210 rc = gcry_sexp_build (&s_pkey, NULL,
211 "(public-key(rsa(n%m)(e%m)))",
213 /* Put DATA into a simplified S-expression. */
215 rc = gcry_sexp_build (&s_data, NULL, "%m", data);
217 else if (algo == PUBKEY_ALGO_ECDH)
221 rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
226 curve = openpgp_oid_to_str (pkey[0]);
228 rc = gpg_error_from_syserror ();
231 /* Now use the ephemeral secret to compute the shared point. */
232 rc = gcry_sexp_build (&s_pkey, NULL,
233 "(public-key(ecdh(curve%s)(q%m)))",
236 /* Put K into a simplified S-expression. */
238 rc = gcry_sexp_build (&s_data, NULL, "%m", k);
240 gcry_mpi_release (k);
244 rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
246 /* Pass it to libgcrypt. */
248 rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
250 gcry_sexp_release (s_data);
251 gcry_sexp_release (s_pkey);
255 else if (algo == PUBKEY_ALGO_ECDH)
257 gcry_mpi_t shared, public, result;
258 byte fp[MAX_FINGERPRINT_LEN];
261 /* Get the shared point and the ephemeral public key. */
262 shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
263 public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
264 gcry_sexp_release (s_ciph);
268 log_debug ("ECDH ephemeral key:");
269 gcry_mpi_dump (public);
274 fingerprint_from_pk (pk, fp, &fpn);
276 rc = gpg_error (GPG_ERR_INV_LENGTH);
278 rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
279 fp, data, pkey, &result);
280 gcry_mpi_release (shared);
288 gcry_mpi_release (public);
289 gcry_mpi_release (result);
292 else /* Elgamal or RSA case. */
293 { /* Fixme: Add better error handling or make gnupg use
294 S-expressions directly. */
295 resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
297 resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
300 gcry_sexp_release (s_ciph);
305 /* Check whether SKEY is a suitable secret key. */
307 pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
312 if (pkalgo == PUBKEY_ALGO_DSA)
314 rc = gcry_sexp_build (&s_skey, NULL,
315 "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
316 skey[0], skey[1], skey[2], skey[3], skey[4]);
318 else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
320 rc = gcry_sexp_build (&s_skey, NULL,
321 "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
322 skey[0], skey[1], skey[2], skey[3]);
324 else if (is_RSA (pkalgo))
326 rc = gcry_sexp_build (&s_skey, NULL,
327 "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
328 skey[0], skey[1], skey[2], skey[3], skey[4],
331 else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH)
333 char *curve = openpgp_oid_to_str (skey[0]);
335 rc = gpg_error_from_syserror ();
338 rc = gcry_sexp_build (&s_skey, NULL,
339 "(private-key(ecc(curve%s)(q%m)(d%m)))",
340 curve, skey[1], skey[2]);
344 else if (pkalgo == PUBKEY_ALGO_EDDSA)
346 char *curve = openpgp_oid_to_str (skey[0]);
348 rc = gpg_error_from_syserror ();
351 rc = gcry_sexp_build (&s_skey, NULL,
352 "(private-key(ecc(curve %s)"
353 "(flags eddsa)(q%m)(d%m)))",
354 curve, skey[1], skey[2]);
359 return GPG_ERR_PUBKEY_ALGO;
363 rc = gcry_pk_testkey (s_skey);
364 gcry_sexp_release (s_skey);