New gpg-agent command to list key information.
[gnupg.git] / common / sexputil.c
1 /* sexputil.c - Utility functions for S-expressions.
2  * Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
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).  */
23
24 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #ifdef HAVE_LOCALE_H
31 #include <locale.h>
32 #endif
33
34 #include "util.h"
35 #include "sexp-parse.h"
36
37
38 /* Helper function to create a a canonical encoded S-expression from a
39    Libgcrypt S-expression object.  The function returns 0 on success
40    and the malloced canonical S-expression is stored at R_BUFFER and
41    the allocated length at R_BUFLEN.  On error an error code is
42    returned and (NULL, 0) stored at R_BUFFER and R_BUFLEN.  If the
43    allocated buffer length is not required, NULL by be used for
44    R_BUFLEN.  */
45 gpg_error_t
46 make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen)
47 {
48   size_t len;
49   unsigned char *buf;
50
51   *r_buffer = NULL;
52   if (r_buflen)
53     *r_buflen = 0;;
54   
55   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
56   if (!len)
57     return gpg_error (GPG_ERR_BUG);
58   buf = xtrymalloc (len);
59   if (!buf)
60     return gpg_error_from_syserror ();
61   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len);
62   if (!len)
63     return gpg_error (GPG_ERR_BUG);
64
65   *r_buffer = buf;
66   if (r_buflen)
67     *r_buflen = len;
68
69   return 0;
70 }
71
72
73 /* Return the so called "keygrip" which is the SHA-1 hash of the
74    public key parameters expressed in a way depended on the algorithm.
75
76    KEY is expected to be an canonical encoded S-expression with a
77    public or private key. KEYLEN is the length of that buffer.
78
79    GRIP must be at least 20 bytes long.  On success 0 is returned, on
80    error an error code. */
81 gpg_error_t
82 keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
83                          unsigned char *grip)
84 {
85   gpg_error_t err;
86   gcry_sexp_t sexp;
87
88   if (!grip)
89     return gpg_error (GPG_ERR_INV_VALUE);
90   err = gcry_sexp_sscan (&sexp, NULL, (const char *)key, keylen);
91   if (err)
92     return err;
93   if (!gcry_pk_get_keygrip (sexp, grip))
94     err = gpg_error (GPG_ERR_INTERNAL);
95   gcry_sexp_release (sexp);
96   return err;
97 }
98
99
100 /* Compare two simple S-expressions like "(3:foo)".  Returns 0 if they
101    are identical or !0 if they are not.  Not that this function can't
102    be used for sorting. */
103 int
104 cmp_simple_canon_sexp (const unsigned char *a_orig,
105                        const unsigned char *b_orig)
106 {
107   const char *a = (const char *)a_orig;
108   const char *b = (const char *)b_orig;
109   unsigned long n1, n2;
110   char *endp;
111
112   if (!a && !b)
113     return 0; /* Both are NULL, they are identical. */
114   if (!a || !b)
115     return 1; /* One is NULL, they are not identical. */
116   if (*a != '(' || *b != '(')
117     log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
118
119   a++;
120   n1 = strtoul (a, &endp, 10);
121   a = endp;
122   b++;
123   n2 = strtoul (b, &endp, 10);
124   b = endp;
125
126   if (*a != ':' || *b != ':' )
127     log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
128   if (n1 != n2)
129     return 1; /* Not the same. */
130
131   for (a++, b++; n1; n1--, a++, b++)
132     if (*a != *b)
133       return 1; /* Not the same. */
134   return 0;
135 }
136
137
138 /* Create a simple S-expression from the hex string at LIBNE.  Returns
139    a newly allocated buffer with that canonical encoded S-expression
140    or NULL in case of an error.  On return the number of characters
141    scanned in LINE will be stored at NSCANNED.  This fucntions stops
142    converting at the first character not representing a hexdigit. Odd
143    numbers of hex digits are allowed; a leading zero is then
144    assumed. If no characters have been found, NULL is returned.*/
145 unsigned char *
146 make_simple_sexp_from_hexstr (const char *line, size_t *nscanned)
147 {
148   size_t n, len;
149   const char *s;
150   unsigned char *buf;
151   unsigned char *p;
152   char numbuf[50], *numbufp;
153   size_t numbuflen;
154
155   for (n=0, s=line; hexdigitp (s); s++, n++)
156     ;
157   if (nscanned)
158     *nscanned = n;
159   if (!n)
160     return NULL;
161   len = ((n+1) & ~0x01)/2; 
162   numbufp = smklen (numbuf, sizeof numbuf, len, &numbuflen);
163   buf = xtrymalloc (1 + numbuflen + len + 1 + 1);
164   if (!buf)
165     return NULL;
166   buf[0] = '(';
167   p = (unsigned char *)stpcpy ((char *)buf+1, numbufp);
168   s = line;
169   if ((n&1))
170     {
171       *p++ = xtoi_1 (s);
172       s++;
173       n--;
174     }
175   for (; n > 1; n -=2, s += 2)
176     *p++ = xtoi_2 (s);
177   *p++ = ')';
178   *p = 0; /* (Not really neaded.) */
179
180   return buf;
181 }
182
183
184 /* Return the hash algorithm from a KSBA sig-val. SIGVAL is a
185    canonical encoded S-expression.  Return 0 if the hash algorithm is
186    not encoded in SIG-VAL or it is not supported by libgcrypt.  */
187 int
188 hash_algo_from_sigval (const unsigned char *sigval)
189 {
190   const unsigned char *s = sigval;
191   size_t n;
192   int depth;
193   char buffer[50];
194
195   if (!s || *s != '(')
196     return 0; /* Invalid S-expression.  */
197   s++;
198   n = snext (&s);
199   if (!n)
200     return 0; /* Invalid S-expression.  */
201   if (!smatch (&s, n, "sig-val"))
202     return 0; /* Not a sig-val.  */
203   if (*s != '(')
204     return 0; /* Invalid S-expression.  */
205   s++;
206   /* Skip over the algo+parameter list.  */
207   depth = 1;
208   if (sskip (&s, &depth) || depth)
209     return 0; /* Invalid S-expression.  */
210   if (*s != '(')
211     return 0; /* No futher list.  */
212   /* Check whether this is (hash ALGO).  */
213   s++;
214   n = snext (&s);
215   if (!n)
216     return 0; /* Invalid S-expression.  */
217   if (!smatch (&s, n, "hash"))
218     return 0; /* Not a "hash" keyword.  */
219   n = snext (&s);
220   if (!n || n+1 >= sizeof (buffer))
221     return 0; /* Algorithm string is missing or too long.  */
222   memcpy (buffer, s, n);
223   buffer[n] = 0;
224   
225   return gcry_md_map_name (buffer);
226 }
227