Line data Source code
1 : /* certcheck.c - check one certificate
2 : * Copyright (C) 2001, 2003, 2004 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 : #include <config.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 : #include <errno.h>
25 : #include <unistd.h>
26 : #include <time.h>
27 : #include <assert.h>
28 :
29 : #include "gpgsm.h"
30 : #include <gcrypt.h>
31 : #include <ksba.h>
32 :
33 : #include "keydb.h"
34 : #include "i18n.h"
35 :
36 :
37 : /* Return the number of bits of the Q parameter from the DSA key
38 : KEY. */
39 : static unsigned int
40 0 : get_dsa_qbits (gcry_sexp_t key)
41 : {
42 : gcry_sexp_t l1, l2;
43 : gcry_mpi_t q;
44 : unsigned int nbits;
45 :
46 0 : l1 = gcry_sexp_find_token (key, "public-key", 0);
47 0 : if (!l1)
48 0 : return 0; /* Does not contain a key object. */
49 0 : l2 = gcry_sexp_cadr (l1);
50 0 : gcry_sexp_release (l1);
51 0 : l1 = gcry_sexp_find_token (l2, "q", 1);
52 0 : gcry_sexp_release (l2);
53 0 : if (!l1)
54 0 : return 0; /* Invalid object. */
55 0 : q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
56 0 : gcry_sexp_release (l1);
57 0 : if (!q)
58 0 : return 0; /* Missing value. */
59 0 : nbits = gcry_mpi_get_nbits (q);
60 0 : gcry_mpi_release (q);
61 :
62 0 : return nbits;
63 : }
64 :
65 :
66 : static int
67 3 : do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits,
68 : gcry_sexp_t pkey, gcry_mpi_t *r_val)
69 : {
70 : int n;
71 : size_t nframe;
72 : unsigned char *frame;
73 :
74 3 : if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
75 0 : {
76 : unsigned int qbits;
77 :
78 0 : if ( pkalgo == GCRY_PK_ECDSA )
79 0 : qbits = gcry_pk_get_nbits (pkey);
80 : else
81 0 : qbits = get_dsa_qbits (pkey);
82 :
83 0 : if ( (qbits%8) )
84 : {
85 0 : log_error(_("DSA requires the hash length to be a"
86 : " multiple of 8 bits\n"));
87 0 : return gpg_error (GPG_ERR_INTERNAL);
88 : }
89 :
90 : /* Don't allow any Q smaller than 160 bits. We don't want
91 : someone to issue signatures from a key with a 16-bit Q or
92 : something like that, which would look correct but allow
93 : trivial forgeries. Yes, I know this rules out using MD5 with
94 : DSA. ;) */
95 0 : if (qbits < 160)
96 : {
97 0 : log_error (_("%s key uses an unsafe (%u bit) hash\n"),
98 : gcry_pk_algo_name (pkalgo), qbits);
99 0 : return gpg_error (GPG_ERR_INTERNAL);
100 : }
101 :
102 : /* Check if we're too short. Too long is safe as we'll
103 : automatically left-truncate. */
104 0 : nframe = gcry_md_get_algo_dlen (algo);
105 0 : if (nframe < qbits/8)
106 : {
107 0 : log_error (_("a %u bit hash is not valid for a %u bit %s key\n"),
108 0 : (unsigned int)nframe*8,
109 : gcry_pk_get_nbits (pkey),
110 : gcry_pk_algo_name (pkalgo));
111 : /* FIXME: we need to check the requirements for ECDSA. */
112 0 : if (nframe < 20 || pkalgo == GCRY_PK_DSA )
113 0 : return gpg_error (GPG_ERR_INTERNAL);
114 : }
115 :
116 0 : frame = xtrymalloc (nframe);
117 0 : if (!frame)
118 0 : return out_of_core ();
119 0 : memcpy (frame, gcry_md_read (md, algo), nframe);
120 0 : n = nframe;
121 : /* Truncate. */
122 0 : if (n > qbits/8)
123 0 : n = qbits/8;
124 : }
125 : else
126 : {
127 : int i;
128 : unsigned char asn[100];
129 : size_t asnlen;
130 : size_t len;
131 :
132 3 : nframe = (nbits+7) / 8;
133 :
134 3 : asnlen = DIM(asn);
135 3 : if (!algo || gcry_md_test_algo (algo))
136 0 : return gpg_error (GPG_ERR_DIGEST_ALGO);
137 3 : if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
138 : {
139 0 : log_error ("no object identifier for algo %d\n", algo);
140 0 : return gpg_error (GPG_ERR_INTERNAL);
141 : }
142 :
143 3 : len = gcry_md_get_algo_dlen (algo);
144 :
145 3 : if ( len + asnlen + 4 > nframe )
146 : {
147 0 : log_error ("can't encode a %d bit MD into a %d bits frame\n",
148 : (int)(len*8), (int)nbits);
149 0 : return gpg_error (GPG_ERR_INTERNAL);
150 : }
151 :
152 : /* We encode the MD in this way:
153 : *
154 : * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
155 : *
156 : * PAD consists of FF bytes.
157 : */
158 3 : frame = xtrymalloc (nframe);
159 3 : if (!frame)
160 0 : return out_of_core ();
161 3 : n = 0;
162 3 : frame[n++] = 0;
163 3 : frame[n++] = 1; /* block type */
164 3 : i = nframe - len - asnlen -3 ;
165 3 : assert ( i > 1 );
166 3 : memset ( frame+n, 0xff, i ); n += i;
167 3 : frame[n++] = 0;
168 3 : memcpy ( frame+n, asn, asnlen ); n += asnlen;
169 3 : memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len;
170 3 : assert ( n == nframe );
171 : }
172 3 : if (DBG_CRYPTO)
173 : {
174 : int j;
175 0 : log_debug ("encoded hash:");
176 0 : for (j=0; j < nframe; j++)
177 0 : log_printf (" %02X", frame[j]);
178 0 : log_printf ("\n");
179 : }
180 :
181 3 : gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe);
182 3 : xfree (frame);
183 3 : return 0;
184 : }
185 :
186 : /* Return the public key algorithm id from the S-expression PKEY.
187 : FIXME: libgcrypt should provide such a function. Note that this
188 : implementation uses the names as used by libksba. */
189 : static int
190 3 : pk_algo_from_sexp (gcry_sexp_t pkey)
191 : {
192 : gcry_sexp_t l1, l2;
193 : const char *name;
194 : size_t n;
195 : int algo;
196 :
197 3 : l1 = gcry_sexp_find_token (pkey, "public-key", 0);
198 3 : if (!l1)
199 0 : return 0; /* Not found. */
200 3 : l2 = gcry_sexp_cadr (l1);
201 3 : gcry_sexp_release (l1);
202 :
203 3 : name = gcry_sexp_nth_data (l2, 0, &n);
204 3 : if (!name)
205 0 : algo = 0; /* Not found. */
206 3 : else if (n==3 && !memcmp (name, "rsa", 3))
207 3 : algo = GCRY_PK_RSA;
208 0 : else if (n==3 && !memcmp (name, "dsa", 3))
209 0 : algo = GCRY_PK_DSA;
210 : /* Because this function is called only for verification we can
211 : assume that ECC actually means ECDSA. */
212 0 : else if (n==3 && !memcmp (name, "ecc", 3))
213 0 : algo = GCRY_PK_ECDSA;
214 0 : else if (n==13 && !memcmp (name, "ambiguous-rsa", 13))
215 0 : algo = GCRY_PK_RSA;
216 : else
217 0 : algo = 0;
218 3 : gcry_sexp_release (l2);
219 3 : return algo;
220 : }
221 :
222 :
223 : /* Check the signature on CERT using the ISSUER-CERT. This function
224 : does only test the cryptographic signature and nothing else. It is
225 : assumed that the ISSUER_CERT is valid. */
226 : int
227 3 : gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
228 : {
229 : const char *algoid;
230 : gcry_md_hd_t md;
231 : int rc, algo;
232 : gcry_mpi_t frame;
233 : ksba_sexp_t p;
234 : size_t n;
235 : gcry_sexp_t s_sig, s_hash, s_pkey;
236 :
237 3 : algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
238 3 : if (!algo)
239 : {
240 0 : log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?");
241 0 : if (algoid
242 0 : && ( !strcmp (algoid, "1.2.840.113549.1.1.2")
243 0 : ||!strcmp (algoid, "1.2.840.113549.2.2")))
244 0 : log_info (_("(this is the MD2 algorithm)\n"));
245 0 : return gpg_error (GPG_ERR_GENERAL);
246 : }
247 3 : rc = gcry_md_open (&md, algo, 0);
248 3 : if (rc)
249 : {
250 0 : log_error ("md_open failed: %s\n", gpg_strerror (rc));
251 0 : return rc;
252 : }
253 3 : if (DBG_HASHING)
254 0 : gcry_md_debug (md, "hash.cert");
255 :
256 3 : rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
257 3 : if (rc)
258 : {
259 0 : log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
260 0 : gcry_md_close (md);
261 0 : return rc;
262 : }
263 3 : gcry_md_final (md);
264 :
265 3 : p = ksba_cert_get_sig_val (cert);
266 3 : n = gcry_sexp_canon_len (p, 0, NULL, NULL);
267 3 : if (!n)
268 : {
269 0 : log_error ("libksba did not return a proper S-Exp\n");
270 0 : gcry_md_close (md);
271 0 : ksba_free (p);
272 0 : return gpg_error (GPG_ERR_BUG);
273 : }
274 3 : if (DBG_CRYPTO)
275 : {
276 : int j;
277 0 : log_debug ("signature value:");
278 0 : for (j=0; j < n; j++)
279 0 : log_printf (" %02X", p[j]);
280 0 : log_printf ("\n");
281 : }
282 :
283 3 : rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n);
284 3 : ksba_free (p);
285 3 : if (rc)
286 : {
287 0 : log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
288 0 : gcry_md_close (md);
289 0 : return rc;
290 : }
291 :
292 3 : p = ksba_cert_get_public_key (issuer_cert);
293 3 : n = gcry_sexp_canon_len (p, 0, NULL, NULL);
294 3 : if (!n)
295 : {
296 0 : log_error ("libksba did not return a proper S-Exp\n");
297 0 : gcry_md_close (md);
298 0 : ksba_free (p);
299 0 : gcry_sexp_release (s_sig);
300 0 : return gpg_error (GPG_ERR_BUG);
301 : }
302 3 : rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
303 3 : ksba_free (p);
304 3 : if (rc)
305 : {
306 0 : log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
307 0 : gcry_md_close (md);
308 0 : gcry_sexp_release (s_sig);
309 0 : return rc;
310 : }
311 :
312 3 : rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
313 : gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
314 3 : if (rc)
315 : {
316 0 : gcry_md_close (md);
317 0 : gcry_sexp_release (s_sig);
318 0 : gcry_sexp_release (s_pkey);
319 0 : return rc;
320 : }
321 :
322 : /* put hash into the S-Exp s_hash */
323 3 : if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
324 0 : BUG ();
325 3 : gcry_mpi_release (frame);
326 :
327 :
328 3 : rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
329 3 : if (DBG_X509)
330 0 : log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
331 3 : gcry_md_close (md);
332 3 : gcry_sexp_release (s_sig);
333 3 : gcry_sexp_release (s_hash);
334 3 : gcry_sexp_release (s_pkey);
335 3 : return rc;
336 : }
337 :
338 :
339 :
340 : int
341 0 : gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
342 : gcry_md_hd_t md, int mdalgo, int *r_pkalgo)
343 : {
344 : int rc;
345 : ksba_sexp_t p;
346 : gcry_mpi_t frame;
347 : gcry_sexp_t s_sig, s_hash, s_pkey;
348 : size_t n;
349 : int pkalgo;
350 :
351 0 : if (r_pkalgo)
352 0 : *r_pkalgo = 0;
353 :
354 0 : n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
355 0 : if (!n)
356 : {
357 0 : log_error ("libksba did not return a proper S-Exp\n");
358 0 : return gpg_error (GPG_ERR_BUG);
359 : }
360 0 : rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n);
361 0 : if (rc)
362 : {
363 0 : log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
364 0 : return rc;
365 : }
366 :
367 0 : p = ksba_cert_get_public_key (cert);
368 0 : n = gcry_sexp_canon_len (p, 0, NULL, NULL);
369 0 : if (!n)
370 : {
371 0 : log_error ("libksba did not return a proper S-Exp\n");
372 0 : ksba_free (p);
373 0 : gcry_sexp_release (s_sig);
374 0 : return gpg_error (GPG_ERR_BUG);
375 : }
376 0 : if (DBG_CRYPTO)
377 0 : log_printhex ("public key: ", p, n);
378 :
379 0 : rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
380 0 : ksba_free (p);
381 0 : if (rc)
382 : {
383 0 : log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
384 0 : gcry_sexp_release (s_sig);
385 0 : return rc;
386 : }
387 :
388 0 : pkalgo = pk_algo_from_sexp (s_pkey);
389 0 : if (r_pkalgo)
390 0 : *r_pkalgo = pkalgo;
391 0 : rc = do_encode_md (md, mdalgo, pkalgo,
392 : gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
393 0 : if (rc)
394 : {
395 0 : gcry_sexp_release (s_sig);
396 0 : gcry_sexp_release (s_pkey);
397 0 : return rc;
398 : }
399 : /* put hash into the S-Exp s_hash */
400 0 : if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
401 0 : BUG ();
402 0 : gcry_mpi_release (frame);
403 :
404 0 : rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
405 0 : if (DBG_X509)
406 0 : log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
407 0 : gcry_sexp_release (s_sig);
408 0 : gcry_sexp_release (s_hash);
409 0 : gcry_sexp_release (s_pkey);
410 0 : return rc;
411 : }
412 :
413 :
414 :
415 : int
416 0 : gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert,
417 : gcry_md_hd_t md, int mdalgo,
418 : unsigned char **r_sigval)
419 : {
420 : int rc;
421 : char *grip, *desc;
422 : size_t siglen;
423 :
424 0 : grip = gpgsm_get_keygrip_hexstring (cert);
425 0 : if (!grip)
426 0 : return gpg_error (GPG_ERR_BAD_CERT);
427 :
428 0 : desc = gpgsm_format_keydesc (cert);
429 :
430 0 : rc = gpgsm_agent_pksign (ctrl, grip, desc, gcry_md_read(md, mdalgo),
431 0 : gcry_md_get_algo_dlen (mdalgo), mdalgo,
432 : r_sigval, &siglen);
433 0 : xfree (desc);
434 0 : xfree (grip);
435 0 : return rc;
436 : }
|