LCOV - code coverage report
Current view: top level - sm - certcheck.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 68 219 31.1 %
Date: 2016-11-29 15:00:56 Functions: 3 6 50.0 %

          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 <https://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             : }

Generated by: LCOV version 1.11