agent: Fix length test in sshcontrol parser.
[gnupg.git] / agent / pksign.c
1 /* pksign.c - public key signing (well, actually using a secret key)
2  * Copyright (C) 2001, 2002, 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 <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30 #include "agent.h"
31
32
33 static int
34 do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
35               int raw_value)
36 {
37   gcry_sexp_t hash;
38   int rc;
39
40   if (!raw_value)
41     {
42       const char *s;
43       char tmp[16+1];
44       int i;
45       
46       s = gcry_md_algo_name (algo);
47       if (s && strlen (s) < 16)
48         {
49           for (i=0; i < strlen (s); i++)
50             tmp[i] = tolower (s[i]);
51           tmp[i] = '\0';   
52         }
53
54       rc = gcry_sexp_build (&hash, NULL,
55                             "(data (flags pkcs1) (hash %s %b))",
56                             tmp, (int)mdlen, md);
57     }
58   else
59     {
60       gcry_mpi_t mpi;
61       
62       rc = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
63       if (! rc)
64         {
65           rc = gcry_sexp_build (&hash, NULL,
66                                 "(data (flags raw) (value %m))",
67                                 mpi);
68           gcry_mpi_release (mpi);
69         }
70           
71     }
72   
73   *r_hash = hash;
74   return rc;   
75 }
76
77
78 /* Special version of do_encode_md to take care of pkcs#1 padding.
79    For TLS-MD5SHA1 we need to do the padding ourself as Libgrypt does
80    not know about this special scheme.  Fixme: We should have a
81    pkcs1-only-padding flag for Libgcrypt. */
82 static int
83 do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits,
84                      gcry_sexp_t *r_hash)
85 {
86   int rc;
87   gcry_sexp_t hash;
88   unsigned char *frame;
89   size_t i, n, nframe;
90             
91   nframe = (nbits+7) / 8;
92   if ( !mdlen || mdlen + 8 + 4 > nframe )
93     {
94       /* Can't encode this hash into a frame of size NFRAME. */
95       return gpg_error (GPG_ERR_TOO_SHORT);
96     }
97
98   frame = xtrymalloc (nframe);
99   if (!frame)
100     return gpg_error_from_syserror ();
101   
102   /* Assemble the pkcs#1 block type 1. */
103   n = 0;
104   frame[n++] = 0;
105   frame[n++] = 1; /* Block type. */
106   i = nframe - mdlen - 3 ;
107   assert (i >= 8); /* At least 8 bytes of padding.  */
108   memset (frame+n, 0xff, i );
109   n += i;
110   frame[n++] = 0;
111   memcpy (frame+n, md, mdlen );
112   n += mdlen;
113   assert (n == nframe);
114   
115   /* Create the S-expression.  */
116   rc = gcry_sexp_build (&hash, NULL,
117                         "(data (flags raw) (value %b))",
118                         (int)nframe, frame);
119   xfree (frame);
120
121   *r_hash = hash;
122   return rc;   
123 }
124
125
126
127 /* SIGN whatever information we have accumulated in CTRL and return
128    the signature S-expression.  LOOKUP is an optional function to
129    provide a way for lower layers to ask for the caching TTL. */
130 int
131 agent_pksign_do (ctrl_t ctrl, const char *desc_text,
132                  gcry_sexp_t *signature_sexp,
133                  cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
134 {
135   gcry_sexp_t s_skey = NULL, s_sig = NULL;
136   unsigned char *shadow_info = NULL;
137   unsigned int rc = 0;          /* FIXME: gpg-error? */
138
139   if (! ctrl->have_keygrip)
140     return gpg_error (GPG_ERR_NO_SECKEY);
141
142   rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
143                             &shadow_info, cache_mode, lookup_ttl,
144                             &s_skey);
145   if (rc)
146     {
147       log_error ("failed to read the secret key\n");
148       goto leave;
149     }
150
151   if (!s_skey)
152     {
153       /* Divert operation to the smartcard */
154
155       unsigned char *buf = NULL;
156       size_t len = 0;
157
158       rc = divert_pksign (ctrl, 
159                           ctrl->digest.value, 
160                           ctrl->digest.valuelen,
161                           ctrl->digest.algo,
162                           shadow_info, &buf);
163       if (rc)
164         {
165           log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
166           goto leave;
167         }
168       len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
169       assert (len);
170
171       rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
172       xfree (buf);
173       if (rc)
174         {
175           log_error ("failed to convert sigbuf returned by divert_pksign "
176                      "into S-Exp: %s", gpg_strerror (rc));
177           goto leave;
178         }
179     }
180   else
181     {
182       /* No smartcard, but a private key */
183
184       gcry_sexp_t s_hash = NULL;
185
186       /* Put the hash into a sexp */
187       if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
188         rc = do_encode_raw_pkcs1 (ctrl->digest.value,
189                                   ctrl->digest.valuelen,
190                                   gcry_pk_get_nbits (s_skey),
191                                   &s_hash);
192       else
193         rc = do_encode_md (ctrl->digest.value,
194                            ctrl->digest.valuelen,
195                            ctrl->digest.algo,
196                            &s_hash,
197                            ctrl->digest.raw_value);
198       if (rc)
199         goto leave;
200
201       if (DBG_CRYPTO)
202         {
203           log_debug ("skey: ");
204           gcry_sexp_dump (s_skey);
205         }
206
207       /* sign */
208       rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
209       gcry_sexp_release (s_hash);
210       if (rc)
211         {
212           log_error ("signing failed: %s\n", gpg_strerror (rc));
213           goto leave;
214         }
215
216       if (DBG_CRYPTO)
217         {
218           log_debug ("result: ");
219           gcry_sexp_dump (s_sig);
220         }
221     }
222
223  leave:
224
225   *signature_sexp = s_sig;
226
227   gcry_sexp_release (s_skey);
228   xfree (shadow_info);
229
230   return rc;
231 }
232
233 /* SIGN whatever information we have accumulated in CTRL and write it
234    back to OUTFP. */
235 int
236 agent_pksign (ctrl_t ctrl, const char *desc_text,
237               membuf_t *outbuf, cache_mode_t cache_mode) 
238 {
239   gcry_sexp_t s_sig = NULL;
240   char *buf = NULL;
241   size_t len = 0;
242   int rc = 0;
243
244   rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode, NULL);
245   if (rc)
246     goto leave;
247
248   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
249   assert (len);
250   buf = xmalloc (len);
251   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
252   assert (len);
253
254   put_membuf (outbuf, buf, len);
255
256  leave:
257   gcry_sexp_release (s_sig);
258   xfree (buf);
259
260   return rc;
261 }