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