1 /* sexputil.c - Utility functions for S-expressions.
2 * Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 /* This file implements a few utility functions useful when working
21 with canonical encrypted S-expresions (i.e. not the S-exprssion
22 objects from libgcrypt). */
36 #include "sexp-parse.h"
39 /* Helper function to create a a canonical encoded S-expression from a
40 Libgcrypt S-expression object. The function returns 0 on success
41 and the malloced canonical S-expression is stored at R_BUFFER and
42 the allocated length at R_BUFLEN. On error an error code is
43 returned and (NULL, 0) stored at R_BUFFER and R_BUFLEN. If the
44 allocated buffer length is not required, NULL by be used for
47 make_canon_sexp (gcry_sexp_t sexp
, unsigned char **r_buffer
, size_t *r_buflen
)
56 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_CANON
, NULL
, 0);
58 return gpg_error (GPG_ERR_BUG
);
59 buf
= xtrymalloc (len
);
61 return gpg_error_from_syserror ();
62 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_CANON
, buf
, len
);
64 return gpg_error (GPG_ERR_BUG
);
74 /* Return the so called "keygrip" which is the SHA-1 hash of the
75 public key parameters expressed in a way depended on the algorithm.
77 KEY is expected to be an canonical encoded S-expression with a
78 public or private key. KEYLEN is the length of that buffer.
80 GRIP must be at least 20 bytes long. On success 0 is returned, on
81 error an error code. */
83 keygrip_from_canon_sexp (const unsigned char *key
, size_t keylen
,
90 return gpg_error (GPG_ERR_INV_VALUE
);
91 err
= gcry_sexp_sscan (&sexp
, NULL
, (const char *)key
, keylen
);
94 if (!gcry_pk_get_keygrip (sexp
, grip
))
95 err
= gpg_error (GPG_ERR_INTERNAL
);
96 gcry_sexp_release (sexp
);
101 /* Compare two simple S-expressions like "(3:foo)". Returns 0 if they
102 are identical or !0 if they are not. Not that this function can't
103 be used for sorting. */
105 cmp_simple_canon_sexp (const unsigned char *a_orig
,
106 const unsigned char *b_orig
)
108 const char *a
= (const char *)a_orig
;
109 const char *b
= (const char *)b_orig
;
110 unsigned long n1
, n2
;
114 return 0; /* Both are NULL, they are identical. */
116 return 1; /* One is NULL, they are not identical. */
117 if (*a
!= '(' || *b
!= '(')
118 log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
121 n1
= strtoul (a
, &endp
, 10);
124 n2
= strtoul (b
, &endp
, 10);
127 if (*a
!= ':' || *b
!= ':' )
128 log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
130 return 1; /* Not the same. */
132 for (a
++, b
++; n1
; n1
--, a
++, b
++)
134 return 1; /* Not the same. */
139 /* Create a simple S-expression from the hex string at LIBNE. Returns
140 a newly allocated buffer with that canonical encoded S-expression
141 or NULL in case of an error. On return the number of characters
142 scanned in LINE will be stored at NSCANNED. This fucntions stops
143 converting at the first character not representing a hexdigit. Odd
144 numbers of hex digits are allowed; a leading zero is then
145 assumed. If no characters have been found, NULL is returned.*/
147 make_simple_sexp_from_hexstr (const char *line
, size_t *nscanned
)
153 char numbuf
[50], *numbufp
;
156 for (n
=0, s
=line
; hexdigitp (s
); s
++, n
++)
162 len
= ((n
+1) & ~0x01)/2;
163 numbufp
= smklen (numbuf
, sizeof numbuf
, len
, &numbuflen
);
164 buf
= xtrymalloc (1 + numbuflen
+ len
+ 1 + 1);
168 p
= (unsigned char *)stpcpy ((char *)buf
+1, numbufp
);
176 for (; n
> 1; n
-=2, s
+= 2)
179 *p
= 0; /* (Not really neaded.) */
185 /* Return the hash algorithm from a KSBA sig-val. SIGVAL is a
186 canonical encoded S-expression. Return 0 if the hash algorithm is
187 not encoded in SIG-VAL or it is not supported by libgcrypt. */
189 hash_algo_from_sigval (const unsigned char *sigval
)
191 const unsigned char *s
= sigval
;
197 return 0; /* Invalid S-expression. */
201 return 0; /* Invalid S-expression. */
202 if (!smatch (&s
, n
, "sig-val"))
203 return 0; /* Not a sig-val. */
205 return 0; /* Invalid S-expression. */
207 /* Skip over the algo+parameter list. */
209 if (sskip (&s
, &depth
) || depth
)
210 return 0; /* Invalid S-expression. */
212 return 0; /* No futher list. */
213 /* Check whether this is (hash ALGO). */
217 return 0; /* Invalid S-expression. */
218 if (!smatch (&s
, n
, "hash"))
219 return 0; /* Not a "hash" keyword. */
221 if (!n
|| n
+1 >= sizeof (buffer
))
222 return 0; /* Algorithm string is missing or too long. */
223 memcpy (buffer
, s
, n
);
226 return gcry_md_map_name (buffer
);
230 /* Create a public key S-expression for an RSA public key from the
231 modulus M with length MLEN and the public exponent E with length
232 ELEN. Returns a newly allocated buffer of NULL in case of a memory
233 allocation problem. If R_LEN is not NULL, the length of the
234 canonical S-expression is stored there. */
236 make_canon_sexp_from_rsa_pk (const void *m_arg
, size_t mlen
,
237 const void *e_arg
, size_t elen
,
240 const unsigned char *m
= m_arg
;
241 const unsigned char *e
= e_arg
;
246 unsigned char *keybuf
, *p
;
247 const char const part1
[] = "(10:public-key(3:rsa(1:n";
248 const char const part2
[] = ")(1:e";
249 const char const part3
[] = ")))";
251 /* Remove leading zeroes. */
252 for (; mlen
&& !*m
; mlen
--, m
++)
254 for (; elen
&& !*e
; elen
--, e
++)
257 /* Insert a leading zero if the number would be zero or interpreted
259 if (!mlen
|| (m
[0] & 0x80))
261 if (!elen
|| (e
[0] & 0x80))
264 /* Build the S-expression. */
265 snprintf (mlen_str
, sizeof mlen_str
, "%u:", (unsigned int)mlen
+m_extra
);
266 snprintf (elen_str
, sizeof elen_str
, "%u:", (unsigned int)elen
+e_extra
);
268 keybuf
= xtrymalloc (strlen (part1
) + strlen (mlen_str
) + mlen
+ m_extra
269 + strlen (part2
) + strlen (elen_str
) + elen
+ e_extra
270 + strlen (part3
) + 1);
274 p
= stpcpy (keybuf
, part1
);
275 p
= stpcpy (p
, mlen_str
);
280 p
= stpcpy (p
, part2
);
281 p
= stpcpy (p
, elen_str
);
286 p
= stpcpy (p
, part3
);
295 /* Return the so called "keygrip" which is the SHA-1 hash of the
296 public key parameters expressed in a way depended on the algorithm.
298 KEY is expected to be an canonical encoded S-expression with a
299 public or private key. KEYLEN is the length of that buffer.
301 GRIP must be at least 20 bytes long. On success 0 is returned, on
302 error an error code. */
304 get_rsa_pk_from_canon_sexp (const unsigned char *keydata
, size_t keydatalen
,
305 unsigned char const **r_n
, size_t *r_nlen
,
306 unsigned char const **r_e
, size_t *r_elen
)
309 const unsigned char *buf
, *tok
;
310 size_t buflen
, toklen
;
311 int depth
, last_depth1
, last_depth2
;
312 const unsigned char *rsa_n
= NULL
;
313 const unsigned char *rsa_e
= NULL
;
314 size_t rsa_n_len
, rsa_e_len
;
324 if ((err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
)))
326 if ((err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
)))
328 if (!tok
|| toklen
!= 10 || memcmp ("public-key", tok
, toklen
))
329 return gpg_error (GPG_ERR_BAD_PUBKEY
);
330 if ((err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
)))
332 if ((err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
)))
334 if (!tok
|| toklen
!= 3 || memcmp ("rsa", tok
, toklen
))
335 return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO
);
338 while (!(err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
))
339 && depth
&& depth
>= last_depth1
)
342 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
343 if ((err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
)))
345 if (tok
&& toklen
== 1)
347 const unsigned char **mpi
;
352 case 'n': mpi
= &rsa_n
; mpi_len
= &rsa_n_len
; break;
353 case 'e': mpi
= &rsa_e
; mpi_len
= &rsa_e_len
; break;
354 default: mpi
= NULL
; mpi_len
= NULL
; break;
357 return gpg_error (GPG_ERR_DUP_VALUE
);
359 if ((err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
)))
363 /* Strip off leading zero bytes and save. */
364 for (;toklen
&& !*tok
; toklen
--, tok
++)
371 /* Skip to the end of the list. */
373 while (!(err
= parse_sexp (&buf
, &buflen
, &depth
, &tok
, &toklen
))
374 && depth
&& depth
>= last_depth2
)
380 if (!rsa_n
|| !rsa_n_len
|| !rsa_e
|| !rsa_e_len
)
381 return gpg_error (GPG_ERR_BAD_PUBKEY
);