Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkm-sexp.h"
24 :
25 : struct _GkmSexp {
26 : gint refs;
27 : gcry_sexp_t real;
28 : };
29 :
30 : GkmSexp*
31 61 : gkm_sexp_new (gcry_sexp_t real)
32 : {
33 : GkmSexp *sexp;
34 61 : g_return_val_if_fail (real, NULL);
35 61 : sexp = g_slice_new0 (GkmSexp);
36 61 : sexp->refs = 1;
37 61 : sexp->real = real;
38 61 : return sexp;
39 : }
40 :
41 : GkmSexp*
42 68 : gkm_sexp_ref (GkmSexp *sexp)
43 : {
44 68 : g_return_val_if_fail (sexp, NULL);
45 68 : ++(sexp->refs);
46 68 : return sexp;
47 : }
48 :
49 : void
50 126 : gkm_sexp_unref (gpointer data)
51 : {
52 126 : GkmSexp *sexp = data;
53 126 : g_return_if_fail (sexp);
54 126 : if (--(sexp->refs) == 0) {
55 58 : g_assert (sexp->real);
56 58 : gcry_sexp_release (sexp->real);
57 58 : g_slice_free (GkmSexp, sexp);
58 : }
59 : }
60 :
61 : gcry_sexp_t
62 76 : gkm_sexp_get (GkmSexp *sexp)
63 : {
64 76 : g_return_val_if_fail (sexp, NULL);
65 76 : g_return_val_if_fail (sexp->real, NULL);
66 76 : return sexp->real;
67 : }
68 :
69 : GType
70 12 : gkm_sexp_boxed_type (void)
71 : {
72 : static GType type = 0;
73 12 : if (!type)
74 9 : type = g_boxed_type_register_static ("GkmSexp",
75 : (GBoxedCopyFunc)gkm_sexp_ref,
76 : (GBoxedFreeFunc)gkm_sexp_unref);
77 12 : return type;
78 : }
79 :
80 : #define PUBLIC_KEY "public-key"
81 : #define PUBLIC_KEY_L 10
82 : #define PRIVATE_KEY "private-key"
83 : #define PRIVATE_KEY_L 11
84 :
85 : gboolean
86 65 : gkm_sexp_parse_key (gcry_sexp_t s_key, int *algorithm, gboolean *is_private,
87 : gcry_sexp_t *numbers)
88 : {
89 65 : gboolean ret = FALSE;
90 65 : gcry_sexp_t child = NULL;
91 65 : gchar *str = NULL;
92 : const gchar *data;
93 : gsize n_data;
94 : gboolean priv;
95 : int algo;
96 :
97 65 : data = gcry_sexp_nth_data (s_key, 0, &n_data);
98 65 : if (!data)
99 0 : goto done;
100 :
101 65 : if (n_data == PUBLIC_KEY_L && strncmp (data, PUBLIC_KEY, PUBLIC_KEY_L) == 0)
102 11 : priv = FALSE;
103 54 : else if (n_data == PRIVATE_KEY_L && strncmp (data, PRIVATE_KEY, PRIVATE_KEY_L) == 0)
104 54 : priv = TRUE;
105 : else
106 0 : goto done;
107 :
108 65 : child = gcry_sexp_nth (s_key, 1);
109 65 : if (!child)
110 0 : goto done;
111 :
112 65 : data = gcry_sexp_nth_data (child, 0, &n_data);
113 65 : if (!data)
114 0 : goto done;
115 :
116 65 : str = g_alloca (n_data + 1);
117 65 : memcpy (str, data, n_data);
118 65 : str[n_data] = 0;
119 :
120 65 : algo = gcry_pk_map_name (str);
121 65 : if (!algo)
122 0 : goto done;
123 :
124 : /* Yay all done */
125 65 : if (algorithm)
126 56 : *algorithm = algo;
127 65 : if (numbers) {
128 18 : *numbers = child;
129 18 : child = NULL;
130 : }
131 65 : if (is_private)
132 31 : *is_private = priv;
133 :
134 65 : ret = TRUE;
135 :
136 65 : done:
137 65 : gcry_sexp_release (child);
138 65 : return ret;
139 : }
140 :
141 : static gcry_sexp_t
142 4 : rsa_numbers_to_public (gcry_sexp_t rsa)
143 : {
144 4 : gcry_sexp_t pubkey = NULL;
145 : gcry_mpi_t n, e;
146 : gcry_error_t gcry;
147 :
148 4 : n = e = NULL;
149 :
150 8 : if (!gkm_sexp_extract_mpi (rsa, &n, "n", NULL) ||
151 4 : !gkm_sexp_extract_mpi (rsa, &e, "e", NULL))
152 0 : goto done;
153 :
154 4 : gcry = gcry_sexp_build (&pubkey, NULL, "(public-key (rsa (n %m) (e %m)))",
155 : n, e);
156 4 : if (gcry)
157 0 : goto done;
158 4 : g_assert (pubkey);
159 :
160 4 : done:
161 4 : gcry_mpi_release (n);
162 4 : gcry_mpi_release (e);
163 :
164 4 : return pubkey;
165 : }
166 :
167 : static gcry_sexp_t
168 2 : dsa_numbers_to_public (gcry_sexp_t dsa)
169 : {
170 : gcry_mpi_t p, q, g, y;
171 2 : gcry_sexp_t pubkey = NULL;
172 : gcry_error_t gcry;
173 :
174 2 : p = q = g = y = NULL;
175 :
176 4 : if (!gkm_sexp_extract_mpi (dsa, &p, "p", NULL) ||
177 4 : !gkm_sexp_extract_mpi (dsa, &q, "q", NULL) ||
178 4 : !gkm_sexp_extract_mpi (dsa, &g, "g", NULL) ||
179 2 : !gkm_sexp_extract_mpi (dsa, &y, "y", NULL))
180 0 : goto done;
181 :
182 2 : gcry = gcry_sexp_build (&pubkey, NULL, "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))",
183 : p, q, g, y);
184 2 : if (gcry)
185 0 : goto done;
186 2 : g_assert (pubkey);
187 :
188 2 : done:
189 2 : gcry_mpi_release (p);
190 2 : gcry_mpi_release (q);
191 2 : gcry_mpi_release (g);
192 2 : gcry_mpi_release (y);
193 :
194 2 : return pubkey;
195 : }
196 :
197 : static gcry_sexp_t
198 2 : ecdsa_numbers_to_public (gcry_sexp_t ecdsa)
199 : {
200 2 : gchar *curve_name = NULL, *q = NULL;
201 : gsize q_len;
202 2 : gcry_sexp_t pubkey = NULL;
203 : gcry_error_t gcry;
204 :
205 4 : if (!gkm_sexp_extract_string (ecdsa, &curve_name, "curve", NULL) ||
206 2 : !gkm_sexp_extract_buffer (ecdsa, &q, &q_len, "q", NULL))
207 0 : goto done;
208 :
209 2 : gcry = gcry_sexp_build (&pubkey, NULL, "(public-key (ecdsa (curve %s) (q %b)))",
210 : curve_name, q_len, q);
211 2 : if (gcry)
212 0 : goto done;
213 2 : g_assert (pubkey);
214 :
215 2 : done:
216 2 : g_free (curve_name);
217 2 : g_free (q);
218 :
219 2 : return pubkey;
220 : }
221 :
222 : gboolean
223 8 : gkm_sexp_key_to_public (gcry_sexp_t privkey, gcry_sexp_t *pubkey)
224 : {
225 : gcry_sexp_t numbers;
226 : int algorithm;
227 :
228 8 : if (!gkm_sexp_parse_key (privkey, &algorithm, NULL, &numbers))
229 0 : g_return_val_if_reached (FALSE);
230 :
231 8 : switch (algorithm) {
232 4 : case GCRY_PK_RSA:
233 4 : *pubkey = rsa_numbers_to_public (numbers);
234 4 : break;
235 2 : case GCRY_PK_DSA:
236 2 : *pubkey = dsa_numbers_to_public (numbers);
237 2 : break;
238 2 : case GCRY_PK_ECC:
239 2 : *pubkey = ecdsa_numbers_to_public (numbers);
240 2 : break;
241 0 : default:
242 0 : g_return_val_if_reached (FALSE);
243 : }
244 :
245 8 : gcry_sexp_release (numbers);
246 8 : return *pubkey ? TRUE : FALSE;
247 : }
248 :
249 : gboolean
250 91 : gkm_sexp_extract_mpi (gcry_sexp_t sexp, gcry_mpi_t *mpi, ...)
251 : {
252 91 : gcry_sexp_t at = NULL;
253 : va_list va;
254 :
255 91 : g_assert (sexp);
256 91 : g_assert (mpi);
257 :
258 91 : va_start (va, mpi);
259 91 : at = gkm_sexp_get_childv (sexp, va);
260 91 : va_end (va);
261 :
262 91 : *mpi = NULL;
263 91 : if (at)
264 91 : *mpi = gcry_sexp_nth_mpi (at ? at : sexp, 1, GCRYMPI_FMT_USG);
265 91 : if (at)
266 91 : gcry_sexp_release (at);
267 :
268 91 : return (*mpi) ? TRUE : FALSE;
269 : }
270 :
271 : /* ECDSA s-exp lists the curve name as a string */
272 : gboolean
273 7 : gkm_sexp_extract_string (gcry_sexp_t sexp, gchar **buf, ...)
274 : {
275 7 : gcry_sexp_t at = NULL;
276 : va_list va;
277 :
278 7 : g_assert (sexp);
279 7 : g_assert (buf);
280 :
281 7 : va_start (va, buf);
282 7 : at = gkm_sexp_get_childv (sexp, va);
283 7 : va_end (va);
284 :
285 7 : *buf = NULL;
286 7 : if (at) {
287 : size_t len;
288 : const char *data;
289 :
290 7 : data = gcry_sexp_nth_data (at, 1, &len);
291 7 : *buf = g_strndup (data, len);
292 7 : gcry_sexp_release (at);
293 : }
294 :
295 7 : return (*buf) ? TRUE : FALSE;
296 : }
297 :
298 : gboolean
299 10 : gkm_sexp_extract_buffer (gcry_sexp_t sexp, gchar **buf, gsize *bufsize, ...)
300 : {
301 10 : gcry_sexp_t at = NULL;
302 : va_list va;
303 :
304 10 : g_assert (sexp);
305 10 : g_assert (buf);
306 :
307 10 : va_start (va, bufsize);
308 10 : at = gkm_sexp_get_childv (sexp, va);
309 10 : va_end (va);
310 :
311 10 : *buf = NULL;
312 10 : if (at) {
313 : size_t len;
314 : const char *data;
315 :
316 10 : data = gcry_sexp_nth_data (at, 1, &len);
317 10 : *buf = g_memdup (data, len);
318 10 : *bufsize = len;
319 10 : gcry_sexp_release (at);
320 : }
321 :
322 10 : return (*buf) ? TRUE : FALSE;
323 : }
324 :
325 : gcry_sexp_t
326 113 : gkm_sexp_get_childv (gcry_sexp_t sexp, va_list va)
327 : {
328 113 : gcry_sexp_t at = NULL;
329 : gcry_sexp_t child;
330 : const char *name;
331 :
332 113 : g_assert (sexp);
333 :
334 : for(;;) {
335 301 : name = va_arg (va, const char*);
336 301 : if (!name)
337 113 : break;
338 :
339 188 : child = gcry_sexp_find_token (at ? at : sexp, name, 0);
340 188 : gcry_sexp_release (at);
341 188 : at = child;
342 188 : if (at == NULL)
343 0 : break;
344 : }
345 :
346 113 : va_end (va);
347 :
348 113 : return at;
349 : }
350 :
351 : void
352 0 : gkm_sexp_dump (gcry_sexp_t sexp)
353 : {
354 : gsize len;
355 : gchar *buf;
356 :
357 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
358 0 : buf = g_malloc (len);
359 0 : gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, buf, len);
360 0 : g_printerr ("%s", buf);
361 0 : g_free (buf);
362 0 : }
|