~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to sm/certcheck.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <errno.h>
 
26
#include <unistd.h> 
 
27
#include <time.h>
 
28
#include <assert.h>
 
29
 
 
30
#include "gpgsm.h"
 
31
#include <gcrypt.h>
 
32
#include <ksba.h>
 
33
 
 
34
#include "keydb.h"
 
35
#include "i18n.h"
 
36
 
 
37
 
 
38
static int
 
39
do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits,
 
40
              gcry_mpi_t *r_val)
 
41
{
 
42
  int n, nframe;
 
43
  unsigned char *frame;
 
44
 
 
45
  if (pkalgo == GCRY_PK_DSA)
 
46
    {
 
47
      nframe = gcry_md_get_algo_dlen (algo);
 
48
      if (nframe != 20)
 
49
        {
 
50
          log_error (_("DSA requires the use of a 160 bit hash algorithm\n"));
 
51
          return gpg_error (GPG_ERR_INTERNAL);
 
52
        }
 
53
      frame = xtrymalloc (nframe);
 
54
      if (!frame)
 
55
        return OUT_OF_CORE (errno);
 
56
      memcpy (frame, gcry_md_read (md, algo), nframe);
 
57
      n = nframe;
 
58
    }
 
59
  else
 
60
    {
 
61
      int i;
 
62
      unsigned char asn[100];
 
63
      size_t asnlen;
 
64
      size_t len;
 
65
 
 
66
      nframe = (nbits+7) / 8;
 
67
 
 
68
      asnlen = DIM(asn);
 
69
      if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
 
70
        {
 
71
          log_error ("no object identifier for algo %d\n", algo);
 
72
          return gpg_error (GPG_ERR_INTERNAL);
 
73
        }
 
74
      
 
75
      len = gcry_md_get_algo_dlen (algo);
 
76
      
 
77
      if ( len + asnlen + 4  > nframe )
 
78
        {
 
79
          log_error ("can't encode a %d bit MD into a %d bits frame\n",
 
80
                     (int)(len*8), (int)nbits);
 
81
          return gpg_error (GPG_ERR_INTERNAL);
 
82
        }
 
83
      
 
84
      /* We encode the MD in this way:
 
85
       *
 
86
       *           0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
 
87
       *
 
88
       * PAD consists of FF bytes.
 
89
       */
 
90
      frame = xtrymalloc (nframe);
 
91
      if (!frame)
 
92
        return OUT_OF_CORE (errno);
 
93
      n = 0;
 
94
      frame[n++] = 0;
 
95
      frame[n++] = 1; /* block type */
 
96
      i = nframe - len - asnlen -3 ;
 
97
      assert ( i > 1 );
 
98
      memset ( frame+n, 0xff, i ); n += i;
 
99
      frame[n++] = 0;
 
100
      memcpy ( frame+n, asn, asnlen ); n += asnlen;
 
101
      memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len;
 
102
      assert ( n == nframe );
 
103
    }
 
104
  if (DBG_X509)
 
105
    {
 
106
      int j;
 
107
      log_debug ("encoded hash:");
 
108
      for (j=0; j < nframe; j++)
 
109
        log_printf (" %02X", frame[j]);
 
110
      log_printf ("\n");
 
111
    }
 
112
      
 
113
  gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe);
 
114
  xfree (frame);
 
115
  return 0;
 
116
}
 
117
 
 
118
/* Return the public key algorithm id from the S-expression PKEY.
 
119
   FIXME: libgcrypt should provide such a function.  Note that this
 
120
   implementation uses the names as used by libksba.  */
 
121
static int
 
122
pk_algo_from_sexp (gcry_sexp_t pkey)
 
123
{
 
124
  gcry_sexp_t l1, l2;
 
125
  const char *name;
 
126
  size_t n;
 
127
  int algo;
 
128
 
 
129
  l1 = gcry_sexp_find_token (pkey, "public-key", 0);
 
130
  if (!l1)
 
131
    return 0; /* Not found.  */
 
132
  l2 = gcry_sexp_cadr (l1);
 
133
  gcry_sexp_release (l1);
 
134
 
 
135
  name = gcry_sexp_nth_data (l2, 0, &n);
 
136
  if (!name)
 
137
    algo = 0; /* Not found. */
 
138
  else if (n==3 && !memcmp (name, "rsa", 3))
 
139
    algo = GCRY_PK_RSA;
 
140
  else if (n==3 && !memcmp (name, "dsa", 3))
 
141
    algo = GCRY_PK_DSA;
 
142
  else if (n==13 && !memcmp (name, "ambiguous-rsa", 13))
 
143
    algo = GCRY_PK_RSA;
 
144
  else
 
145
    algo = 0;
 
146
  gcry_sexp_release (l2);
 
147
  return algo;
 
148
}
 
149
 
 
150
 
 
151
/*
 
152
  Check the signature on CERT using the ISSUER-CERT.  This function
 
153
  does only test the cryptographic signature and nothing else.  It is
 
154
  assumed that the ISSUER_CERT is valid. */
 
155
int
 
156
gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
 
157
{
 
158
  const char *algoid;
 
159
  gcry_md_hd_t md;
 
160
  int rc, algo;
 
161
  gcry_mpi_t frame;
 
162
  ksba_sexp_t p;
 
163
  size_t n;
 
164
  gcry_sexp_t s_sig, s_hash, s_pkey;
 
165
 
 
166
  algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
 
167
  if (!algo)
 
168
    {
 
169
      log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
 
170
      return gpg_error (GPG_ERR_GENERAL);
 
171
    }
 
172
  rc = gcry_md_open (&md, algo, 0);
 
173
  if (rc)
 
174
    {
 
175
      log_error ("md_open failed: %s\n", gpg_strerror (rc));
 
176
      return rc;
 
177
    }
 
178
  if (DBG_HASHING)
 
179
    gcry_md_start_debug (md, "hash.cert");
 
180
 
 
181
  rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
 
182
  if (rc)
 
183
    {
 
184
      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
 
185
      gcry_md_close (md);
 
186
      return rc;
 
187
    }
 
188
  gcry_md_final (md);
 
189
 
 
190
  p = ksba_cert_get_sig_val (cert);
 
191
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
 
192
  if (!n)
 
193
    {
 
194
      log_error ("libksba did not return a proper S-Exp\n");
 
195
      gcry_md_close (md);
 
196
      ksba_free (p);
 
197
      return gpg_error (GPG_ERR_BUG);
 
198
    }
 
199
  if (DBG_X509)
 
200
    {
 
201
      int j;
 
202
      log_debug ("signature value:");
 
203
      for (j=0; j < n; j++)
 
204
        log_printf (" %02X", p[j]);
 
205
      log_printf ("\n");
 
206
    }
 
207
 
 
208
  rc = gcry_sexp_sscan ( &s_sig, NULL, p, n);
 
209
  ksba_free (p);
 
210
  if (rc)
 
211
    {
 
212
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
 
213
      gcry_md_close (md);
 
214
      return rc;
 
215
    }
 
216
 
 
217
  p = ksba_cert_get_public_key (issuer_cert);
 
218
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
 
219
  if (!n)
 
220
    {
 
221
      log_error ("libksba did not return a proper S-Exp\n");
 
222
      gcry_md_close (md);
 
223
      ksba_free (p);
 
224
      gcry_sexp_release (s_sig);
 
225
      return gpg_error (GPG_ERR_BUG);
 
226
    }
 
227
  rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
 
228
  ksba_free (p);
 
229
  if (rc)
 
230
    {
 
231
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
 
232
      gcry_md_close (md);
 
233
      gcry_sexp_release (s_sig);
 
234
      return rc;
 
235
    }
 
236
 
 
237
  rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
 
238
                     gcry_pk_get_nbits (s_pkey), &frame);
 
239
  if (rc)
 
240
    {
 
241
      gcry_md_close (md);
 
242
      gcry_sexp_release (s_sig);
 
243
      gcry_sexp_release (s_pkey);
 
244
      return rc;
 
245
    }
 
246
 
 
247
  /* put hash into the S-Exp s_hash */
 
248
  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
 
249
    BUG ();
 
250
  gcry_mpi_release (frame);
 
251
 
 
252
  
 
253
  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
 
254
  if (DBG_CRYPTO)
 
255
      log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
 
256
  gcry_md_close (md);
 
257
  gcry_sexp_release (s_sig);
 
258
  gcry_sexp_release (s_hash);
 
259
  gcry_sexp_release (s_pkey);
 
260
  return rc;
 
261
}
 
262
 
 
263
 
 
264
 
 
265
int
 
266
gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
 
267
                           gcry_md_hd_t md, int algo)
 
268
{
 
269
  int rc;
 
270
  ksba_sexp_t p;
 
271
  gcry_mpi_t frame;
 
272
  gcry_sexp_t s_sig, s_hash, s_pkey;
 
273
  size_t n;
 
274
 
 
275
  n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
 
276
  if (!n)
 
277
    {
 
278
      log_error ("libksba did not return a proper S-Exp\n");
 
279
      return gpg_error (GPG_ERR_BUG);
 
280
    }
 
281
  rc = gcry_sexp_sscan (&s_sig, NULL, sigval, n);
 
282
  if (rc)
 
283
    {
 
284
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
 
285
      return rc;
 
286
    }
 
287
 
 
288
  p = ksba_cert_get_public_key (cert);
 
289
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
 
290
  if (!n)
 
291
    {
 
292
      log_error ("libksba did not return a proper S-Exp\n");
 
293
      ksba_free (p);
 
294
      gcry_sexp_release (s_sig);
 
295
      return gpg_error (GPG_ERR_BUG);
 
296
    }
 
297
  if (DBG_X509)
 
298
    log_printhex ("public key: ", p, n);
 
299
 
 
300
  rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
 
301
  ksba_free (p);
 
302
  if (rc)
 
303
    {
 
304
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
 
305
      gcry_sexp_release (s_sig);
 
306
      return rc;
 
307
    }
 
308
 
 
309
 
 
310
  rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
 
311
                     gcry_pk_get_nbits (s_pkey), &frame);
 
312
  if (rc)
 
313
    {
 
314
      gcry_sexp_release (s_sig);
 
315
      gcry_sexp_release (s_pkey);
 
316
      return rc;
 
317
    }
 
318
  /* put hash into the S-Exp s_hash */
 
319
  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
 
320
    BUG ();
 
321
  gcry_mpi_release (frame);
 
322
  
 
323
  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
 
324
  if (DBG_CRYPTO)
 
325
      log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
 
326
  gcry_sexp_release (s_sig);
 
327
  gcry_sexp_release (s_hash);
 
328
  gcry_sexp_release (s_pkey);
 
329
  return rc;
 
330
}
 
331
 
 
332
 
 
333
 
 
334
int
 
335
gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert,
 
336
                            gcry_md_hd_t md, int mdalgo, char **r_sigval)
 
337
{
 
338
  int rc;
 
339
  char *grip, *desc;
 
340
  size_t siglen;
 
341
 
 
342
  grip = gpgsm_get_keygrip_hexstring (cert);
 
343
  if (!grip)
 
344
    return gpg_error (GPG_ERR_BAD_CERT);
 
345
 
 
346
  desc = gpgsm_format_keydesc (cert);
 
347
 
 
348
  rc = gpgsm_agent_pksign (ctrl, grip, desc, gcry_md_read(md, mdalgo), 
 
349
                           gcry_md_get_algo_dlen (mdalgo), mdalgo,
 
350
                           r_sigval, &siglen);
 
351
  xfree (desc);
 
352
  xfree (grip);
 
353
  return rc;
 
354
}
 
355
 
 
356
 
 
357