Updated estream.
[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 pckcs#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. */
129 int
130 agent_pksign_do (ctrl_t ctrl, const char *desc_text,
131                  gcry_sexp_t *signature_sexp, cache_mode_t cache_mode)
132 {
133   gcry_sexp_t s_skey = NULL, s_sig = NULL;
134   unsigned char *shadow_info = NULL;
135   unsigned int rc = 0;          /* FIXME: gpg-error? */
136
137   if (! ctrl->have_keygrip)
138     return gpg_error (GPG_ERR_NO_SECKEY);
139
140   rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
141                             &shadow_info, cache_mode, &s_skey);
142   if (rc)
143     {
144       log_error ("failed to read the secret key\n");
145       goto leave;
146     }
147
148   if (!s_skey)
149     {
150       /* Divert operation to the smartcard */
151
152       unsigned char *buf = NULL;
153       size_t len = 0;
154
155       rc = divert_pksign (ctrl, 
156                           ctrl->digest.value, 
157                           ctrl->digest.valuelen,
158                           ctrl->digest.algo,
159                           shadow_info, &buf);
160       if (rc)
161         {
162           log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
163           goto leave;
164         }
165       len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
166       assert (len);
167
168       rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
169       xfree (buf);
170       if (rc)
171         {
172           log_error ("failed to convert sigbuf returned by divert_pksign "
173                      "into S-Exp: %s", gpg_strerror (rc));
174           goto leave;
175         }
176     }
177   else
178     {
179       /* No smartcard, but a private key */
180
181       gcry_sexp_t s_hash = NULL;
182
183       /* Put the hash into a sexp */
184       if (ctrl->digest.algo == GCRY_MD_USER_TLS_MD5SHA1)
185         rc = do_encode_raw_pkcs1 (ctrl->digest.value,
186                                   ctrl->digest.valuelen,
187                                   gcry_pk_get_nbits (s_skey),
188                                   &s_hash);
189       else
190         rc = do_encode_md (ctrl->digest.value,
191                            ctrl->digest.valuelen,
192                            ctrl->digest.algo,
193                            &s_hash,
194                            ctrl->digest.raw_value);
195       if (rc)
196         goto leave;
197
198       if (DBG_CRYPTO)
199         {
200           log_debug ("skey: ");
201           gcry_sexp_dump (s_skey);
202         }
203
204       /* sign */
205       rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
206       gcry_sexp_release (s_hash);
207       if (rc)
208         {
209           log_error ("signing failed: %s\n", gpg_strerror (rc));
210           goto leave;
211         }
212
213       if (DBG_CRYPTO)
214         {
215           log_debug ("result: ");
216           gcry_sexp_dump (s_sig);
217         }
218     }
219
220  leave:
221
222   *signature_sexp = s_sig;
223
224   gcry_sexp_release (s_skey);
225   xfree (shadow_info);
226
227   return rc;
228 }
229
230 /* SIGN whatever information we have accumulated in CTRL and write it
231    back to OUTFP. */
232 int
233 agent_pksign (ctrl_t ctrl, const char *desc_text,
234               membuf_t *outbuf, cache_mode_t cache_mode) 
235 {
236   gcry_sexp_t s_sig = NULL;
237   char *buf = NULL;
238   size_t len = 0;
239   int rc = 0;
240
241   rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode);
242   if (rc)
243     goto leave;
244
245   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
246   assert (len);
247   buf = xmalloc (len);
248   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
249   assert (len);
250
251   put_membuf (outbuf, buf, len);
252
253  leave:
254   gcry_sexp_release (s_sig);
255   xfree (buf);
256
257   return rc;
258 }