/src/gnupg/common/sexputil.c
Line | Count | Source |
1 | | /* sexputil.c - Utility functions for S-expressions. |
2 | | * Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
3 | | * Copyright (C) 2013 Werner Koch |
4 | | * |
5 | | * This file is part of GnuPG. |
6 | | * |
7 | | * This file is free software; you can redistribute it and/or modify |
8 | | * it under the terms of either |
9 | | * |
10 | | * - the GNU Lesser General Public License as published by the Free |
11 | | * Software Foundation; either version 3 of the License, or (at |
12 | | * your option) any later version. |
13 | | * |
14 | | * or |
15 | | * |
16 | | * - the GNU General Public License as published by the Free |
17 | | * Software Foundation; either version 2 of the License, or (at |
18 | | * your option) any later version. |
19 | | * |
20 | | * or both in parallel, as here. |
21 | | * |
22 | | * This file is distributed in the hope that it will be useful, |
23 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
24 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
25 | | * GNU General Public License for more details. |
26 | | * |
27 | | * You should have received a copy of the GNU General Public License |
28 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
29 | | */ |
30 | | |
31 | | /* This file implements a few utility functions useful when working |
32 | | with canonical encrypted S-expressions (i.e. not the S-exprssion |
33 | | objects from libgcrypt). */ |
34 | | |
35 | | #include <config.h> |
36 | | #include <stdio.h> |
37 | | #include <stdlib.h> |
38 | | #include <string.h> |
39 | | #include <unistd.h> |
40 | | #include <errno.h> |
41 | | #ifdef HAVE_LOCALE_H |
42 | | #include <locale.h> |
43 | | #endif |
44 | | |
45 | | #include "util.h" |
46 | | #include "tlv.h" |
47 | | #include "sexp-parse.h" |
48 | | #include "openpgpdefs.h" /* for pubkey_algo_t */ |
49 | | |
50 | | |
51 | | /* Return a malloced string with the S-expression CANON in advanced |
52 | | format. Returns NULL on error. */ |
53 | | static char * |
54 | | sexp_to_string (gcry_sexp_t sexp) |
55 | 0 | { |
56 | 0 | size_t n; |
57 | 0 | char *result; |
58 | |
|
59 | 0 | if (!sexp) |
60 | 0 | return NULL; |
61 | 0 | n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); |
62 | 0 | if (!n) |
63 | 0 | return NULL; |
64 | 0 | result = xtrymalloc (n); |
65 | 0 | if (!result) |
66 | 0 | return NULL; |
67 | 0 | n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, n); |
68 | 0 | if (!n) |
69 | 0 | BUG (); |
70 | | |
71 | 0 | return result; |
72 | 0 | } |
73 | | |
74 | | |
75 | | /* Return a malloced string with the S-expression CANON in advanced |
76 | | format. Returns NULL on error. */ |
77 | | char * |
78 | | canon_sexp_to_string (const unsigned char *canon, size_t canonlen) |
79 | 0 | { |
80 | 0 | size_t n; |
81 | 0 | gcry_sexp_t sexp; |
82 | 0 | char *result; |
83 | |
|
84 | 0 | n = gcry_sexp_canon_len (canon, canonlen, NULL, NULL); |
85 | 0 | if (!n) |
86 | 0 | return NULL; |
87 | 0 | if (gcry_sexp_sscan (&sexp, NULL, canon, n)) |
88 | 0 | return NULL; |
89 | 0 | result = sexp_to_string (sexp); |
90 | 0 | gcry_sexp_release (sexp); |
91 | 0 | return result; |
92 | 0 | } |
93 | | |
94 | | |
95 | | /* Print the canonical encoded S-expression in SEXP in advanced |
96 | | format. SEXPLEN may be passed as 0 is SEXP is known to be valid. |
97 | | With TEXT of NULL print just the raw S-expression, with TEXT just |
98 | | an empty string, print a trailing linefeed, otherwise print an |
99 | | entire debug line. */ |
100 | | void |
101 | | log_printcanon (const char *text, const unsigned char *sexp, size_t sexplen) |
102 | 0 | { |
103 | 0 | if (text && *text) |
104 | 0 | log_debug ("%s ", text); |
105 | 0 | if (sexp) |
106 | 0 | { |
107 | 0 | char *buf = canon_sexp_to_string (sexp, sexplen); |
108 | 0 | log_printf ("%s", buf? buf : "[invalid S-expression]"); |
109 | 0 | xfree (buf); |
110 | 0 | } |
111 | 0 | if (text) |
112 | 0 | log_printf ("\n"); |
113 | 0 | } |
114 | | |
115 | | |
116 | | /* Print the gcrypt S-expression SEXP in advanced format. With TEXT |
117 | | of NULL print just the raw S-expression, with TEXT just an empty |
118 | | string, print a trailing linefeed, otherwise print an entire debug |
119 | | line. */ |
120 | | void |
121 | | log_printsexp (const char *text, gcry_sexp_t sexp) |
122 | 0 | { |
123 | 0 | if (text && *text) |
124 | 0 | log_debug ("%s ", text); |
125 | 0 | if (sexp) |
126 | 0 | { |
127 | 0 | char *buf = sexp_to_string (sexp); |
128 | 0 | log_printf ("%s", buf? buf : "[invalid S-expression]"); |
129 | 0 | xfree (buf); |
130 | 0 | } |
131 | 0 | if (text) |
132 | 0 | log_printf ("\n"); |
133 | 0 | } |
134 | | |
135 | | |
136 | | /* Helper function to create a canonical encoded S-expression from a |
137 | | Libgcrypt S-expression object. The function returns 0 on success |
138 | | and the malloced canonical S-expression is stored at R_BUFFER and |
139 | | the allocated length at R_BUFLEN. On error an error code is |
140 | | returned and (NULL, 0) stored at R_BUFFER and R_BUFLEN. If the |
141 | | allocated buffer length is not required, NULL by be used for |
142 | | R_BUFLEN. */ |
143 | | gpg_error_t |
144 | | make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen) |
145 | 0 | { |
146 | 0 | size_t len; |
147 | 0 | unsigned char *buf; |
148 | |
|
149 | 0 | *r_buffer = NULL; |
150 | 0 | if (r_buflen) |
151 | 0 | *r_buflen = 0;; |
152 | |
|
153 | 0 | len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); |
154 | 0 | if (!len) |
155 | 0 | return gpg_error (GPG_ERR_BUG); |
156 | 0 | buf = gcry_is_secure (sexp)? xtrymalloc_secure (len) : xtrymalloc (len); |
157 | 0 | if (!buf) |
158 | 0 | return gpg_error_from_syserror (); |
159 | 0 | len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len); |
160 | 0 | if (!len) |
161 | 0 | return gpg_error (GPG_ERR_BUG); |
162 | | |
163 | 0 | *r_buffer = buf; |
164 | 0 | if (r_buflen) |
165 | 0 | *r_buflen = len; |
166 | |
|
167 | 0 | return 0; |
168 | 0 | } |
169 | | |
170 | | |
171 | | /* Same as make_canon_sexp but pad the buffer to multiple of 64 |
172 | | bits. If SECURE is set, secure memory will be allocated. */ |
173 | | gpg_error_t |
174 | | make_canon_sexp_pad (gcry_sexp_t sexp, int secure, |
175 | | unsigned char **r_buffer, size_t *r_buflen) |
176 | 0 | { |
177 | 0 | size_t len; |
178 | 0 | unsigned char *buf; |
179 | |
|
180 | 0 | *r_buffer = NULL; |
181 | 0 | if (r_buflen) |
182 | 0 | *r_buflen = 0;; |
183 | |
|
184 | 0 | len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); |
185 | 0 | if (!len) |
186 | 0 | return gpg_error (GPG_ERR_BUG); |
187 | 0 | len += (8 - len % 8) % 8; |
188 | 0 | buf = secure? xtrycalloc_secure (1, len) : xtrycalloc (1, len); |
189 | 0 | if (!buf) |
190 | 0 | return gpg_error_from_syserror (); |
191 | 0 | if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len)) |
192 | 0 | return gpg_error (GPG_ERR_BUG); |
193 | | |
194 | 0 | *r_buffer = buf; |
195 | 0 | if (r_buflen) |
196 | 0 | *r_buflen = len; |
197 | |
|
198 | 0 | return 0; |
199 | 0 | } |
200 | | |
201 | | /* Return the so called "keygrip" which is the SHA-1 hash of the |
202 | | public key parameters expressed in a way dependent on the algorithm. |
203 | | |
204 | | KEY is expected to be an canonical encoded S-expression with a |
205 | | public or private key. KEYLEN is the length of that buffer. |
206 | | |
207 | | GRIP must be at least 20 bytes long. On success 0 is returned, on |
208 | | error an error code. */ |
209 | | gpg_error_t |
210 | | keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, |
211 | | unsigned char *grip) |
212 | 0 | { |
213 | 0 | gpg_error_t err; |
214 | 0 | gcry_sexp_t sexp; |
215 | |
|
216 | 0 | if (!grip) |
217 | 0 | return gpg_error (GPG_ERR_INV_VALUE); |
218 | 0 | err = gcry_sexp_sscan (&sexp, NULL, (const char *)key, keylen); |
219 | 0 | if (err) |
220 | 0 | return err; |
221 | 0 | if (!gcry_pk_get_keygrip (sexp, grip)) |
222 | 0 | err = gpg_error (GPG_ERR_INTERNAL); |
223 | 0 | gcry_sexp_release (sexp); |
224 | 0 | return err; |
225 | 0 | } |
226 | | |
227 | | |
228 | | /* Compare two simple S-expressions like "(3:foo)". Returns 0 if they |
229 | | are identical or !0 if they are not. Note that this function can't |
230 | | be used for sorting. */ |
231 | | int |
232 | | cmp_simple_canon_sexp (const unsigned char *a_orig, |
233 | | const unsigned char *b_orig) |
234 | 0 | { |
235 | 0 | const char *a = (const char *)a_orig; |
236 | 0 | const char *b = (const char *)b_orig; |
237 | 0 | unsigned long n1, n2; |
238 | 0 | char *endp; |
239 | |
|
240 | 0 | if (!a && !b) |
241 | 0 | return 0; /* Both are NULL, they are identical. */ |
242 | 0 | if (!a || !b) |
243 | 0 | return 1; /* One is NULL, they are not identical. */ |
244 | 0 | if (*a != '(' || *b != '(') |
245 | 0 | log_bug ("invalid S-exp in cmp_simple_canon_sexp\n"); |
246 | | |
247 | 0 | a++; |
248 | 0 | n1 = strtoul (a, &endp, 10); |
249 | 0 | a = endp; |
250 | 0 | b++; |
251 | 0 | n2 = strtoul (b, &endp, 10); |
252 | 0 | b = endp; |
253 | |
|
254 | 0 | if (*a != ':' || *b != ':' ) |
255 | 0 | log_bug ("invalid S-exp in cmp_simple_canon_sexp\n"); |
256 | 0 | if (n1 != n2) |
257 | 0 | return 1; /* Not the same. */ |
258 | | |
259 | 0 | for (a++, b++; n1; n1--, a++, b++) |
260 | 0 | if (*a != *b) |
261 | 0 | return 1; /* Not the same. */ |
262 | 0 | return 0; |
263 | 0 | } |
264 | | |
265 | | |
266 | | |
267 | | /* Helper for cmp_canon_sexp. */ |
268 | | static int |
269 | | cmp_canon_sexp_def_tcmp (void *ctx, int depth, |
270 | | const unsigned char *aval, size_t alen, |
271 | | const unsigned char *bval, size_t blen) |
272 | 0 | { |
273 | 0 | (void)ctx; |
274 | 0 | (void)depth; |
275 | |
|
276 | 0 | if (alen > blen) |
277 | 0 | return 1; |
278 | 0 | else if (alen < blen) |
279 | 0 | return -1; |
280 | 0 | else |
281 | 0 | return memcmp (aval, bval, alen); |
282 | 0 | } |
283 | | |
284 | | |
285 | | /* Compare the two canonical encoded s-expressions A with maximum |
286 | | * length ALEN and B with maximum length BLEN. |
287 | | * |
288 | | * Returns 0 if they match. |
289 | | * |
290 | | * If TCMP is NULL, this is not different really different from a |
291 | | * memcmp but does not consider any garbage after the last closing |
292 | | * parentheses. |
293 | | * |
294 | | * If TCMP is not NULL, it is expected to be a function to compare the |
295 | | * values of each token. TCMP is called for each token while parsing |
296 | | * the s-expressions until TCMP return a non-zero value. Here the CTX |
297 | | * receives the provided value TCMPCTX, DEPTH is the number of |
298 | | * currently open parentheses and (AVAL,ALEN) and (BVAL,BLEN) the |
299 | | * values of the current token. TCMP needs to return zero to indicate |
300 | | * that the tokens match. */ |
301 | | int |
302 | | cmp_canon_sexp (const unsigned char *a, size_t alen, |
303 | | const unsigned char *b, size_t blen, |
304 | | int (*tcmp)(void *ctx, int depth, |
305 | | const unsigned char *aval, size_t avallen, |
306 | | const unsigned char *bval, size_t bvallen), |
307 | | void *tcmpctx) |
308 | 0 | { |
309 | 0 | const unsigned char *a_buf, *a_tok; |
310 | 0 | const unsigned char *b_buf, *b_tok; |
311 | 0 | size_t a_buflen, a_toklen; |
312 | 0 | size_t b_buflen, b_toklen; |
313 | 0 | int a_depth, b_depth, ret; |
314 | |
|
315 | 0 | if ((!a && !b) || (!alen && !blen)) |
316 | 0 | return 0; /* Both are NULL, they are identical. */ |
317 | 0 | if (!a || !b) |
318 | 0 | return !!a - !!b; /* One is NULL, they are not identical. */ |
319 | 0 | if (*a != '(' || *b != '(') |
320 | 0 | log_bug ("invalid S-exp in %s\n", __func__); |
321 | | |
322 | 0 | if (!tcmp) |
323 | 0 | tcmp = cmp_canon_sexp_def_tcmp; |
324 | |
|
325 | 0 | a_depth = 0; |
326 | 0 | a_buf = a; |
327 | 0 | a_buflen = alen; |
328 | 0 | b_depth = 0; |
329 | 0 | b_buf = b; |
330 | 0 | b_buflen = blen; |
331 | |
|
332 | 0 | for (;;) |
333 | 0 | { |
334 | 0 | if (parse_sexp (&a_buf, &a_buflen, &a_depth, &a_tok, &a_toklen)) |
335 | 0 | return -1; /* A is invalid. */ |
336 | 0 | if (parse_sexp (&b_buf, &b_buflen, &b_depth, &b_tok, &b_toklen)) |
337 | 0 | return -1; /* B is invalid. */ |
338 | 0 | if (!a_depth && !b_depth) |
339 | 0 | return 0; /* End of both expressions - they match. */ |
340 | 0 | if (a_depth != b_depth) |
341 | 0 | return a_depth - b_depth; /* Not the same structure */ |
342 | 0 | if (!a_tok && !b_tok) |
343 | 0 | ; /* parens */ |
344 | 0 | else if (a_tok && b_tok) |
345 | 0 | { |
346 | 0 | ret = tcmp (tcmpctx, a_depth, a_tok, a_toklen, b_tok, b_toklen); |
347 | 0 | if (ret) |
348 | 0 | return ret; /* Mismatch */ |
349 | 0 | } |
350 | 0 | else /* One has a paren other has not. */ |
351 | 0 | return !!a_tok - !!b_tok; |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | |
356 | | /* Create a simple S-expression from the hex string at LINE. Returns |
357 | | a newly allocated buffer with that canonical encoded S-expression |
358 | | or NULL in case of an error. On return the number of characters |
359 | | scanned in LINE will be stored at NSCANNED. This functions stops |
360 | | converting at the first character not representing a hexdigit. Odd |
361 | | numbers of hex digits are allowed; a leading zero is then |
362 | | assumed. If no characters have been found, NULL is returned.*/ |
363 | | unsigned char * |
364 | | make_simple_sexp_from_hexstr (const char *line, size_t *nscanned) |
365 | 0 | { |
366 | 0 | size_t n, len; |
367 | 0 | const char *s; |
368 | 0 | unsigned char *buf; |
369 | 0 | unsigned char *p; |
370 | 0 | char numbuf[50], *numbufp; |
371 | 0 | size_t numbuflen; |
372 | |
|
373 | 0 | for (n=0, s=line; hexdigitp (s); s++, n++) |
374 | 0 | ; |
375 | 0 | if (nscanned) |
376 | 0 | *nscanned = n; |
377 | 0 | if (!n) |
378 | 0 | return NULL; |
379 | 0 | len = ((n+1) & ~0x01)/2; |
380 | 0 | numbufp = smklen (numbuf, sizeof numbuf, len, &numbuflen); |
381 | 0 | buf = xtrymalloc (1 + numbuflen + len + 1 + 1); |
382 | 0 | if (!buf) |
383 | 0 | return NULL; |
384 | 0 | buf[0] = '('; |
385 | 0 | p = (unsigned char *)stpcpy ((char *)buf+1, numbufp); |
386 | 0 | s = line; |
387 | 0 | if ((n&1)) |
388 | 0 | { |
389 | 0 | *p++ = xtoi_1 (s); |
390 | 0 | s++; |
391 | 0 | n--; |
392 | 0 | } |
393 | 0 | for (; n > 1; n -=2, s += 2) |
394 | 0 | *p++ = xtoi_2 (s); |
395 | 0 | *p++ = ')'; |
396 | 0 | *p = 0; /* (Not really needed.) */ |
397 | |
|
398 | 0 | return buf; |
399 | 0 | } |
400 | | |
401 | | |
402 | | /* Return the hash algorithm from a KSBA sig-val. SIGVAL is a |
403 | | canonical encoded S-expression. Return 0 if the hash algorithm is |
404 | | not encoded in SIG-VAL or it is not supported by libgcrypt. */ |
405 | | int |
406 | | hash_algo_from_sigval (const unsigned char *sigval) |
407 | 0 | { |
408 | 0 | const unsigned char *s = sigval; |
409 | 0 | size_t n; |
410 | 0 | int depth; |
411 | 0 | char buffer[50]; |
412 | |
|
413 | 0 | if (!s || *s != '(') |
414 | 0 | return 0; /* Invalid S-expression. */ |
415 | 0 | s++; |
416 | 0 | n = snext (&s); |
417 | 0 | if (!n) |
418 | 0 | return 0; /* Invalid S-expression. */ |
419 | 0 | if (!smatch (&s, n, "sig-val")) |
420 | 0 | return 0; /* Not a sig-val. */ |
421 | 0 | if (*s != '(') |
422 | 0 | return 0; /* Invalid S-expression. */ |
423 | 0 | s++; |
424 | | /* Skip over the algo+parameter list. */ |
425 | 0 | depth = 1; |
426 | 0 | if (sskip (&s, &depth) || depth) |
427 | 0 | return 0; /* Invalid S-expression. */ |
428 | 0 | if (*s != '(') |
429 | 0 | return 0; /* No further list. */ |
430 | | /* Check whether this is (hash ALGO). */ |
431 | 0 | s++; |
432 | 0 | n = snext (&s); |
433 | 0 | if (!n) |
434 | 0 | return 0; /* Invalid S-expression. */ |
435 | 0 | if (!smatch (&s, n, "hash")) |
436 | 0 | return 0; /* Not a "hash" keyword. */ |
437 | 0 | n = snext (&s); |
438 | 0 | if (!n || n+1 >= sizeof (buffer)) |
439 | 0 | return 0; /* Algorithm string is missing or too long. */ |
440 | 0 | memcpy (buffer, s, n); |
441 | 0 | buffer[n] = 0; |
442 | |
|
443 | 0 | return gcry_md_map_name (buffer); |
444 | 0 | } |
445 | | |
446 | | |
447 | | /* Create a public key S-expression for an RSA public key from the |
448 | | modulus M with length MLEN and the public exponent E with length |
449 | | ELEN. Returns a newly allocated buffer of NULL in case of a memory |
450 | | allocation problem. If R_LEN is not NULL, the length of the |
451 | | canonical S-expression is stored there. */ |
452 | | unsigned char * |
453 | | make_canon_sexp_from_rsa_pk (const void *m_arg, size_t mlen, |
454 | | const void *e_arg, size_t elen, |
455 | | size_t *r_len) |
456 | 0 | { |
457 | 0 | const unsigned char *m = m_arg; |
458 | 0 | const unsigned char *e = e_arg; |
459 | 0 | int m_extra = 0; |
460 | 0 | int e_extra = 0; |
461 | 0 | char mlen_str[35]; |
462 | 0 | char elen_str[35]; |
463 | 0 | unsigned char *keybuf, *p; |
464 | 0 | const char part1[] = "(10:public-key(3:rsa(1:n"; |
465 | 0 | const char part2[] = ")(1:e"; |
466 | 0 | const char part3[] = ")))"; |
467 | | |
468 | | /* Remove leading zeroes. */ |
469 | 0 | for (; mlen && !*m; mlen--, m++) |
470 | 0 | ; |
471 | 0 | for (; elen && !*e; elen--, e++) |
472 | 0 | ; |
473 | | |
474 | | /* Insert a leading zero if the number would be zero or interpreted |
475 | | as negative. */ |
476 | 0 | if (!mlen || (m[0] & 0x80)) |
477 | 0 | m_extra = 1; |
478 | 0 | if (!elen || (e[0] & 0x80)) |
479 | 0 | e_extra = 1; |
480 | | |
481 | | /* Build the S-expression. */ |
482 | 0 | snprintf (mlen_str, sizeof mlen_str, "%u:", (unsigned int)mlen+m_extra); |
483 | 0 | snprintf (elen_str, sizeof elen_str, "%u:", (unsigned int)elen+e_extra); |
484 | |
|
485 | 0 | keybuf = xtrymalloc (strlen (part1) + strlen (mlen_str) + mlen + m_extra |
486 | 0 | + strlen (part2) + strlen (elen_str) + elen + e_extra |
487 | 0 | + strlen (part3) + 1); |
488 | 0 | if (!keybuf) |
489 | 0 | return NULL; |
490 | | |
491 | 0 | p = stpcpy (keybuf, part1); |
492 | 0 | p = stpcpy (p, mlen_str); |
493 | 0 | if (m_extra) |
494 | 0 | *p++ = 0; |
495 | 0 | memcpy (p, m, mlen); |
496 | 0 | p += mlen; |
497 | 0 | p = stpcpy (p, part2); |
498 | 0 | p = stpcpy (p, elen_str); |
499 | 0 | if (e_extra) |
500 | 0 | *p++ = 0; |
501 | 0 | memcpy (p, e, elen); |
502 | 0 | p += elen; |
503 | 0 | p = stpcpy (p, part3); |
504 | |
|
505 | 0 | if (r_len) |
506 | 0 | *r_len = p - keybuf; |
507 | |
|
508 | 0 | return keybuf; |
509 | 0 | } |
510 | | |
511 | | |
512 | | /* Return the parameters of a public RSA key expressed as an |
513 | | canonical encoded S-expression. */ |
514 | | gpg_error_t |
515 | | get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, |
516 | | unsigned char const **r_n, size_t *r_nlen, |
517 | | unsigned char const **r_e, size_t *r_elen) |
518 | 0 | { |
519 | 0 | gpg_error_t err; |
520 | 0 | const unsigned char *buf, *tok; |
521 | 0 | size_t buflen, toklen; |
522 | 0 | int depth, last_depth1, last_depth2; |
523 | 0 | const unsigned char *rsa_n = NULL; |
524 | 0 | const unsigned char *rsa_e = NULL; |
525 | 0 | size_t rsa_n_len, rsa_e_len; |
526 | |
|
527 | 0 | *r_n = NULL; |
528 | 0 | *r_nlen = 0; |
529 | 0 | *r_e = NULL; |
530 | 0 | *r_elen = 0; |
531 | |
|
532 | 0 | buf = keydata; |
533 | 0 | buflen = keydatalen; |
534 | 0 | depth = 0; |
535 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
536 | 0 | return err; |
537 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
538 | 0 | return err; |
539 | 0 | if (!tok || !((toklen == 10 && !memcmp ("public-key", tok, toklen)) |
540 | 0 | || (toklen == 11 && !memcmp ("private-key", tok, toklen)))) |
541 | 0 | return gpg_error (GPG_ERR_BAD_PUBKEY); |
542 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
543 | 0 | return err; |
544 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
545 | 0 | return err; |
546 | 0 | if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen)) |
547 | 0 | return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); |
548 | | |
549 | 0 | last_depth1 = depth; |
550 | 0 | while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) |
551 | 0 | && depth && depth >= last_depth1) |
552 | 0 | { |
553 | 0 | if (tok) |
554 | 0 | return gpg_error (GPG_ERR_UNKNOWN_SEXP); |
555 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
556 | 0 | return err; |
557 | 0 | if (tok && toklen == 1) |
558 | 0 | { |
559 | 0 | const unsigned char **mpi; |
560 | 0 | size_t *mpi_len; |
561 | |
|
562 | 0 | switch (*tok) |
563 | 0 | { |
564 | 0 | case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break; |
565 | 0 | case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break; |
566 | 0 | default: mpi = NULL; mpi_len = NULL; break; |
567 | 0 | } |
568 | 0 | if (mpi && *mpi) |
569 | 0 | return gpg_error (GPG_ERR_DUP_VALUE); |
570 | | |
571 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
572 | 0 | return err; |
573 | 0 | if (tok && mpi) |
574 | 0 | { |
575 | | /* Strip off leading zero bytes and save. */ |
576 | 0 | for (;toklen && !*tok; toklen--, tok++) |
577 | 0 | ; |
578 | 0 | *mpi = tok; |
579 | 0 | *mpi_len = toklen; |
580 | 0 | } |
581 | 0 | } |
582 | | |
583 | | /* Skip to the end of the list. */ |
584 | 0 | last_depth2 = depth; |
585 | 0 | while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) |
586 | 0 | && depth && depth >= last_depth2) |
587 | 0 | ; |
588 | 0 | if (err) |
589 | 0 | return err; |
590 | 0 | } |
591 | | |
592 | 0 | if (err) |
593 | 0 | return err; |
594 | | |
595 | 0 | if (!rsa_n || !rsa_n_len || !rsa_e || !rsa_e_len) |
596 | 0 | return gpg_error (GPG_ERR_BAD_PUBKEY); |
597 | | |
598 | 0 | *r_n = rsa_n; |
599 | 0 | *r_nlen = rsa_n_len; |
600 | 0 | *r_e = rsa_e; |
601 | 0 | *r_elen = rsa_e_len; |
602 | 0 | return 0; |
603 | 0 | } |
604 | | |
605 | | |
606 | | /* Return the public key parameter Q of a public RSA or ECC key |
607 | | * expressed as an canonical encoded S-expression. */ |
608 | | gpg_error_t |
609 | | get_ecc_q_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, |
610 | | unsigned char const **r_q, size_t *r_qlen) |
611 | 0 | { |
612 | 0 | gpg_error_t err; |
613 | 0 | const unsigned char *buf, *tok; |
614 | 0 | size_t buflen, toklen; |
615 | 0 | int depth, last_depth1, last_depth2; |
616 | 0 | const unsigned char *ecc_q = NULL; |
617 | 0 | size_t ecc_q_len = 0; |
618 | |
|
619 | 0 | *r_q = NULL; |
620 | 0 | *r_qlen = 0; |
621 | |
|
622 | 0 | buf = keydata; |
623 | 0 | buflen = keydatalen; |
624 | 0 | depth = 0; |
625 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
626 | 0 | return err; |
627 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
628 | 0 | return err; |
629 | 0 | if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen)) |
630 | 0 | return gpg_error (GPG_ERR_BAD_PUBKEY); |
631 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
632 | 0 | return err; |
633 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
634 | 0 | return err; |
635 | 0 | if (tok && toklen == 3 && !memcmp ("ecc", tok, toklen)) |
636 | 0 | ; |
637 | 0 | else if (tok && toklen == 5 && (!memcmp ("ecdsa", tok, toklen) |
638 | 0 | || !memcmp ("eddsa", tok, toklen))) |
639 | 0 | ; |
640 | 0 | else |
641 | 0 | return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); |
642 | | |
643 | 0 | last_depth1 = depth; |
644 | 0 | while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) |
645 | 0 | && depth && depth >= last_depth1) |
646 | 0 | { |
647 | 0 | if (tok) |
648 | 0 | return gpg_error (GPG_ERR_UNKNOWN_SEXP); |
649 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
650 | 0 | return err; |
651 | 0 | if (tok && toklen == 1) |
652 | 0 | { |
653 | 0 | const unsigned char **mpi; |
654 | 0 | size_t *mpi_len; |
655 | |
|
656 | 0 | switch (*tok) |
657 | 0 | { |
658 | 0 | case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break; |
659 | 0 | default: mpi = NULL; mpi_len = NULL; break; |
660 | 0 | } |
661 | 0 | if (mpi && *mpi) |
662 | 0 | return gpg_error (GPG_ERR_DUP_VALUE); |
663 | | |
664 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
665 | 0 | return err; |
666 | 0 | if (tok && mpi) |
667 | 0 | { |
668 | 0 | *mpi = tok; |
669 | 0 | *mpi_len = toklen; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | /* Skip to the end of the list. */ |
674 | 0 | last_depth2 = depth; |
675 | 0 | while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) |
676 | 0 | && depth && depth >= last_depth2) |
677 | 0 | ; |
678 | 0 | if (err) |
679 | 0 | return err; |
680 | 0 | } |
681 | | |
682 | 0 | if (err) |
683 | 0 | return err; |
684 | | |
685 | 0 | if (!ecc_q || !ecc_q_len) |
686 | 0 | return gpg_error (GPG_ERR_BAD_PUBKEY); |
687 | | |
688 | 0 | *r_q = ecc_q; |
689 | 0 | *r_qlen = ecc_q_len; |
690 | 0 | return 0; |
691 | 0 | } |
692 | | |
693 | | |
694 | | /* Return an uncompressed point (X,Y) in P at R_BUF as a malloced |
695 | | * buffer with its byte length stored at R_BUFLEN. May not be used |
696 | | * for sensitive data. */ |
697 | | static gpg_error_t |
698 | | ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p, |
699 | | unsigned char **r_buf, unsigned int *r_buflen) |
700 | 0 | { |
701 | 0 | gpg_error_t err; |
702 | 0 | int pbytes = (mpi_get_nbits (p)+7)/8; |
703 | 0 | size_t n; |
704 | 0 | unsigned char *buf, *ptr; |
705 | |
|
706 | 0 | *r_buf = NULL; |
707 | 0 | *r_buflen = 0; |
708 | |
|
709 | 0 | buf = xtrymalloc (1 + 2*pbytes); |
710 | 0 | if (!buf) |
711 | 0 | return gpg_error_from_syserror (); |
712 | 0 | *buf = 04; /* Uncompressed point. */ |
713 | 0 | ptr = buf+1; |
714 | 0 | err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x); |
715 | 0 | if (err) |
716 | 0 | { |
717 | 0 | xfree (buf); |
718 | 0 | return err; |
719 | 0 | } |
720 | 0 | if (n < pbytes) |
721 | 0 | { |
722 | 0 | memmove (ptr+(pbytes-n), ptr, n); |
723 | 0 | memset (ptr, 0, (pbytes-n)); |
724 | 0 | } |
725 | 0 | ptr += pbytes; |
726 | 0 | err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y); |
727 | 0 | if (err) |
728 | 0 | { |
729 | 0 | xfree (buf); |
730 | 0 | return err; |
731 | 0 | } |
732 | 0 | if (n < pbytes) |
733 | 0 | { |
734 | 0 | memmove (ptr+(pbytes-n), ptr, n); |
735 | 0 | memset (ptr, 0, (pbytes-n)); |
736 | 0 | } |
737 | |
|
738 | 0 | *r_buf = buf; |
739 | 0 | *r_buflen = 1 + 2*pbytes; |
740 | 0 | return 0; |
741 | 0 | } |
742 | | |
743 | | |
744 | | /* Convert the ECC parameter Q in the canonical s-expression |
745 | | * (KEYDATA,KEYDATALEN) to uncompressed form. On success and if a |
746 | | * conversion was done, the new canonical encoded s-expression is |
747 | | * returned at (R_NEWKEYDAT,R_NEWKEYDATALEN); if a conversion was not |
748 | | * required (NULL,0) is stored there. On error an error code is |
749 | | * returned. The function may take any kind of key but will only do |
750 | | * the conversion for ECC curves where compression is supported. */ |
751 | | gpg_error_t |
752 | | uncompress_ecc_q_in_canon_sexp (const unsigned char *keydata, |
753 | | size_t keydatalen, |
754 | | unsigned char **r_newkeydata, |
755 | | size_t *r_newkeydatalen) |
756 | 0 | { |
757 | 0 | gpg_error_t err; |
758 | 0 | const unsigned char *buf, *tok; |
759 | 0 | size_t buflen, toklen, n; |
760 | 0 | int depth, last_depth1, last_depth2; |
761 | 0 | const unsigned char *q_ptr; /* Points to the value of "q". */ |
762 | 0 | size_t q_ptrlen; /* Remaining length in KEYDATA. */ |
763 | 0 | size_t q_toklen; /* Q's length including prefix. */ |
764 | 0 | const unsigned char *curve_ptr; /* Points to the value of "curve". */ |
765 | 0 | size_t curve_ptrlen; /* Remaining length in KEYDATA. */ |
766 | 0 | gcry_mpi_t x, y; /* Point Q */ |
767 | 0 | gcry_mpi_t p, a, b; /* Curve parameters. */ |
768 | 0 | gcry_mpi_t x3, t, p1_4; /* Helper */ |
769 | 0 | int y_bit; |
770 | 0 | unsigned char *qvalue; /* Q in uncompressed form. */ |
771 | 0 | unsigned int qvaluelen; |
772 | 0 | unsigned char *dst; /* Helper */ |
773 | 0 | char lenstr[35]; /* Helper for a length prefix. */ |
774 | |
|
775 | 0 | *r_newkeydata = NULL; |
776 | 0 | *r_newkeydatalen = 0; |
777 | |
|
778 | 0 | buf = keydata; |
779 | 0 | buflen = keydatalen; |
780 | 0 | depth = 0; |
781 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
782 | 0 | return err; |
783 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
784 | 0 | return err; |
785 | 0 | if (!tok) |
786 | 0 | return gpg_error (GPG_ERR_BAD_PUBKEY); |
787 | 0 | else if (toklen == 10 && !memcmp ("public-key", tok, toklen)) |
788 | 0 | ; |
789 | 0 | else if (toklen == 11 && !memcmp ("private-key", tok, toklen)) |
790 | 0 | ; |
791 | 0 | else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen)) |
792 | 0 | ; |
793 | 0 | else |
794 | 0 | return gpg_error (GPG_ERR_BAD_PUBKEY); |
795 | | |
796 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
797 | 0 | return err; |
798 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
799 | 0 | return err; |
800 | | |
801 | 0 | if (tok && toklen == 3 && !memcmp ("ecc", tok, toklen)) |
802 | 0 | ; |
803 | 0 | else if (tok && toklen == 5 && !memcmp ("ecdsa", tok, toklen)) |
804 | 0 | ; |
805 | 0 | else |
806 | 0 | return 0; /* Other algo - no need for conversion. */ |
807 | | |
808 | 0 | last_depth1 = depth; |
809 | 0 | q_ptr = curve_ptr = NULL; |
810 | 0 | q_ptrlen = 0; /*(silence cc warning)*/ |
811 | 0 | while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) |
812 | 0 | && depth && depth >= last_depth1) |
813 | 0 | { |
814 | 0 | if (tok) |
815 | 0 | return gpg_error (GPG_ERR_UNKNOWN_SEXP); |
816 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
817 | 0 | return err; |
818 | 0 | if (tok && toklen == 1 && *tok == 'q' && !q_ptr) |
819 | 0 | { |
820 | 0 | q_ptr = buf; |
821 | 0 | q_ptrlen = buflen; |
822 | 0 | } |
823 | 0 | else if (tok && toklen == 5 && !memcmp (tok, "curve", 5) && !curve_ptr) |
824 | 0 | { |
825 | 0 | curve_ptr = buf; |
826 | 0 | curve_ptrlen = buflen; |
827 | 0 | } |
828 | |
|
829 | 0 | if (q_ptr && curve_ptr) |
830 | 0 | break; /* We got all what we need. */ |
831 | | |
832 | | /* Skip to the end of the list. */ |
833 | 0 | last_depth2 = depth; |
834 | 0 | while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) |
835 | 0 | && depth && depth >= last_depth2) |
836 | 0 | ; |
837 | 0 | if (err) |
838 | 0 | return err; |
839 | 0 | } |
840 | 0 | if (err) |
841 | 0 | return err; |
842 | | |
843 | 0 | if (!q_ptr) |
844 | 0 | return 0; /* No Q - nothing to do. */ |
845 | | |
846 | | /* Get Q's value and check whether uncompressing is at all required. */ |
847 | 0 | buf = q_ptr; |
848 | 0 | buflen = q_ptrlen; |
849 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
850 | 0 | return err; |
851 | 0 | if (toklen < 2 || !(*tok == 0x02 || *tok == 0x03)) |
852 | 0 | return 0; /* Invalid length or not compressed. */ |
853 | 0 | q_toklen = buf - q_ptr; /* We want the length with the prefix. */ |
854 | | |
855 | | /* Put the x-coordinate of q into X and remember the y bit */ |
856 | 0 | y_bit = (*tok == 0x03); |
857 | 0 | err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, tok+1, toklen-1, NULL); |
858 | 0 | if (err) |
859 | 0 | return err; |
860 | | |
861 | | /* For uncompressing we need to know the curve. */ |
862 | 0 | if (!curve_ptr) |
863 | 0 | { |
864 | 0 | gcry_mpi_release (x); |
865 | 0 | return gpg_error (GPG_ERR_INV_CURVE); |
866 | 0 | } |
867 | 0 | buf = curve_ptr; |
868 | 0 | buflen = curve_ptrlen; |
869 | 0 | if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) |
870 | 0 | { |
871 | 0 | gcry_mpi_release (x); |
872 | 0 | return err; |
873 | 0 | } |
874 | | |
875 | 0 | { |
876 | 0 | char name[50]; |
877 | 0 | gcry_sexp_t curveparam; |
878 | |
|
879 | 0 | if (toklen + 1 > sizeof name) |
880 | 0 | { |
881 | 0 | gcry_mpi_release (x); |
882 | 0 | return gpg_error (GPG_ERR_TOO_LARGE); |
883 | 0 | } |
884 | 0 | mem2str (name, tok, toklen+1); |
885 | 0 | curveparam = gcry_pk_get_param (GCRY_PK_ECC, name); |
886 | 0 | if (!curveparam) |
887 | 0 | { |
888 | 0 | gcry_mpi_release (x); |
889 | 0 | return gpg_error (GPG_ERR_UNKNOWN_CURVE); |
890 | 0 | } |
891 | | |
892 | 0 | err = gcry_sexp_extract_param (curveparam, NULL, "pab", &p, &a, &b, NULL); |
893 | 0 | gcry_sexp_release (curveparam); |
894 | 0 | if (err) |
895 | 0 | { |
896 | 0 | gcry_mpi_release (x); |
897 | 0 | return gpg_error (GPG_ERR_INTERNAL); |
898 | 0 | } |
899 | 0 | } |
900 | | |
901 | 0 | if (!mpi_test_bit (p, 1)) |
902 | 0 | { |
903 | | /* No support for point compression for this curve. */ |
904 | 0 | gcry_mpi_release (x); |
905 | 0 | gcry_mpi_release (p); |
906 | 0 | gcry_mpi_release (a); |
907 | 0 | gcry_mpi_release (b); |
908 | 0 | return gpg_error (GPG_ERR_NOT_IMPLEMENTED); |
909 | 0 | } |
910 | | |
911 | | /* |
912 | | * Recover Y. The Weierstrass curve: y^2 = x^3 + a*x + b |
913 | | */ |
914 | | |
915 | 0 | x3 = mpi_new (0); |
916 | 0 | t = mpi_new (0); |
917 | 0 | p1_4 = mpi_new (0); |
918 | 0 | y = mpi_new (0); |
919 | | |
920 | | /* Compute right hand side. */ |
921 | 0 | mpi_powm (x3, x, GCRYMPI_CONST_THREE, p); |
922 | 0 | mpi_mul (t, a, x); |
923 | 0 | mpi_mod (t, t, p); |
924 | 0 | mpi_add (t, t, b); |
925 | 0 | mpi_mod (t, t, p); |
926 | 0 | mpi_add (t, t, x3); |
927 | 0 | mpi_mod (t, t, p); |
928 | | |
929 | | /* |
930 | | * When p mod 4 = 3, modular square root of A can be computed by |
931 | | * A^((p+1)/4) mod p |
932 | | */ |
933 | | |
934 | | /* Compute (p+1)/4 into p1_4 */ |
935 | 0 | mpi_rshift (p1_4, p, 2); |
936 | 0 | mpi_add_ui (p1_4, p1_4, 1); |
937 | |
|
938 | 0 | mpi_powm (y, t, p1_4, p); |
939 | |
|
940 | 0 | if (y_bit != mpi_test_bit (y, 0)) |
941 | 0 | mpi_sub (y, p, y); |
942 | |
|
943 | 0 | gcry_mpi_release (p1_4); |
944 | 0 | gcry_mpi_release (t); |
945 | 0 | gcry_mpi_release (x3); |
946 | 0 | gcry_mpi_release (a); |
947 | 0 | gcry_mpi_release (b); |
948 | |
|
949 | 0 | err = ec2os (x, y, p, &qvalue, &qvaluelen); |
950 | 0 | gcry_mpi_release (x); |
951 | 0 | gcry_mpi_release (y); |
952 | 0 | gcry_mpi_release (p); |
953 | 0 | if (err) |
954 | 0 | return err; |
955 | | |
956 | 0 | snprintf (lenstr, sizeof lenstr, "%u:", (unsigned int)qvaluelen); |
957 | | /* Note that for simplicity we do not subtract the old length of Q |
958 | | * for the new buffer. */ |
959 | 0 | *r_newkeydata = xtrymalloc (qvaluelen + strlen(lenstr) + qvaluelen); |
960 | 0 | if (!*r_newkeydata) |
961 | 0 | return gpg_error_from_syserror (); |
962 | 0 | dst = *r_newkeydata; |
963 | |
|
964 | 0 | n = q_ptr - keydata; |
965 | 0 | memcpy (dst, keydata, n); /* Copy first part of original data. */ |
966 | 0 | dst += n; |
967 | |
|
968 | 0 | n = strlen (lenstr); |
969 | 0 | memcpy (dst, lenstr, n); /* Copy new prefix of Q's value. */ |
970 | 0 | dst += n; |
971 | |
|
972 | 0 | memcpy (dst, qvalue, qvaluelen); /* Copy new value of Q. */ |
973 | 0 | dst += qvaluelen; |
974 | |
|
975 | 0 | log_assert (q_toklen < q_ptrlen); |
976 | 0 | n = q_ptrlen - q_toklen; |
977 | 0 | memcpy (dst, q_ptr + q_toklen, n);/* Copy rest of original data. */ |
978 | 0 | dst += n; |
979 | |
|
980 | 0 | *r_newkeydatalen = dst - *r_newkeydata; |
981 | |
|
982 | 0 | xfree (qvalue); |
983 | |
|
984 | 0 | return 0; |
985 | 0 | } |
986 | | |
987 | | |
988 | | /* Return the algo of a public KEY of SEXP. */ |
989 | | int |
990 | | get_pk_algo_from_key (gcry_sexp_t key) |
991 | 0 | { |
992 | 0 | gcry_sexp_t list; |
993 | 0 | const char *s; |
994 | 0 | size_t n; |
995 | 0 | char algoname[10]; |
996 | 0 | int algo = 0; |
997 | |
|
998 | 0 | list = gcry_sexp_nth (key, 1); |
999 | 0 | if (!list) |
1000 | 0 | goto out; |
1001 | 0 | s = gcry_sexp_nth_data (list, 0, &n); |
1002 | 0 | if (!s) |
1003 | 0 | goto out; |
1004 | 0 | if (n >= sizeof (algoname)) |
1005 | 0 | goto out; |
1006 | 0 | memcpy (algoname, s, n); |
1007 | 0 | algoname[n] = 0; |
1008 | |
|
1009 | 0 | algo = gcry_pk_map_name (algoname); |
1010 | 0 | if (algo == GCRY_PK_ECC) |
1011 | 0 | { |
1012 | 0 | gcry_sexp_t l1; |
1013 | 0 | int i; |
1014 | |
|
1015 | 0 | l1 = gcry_sexp_find_token (list, "flags", 0); |
1016 | 0 | for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--) |
1017 | 0 | { |
1018 | 0 | s = gcry_sexp_nth_data (l1, i, &n); |
1019 | 0 | if (!s) |
1020 | 0 | continue; /* Not a data element. */ |
1021 | | |
1022 | 0 | if (n == 5 && !memcmp (s, "eddsa", 5)) |
1023 | 0 | { |
1024 | 0 | algo = GCRY_PK_EDDSA; |
1025 | 0 | break; |
1026 | 0 | } |
1027 | 0 | } |
1028 | 0 | gcry_sexp_release (l1); |
1029 | |
|
1030 | 0 | l1 = gcry_sexp_find_token (list, "curve", 0); |
1031 | 0 | s = gcry_sexp_nth_data (l1, 1, &n); |
1032 | 0 | if (n == 5 && !memcmp (s, "Ed448", 5)) |
1033 | 0 | algo = GCRY_PK_EDDSA; |
1034 | 0 | gcry_sexp_release (l1); |
1035 | 0 | } |
1036 | |
|
1037 | 0 | out: |
1038 | 0 | gcry_sexp_release (list); |
1039 | |
|
1040 | 0 | return algo; |
1041 | 0 | } |
1042 | | |
1043 | | |
1044 | | /* This is a variant of get_pk_algo_from_key but takes an canonical |
1045 | | * encoded S-expression as input. Returns a GCRYPT public key |
1046 | | * identiier or 0 on error. */ |
1047 | | int |
1048 | | get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen) |
1049 | 0 | { |
1050 | 0 | gcry_sexp_t sexp; |
1051 | 0 | int algo; |
1052 | |
|
1053 | 0 | if (gcry_sexp_sscan (&sexp, NULL, keydata, keydatalen)) |
1054 | 0 | return 0; |
1055 | | |
1056 | 0 | algo = get_pk_algo_from_key (sexp); |
1057 | 0 | gcry_sexp_release (sexp); |
1058 | 0 | return algo; |
1059 | 0 | } |
1060 | | |
1061 | | |
1062 | | /* Given the public key S_PKEY, return a new buffer with a descriptive |
1063 | | * string for its algorithm. This function may return NULL on memory |
1064 | | * error. If R_ALGOID is not NULL the gcrypt algo id is stored there. */ |
1065 | | char * |
1066 | | pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid) |
1067 | 0 | { |
1068 | 0 | const char *prefix; |
1069 | 0 | gcry_sexp_t l1; |
1070 | 0 | char *algoname; |
1071 | 0 | int algo; |
1072 | 0 | char *result; |
1073 | |
|
1074 | 0 | if (r_algoid) |
1075 | 0 | *r_algoid = 0; |
1076 | |
|
1077 | 0 | l1 = gcry_sexp_find_token (s_pkey, "public-key", 0); |
1078 | 0 | if (!l1) |
1079 | 0 | l1 = gcry_sexp_find_token (s_pkey, "private-key", 0); |
1080 | 0 | if (!l1) |
1081 | 0 | return xtrystrdup ("E_no_key"); |
1082 | 0 | { |
1083 | 0 | gcry_sexp_t l_tmp = gcry_sexp_cadr (l1); |
1084 | 0 | gcry_sexp_release (l1); |
1085 | 0 | l1 = l_tmp; |
1086 | 0 | } |
1087 | 0 | algoname = gcry_sexp_nth_string (l1, 0); |
1088 | 0 | gcry_sexp_release (l1); |
1089 | 0 | if (!algoname) |
1090 | 0 | return xtrystrdup ("E_no_algo"); |
1091 | | |
1092 | 0 | algo = gcry_pk_map_name (algoname); |
1093 | 0 | switch (algo) |
1094 | 0 | { |
1095 | 0 | case GCRY_PK_RSA: prefix = "rsa"; break; |
1096 | 0 | case GCRY_PK_ELG: prefix = "elg"; break; |
1097 | 0 | case GCRY_PK_DSA: prefix = "dsa"; break; |
1098 | 0 | case GCRY_PK_ECC: prefix = ""; break; |
1099 | 0 | default: prefix = NULL; break; |
1100 | 0 | } |
1101 | | |
1102 | 0 | if (prefix && *prefix) |
1103 | 0 | result = xtryasprintf ("%s%u", prefix, gcry_pk_get_nbits (s_pkey)); |
1104 | 0 | else if (prefix) |
1105 | 0 | { |
1106 | 0 | const char *curve = gcry_pk_get_curve (s_pkey, 0, NULL); |
1107 | 0 | const char *name = openpgp_oid_or_name_to_curve (curve, 0); |
1108 | |
|
1109 | 0 | if (name) |
1110 | 0 | result = xtrystrdup (name); |
1111 | 0 | else if (curve) |
1112 | 0 | result = xtryasprintf ("X_%s", curve); |
1113 | 0 | else |
1114 | 0 | result = xtrystrdup ("E_unknown"); |
1115 | 0 | } |
1116 | 0 | else |
1117 | 0 | result = xtryasprintf ("X_algo_%d", algo); |
1118 | |
|
1119 | 0 | if (r_algoid) |
1120 | 0 | *r_algoid = algo; |
1121 | 0 | xfree (algoname); |
1122 | 0 | return result; |
1123 | 0 | } |
1124 | | |
1125 | | |
1126 | | /* Map a pubkey algo id from gcrypt to a string. This is the same as |
1127 | | * gcry_pk_algo_name but makes sure that the ECC algo identifiers are |
1128 | | * not all mapped to "ECC". */ |
1129 | | const char * |
1130 | | pubkey_algo_to_string (int algo) |
1131 | 0 | { |
1132 | 0 | if (algo == GCRY_PK_ECDSA) |
1133 | 0 | return "ECDSA"; |
1134 | 0 | else if (algo == GCRY_PK_ECDH) |
1135 | 0 | return "ECDH"; |
1136 | 0 | else if (algo == GCRY_PK_EDDSA) |
1137 | 0 | return "EdDSA"; |
1138 | 0 | else |
1139 | 0 | return gcry_pk_algo_name (algo); |
1140 | 0 | } |
1141 | | |
1142 | | |
1143 | | /* Map a hash algo id from gcrypt to a string. This is the same as |
1144 | | * gcry_md_algo_name but the returned string is lower case, as |
1145 | | * expected by libksba and it avoids some overhead. */ |
1146 | | const char * |
1147 | | hash_algo_to_string (int algo) |
1148 | 0 | { |
1149 | 0 | static const struct |
1150 | 0 | { |
1151 | 0 | const char *name; |
1152 | 0 | int algo; |
1153 | 0 | } hashnames[] = |
1154 | 0 | { |
1155 | 0 | { "sha256", GCRY_MD_SHA256 }, |
1156 | 0 | { "sha512", GCRY_MD_SHA512 }, |
1157 | 0 | { "sha1", GCRY_MD_SHA1 }, |
1158 | 0 | { "sha384", GCRY_MD_SHA384 }, |
1159 | 0 | { "sha224", GCRY_MD_SHA224 }, |
1160 | 0 | { "sha3-224", GCRY_MD_SHA3_224 }, |
1161 | 0 | { "sha3-256", GCRY_MD_SHA3_256 }, |
1162 | 0 | { "sha3-384", GCRY_MD_SHA3_384 }, |
1163 | 0 | { "sha3-512", GCRY_MD_SHA3_512 }, |
1164 | 0 | { "ripemd160", GCRY_MD_RMD160 }, |
1165 | 0 | { "rmd160", GCRY_MD_RMD160 }, |
1166 | 0 | { "md2", GCRY_MD_MD2 }, |
1167 | 0 | { "md4", GCRY_MD_MD4 }, |
1168 | 0 | { "tiger", GCRY_MD_TIGER }, |
1169 | 0 | { "haval", GCRY_MD_HAVAL }, |
1170 | 0 | { "sm3", GCRY_MD_SM3 }, |
1171 | 0 | { "md5", GCRY_MD_MD5 } |
1172 | 0 | }; |
1173 | 0 | int i; |
1174 | |
|
1175 | 0 | for (i=0; i < DIM (hashnames); i++) |
1176 | 0 | if (algo == hashnames[i].algo) |
1177 | 0 | return hashnames[i].name; |
1178 | 0 | return "?"; |
1179 | 0 | } |
1180 | | |
1181 | | |
1182 | | /* Map cipher modes to a string. */ |
1183 | | const char * |
1184 | | cipher_mode_to_string (int mode) |
1185 | 0 | { |
1186 | 0 | switch (mode) |
1187 | 0 | { |
1188 | 0 | case GCRY_CIPHER_MODE_CFB: return "CFB"; |
1189 | 0 | case GCRY_CIPHER_MODE_CBC: return "CBC"; |
1190 | 0 | case GCRY_CIPHER_MODE_GCM: return "GCM"; |
1191 | 0 | case GCRY_CIPHER_MODE_OCB: return "OCB"; |
1192 | 0 | case 14: return "EAX"; /* Only in gcrypt 1.9 */ |
1193 | 0 | default: return "[?]"; |
1194 | 0 | } |
1195 | 0 | } |
1196 | | |
1197 | | /* Return the canonical name of the ECC curve in KEY. */ |
1198 | | const char * |
1199 | | get_ecc_curve_from_key (gcry_sexp_t key) |
1200 | 0 | { |
1201 | 0 | gcry_sexp_t list = NULL; |
1202 | 0 | gcry_sexp_t l2 = NULL; |
1203 | 0 | const char *curve_name = NULL; |
1204 | 0 | char *name = NULL; |
1205 | | |
1206 | | /* Check that the first element is valid. */ |
1207 | 0 | list = gcry_sexp_find_token (key, "public-key", 0); |
1208 | 0 | if (!list) |
1209 | 0 | list = gcry_sexp_find_token (key, "private-key", 0); |
1210 | 0 | if (!list) |
1211 | 0 | list = gcry_sexp_find_token (key, "protected-private-key", 0); |
1212 | 0 | if (!list) |
1213 | 0 | list = gcry_sexp_find_token (key, "shadowed-private-key", 0); |
1214 | 0 | if (!list) |
1215 | 0 | goto leave; |
1216 | | |
1217 | 0 | l2 = gcry_sexp_cadr (list); |
1218 | 0 | gcry_sexp_release (list); |
1219 | 0 | list = l2; |
1220 | 0 | l2 = NULL; |
1221 | |
|
1222 | 0 | name = gcry_sexp_nth_string (list, 0); |
1223 | 0 | if (!name) |
1224 | 0 | goto leave; |
1225 | | |
1226 | 0 | if (gcry_pk_map_name (name) != GCRY_PK_ECC) |
1227 | 0 | goto leave; |
1228 | | |
1229 | 0 | l2 = gcry_sexp_find_token (list, "curve", 0); |
1230 | 0 | xfree (name); |
1231 | 0 | name = gcry_sexp_nth_string (l2, 1); |
1232 | 0 | curve_name = openpgp_oid_or_name_to_curve (name, 1); |
1233 | 0 | gcry_sexp_release (l2); |
1234 | |
|
1235 | 0 | leave: |
1236 | 0 | xfree (name); |
1237 | 0 | gcry_sexp_release (list); |
1238 | 0 | return curve_name; |
1239 | 0 | } |