gcc-4 defaults forced me to edit many many files to get rid of the
[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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30
31 #include "agent.h"
32
33
34 static int
35 do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
36               int raw_value)
37 {
38   gcry_sexp_t hash;
39   int rc;
40
41   if (! raw_value)
42     {
43       const char *s;
44       char tmp[16+1];
45       int i;
46       
47       s = gcry_md_algo_name (algo);
48       if (s && strlen (s) < 16)
49         {
50           for (i=0; i < strlen (s); i++)
51             tmp[i] = tolower (s[i]);
52           tmp[i] = '\0';   
53         }
54
55       rc = gcry_sexp_build (&hash, NULL,
56                             "(data (flags pkcs1) (hash %s %b))",
57                             tmp, mdlen, md);
58     }
59   else
60     {
61       gcry_mpi_t mpi;
62       
63       rc = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
64       if (! rc)
65         {
66           rc = gcry_sexp_build (&hash, NULL,
67                                 "(data (flags raw) (value %m))",
68                                 mpi);
69           gcry_mpi_release (mpi);
70         }
71           
72     }
73   
74   *r_hash = hash;
75   return rc;   
76 }
77
78
79 /* SIGN whatever information we have accumulated in CTRL and return
80    the signature S-Expression. */
81 int
82 agent_pksign_do (ctrl_t ctrl, const char *desc_text,
83                  gcry_sexp_t *signature_sexp, cache_mode_t cache_mode)
84 {
85   gcry_sexp_t s_skey = NULL, s_sig = NULL;
86   unsigned char *shadow_info = NULL;
87   unsigned int rc = 0;          /* FIXME: gpg-error? */
88
89   if (! ctrl->have_keygrip)
90     return gpg_error (GPG_ERR_NO_SECKEY);
91
92   rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
93                             &shadow_info, cache_mode, &s_skey);
94   if (rc)
95     {
96       log_error ("failed to read the secret key\n");
97       goto leave;
98     }
99
100   if (!s_skey)
101     {
102       /* Divert operation to the smartcard */
103
104       unsigned char *buf = NULL;
105       size_t len = 0;
106
107       rc = divert_pksign (ctrl, 
108                           ctrl->digest.value, 
109                           ctrl->digest.valuelen,
110                           ctrl->digest.algo,
111                           shadow_info, &buf);
112       if (rc)
113         {
114           log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
115           goto leave;
116         }
117       len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
118       assert (len);
119
120       rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
121       xfree (buf);
122       if (rc)
123         {
124           log_error ("failed to convert sigbuf returned by divert_pksign "
125                      "into S-Exp: %s", gpg_strerror (rc));
126           goto leave;
127         }
128     }
129   else
130     {
131       /* No smartcard, but a private key */
132
133       gcry_sexp_t s_hash = NULL;
134
135       /* put the hash into a sexp */
136       rc = do_encode_md (ctrl->digest.value,
137                          ctrl->digest.valuelen,
138                          ctrl->digest.algo,
139                          &s_hash,
140                          ctrl->digest.raw_value);
141       if (rc)
142         goto leave;
143
144       if (DBG_CRYPTO)
145         {
146           log_debug ("skey: ");
147           gcry_sexp_dump (s_skey);
148         }
149
150       /* sign */
151       rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
152       gcry_sexp_release (s_hash);
153       if (rc)
154         {
155           log_error ("signing failed: %s\n", gpg_strerror (rc));
156           goto leave;
157         }
158
159       if (DBG_CRYPTO)
160         {
161           log_debug ("result: ");
162           gcry_sexp_dump (s_sig);
163         }
164     }
165
166  leave:
167
168   *signature_sexp = s_sig;
169
170   gcry_sexp_release (s_skey);
171   xfree (shadow_info);
172
173   return rc;
174 }
175
176 /* SIGN whatever information we have accumulated in CTRL and write it
177    back to OUTFP. */
178 int
179 agent_pksign (ctrl_t ctrl, const char *desc_text,
180               membuf_t *outbuf, cache_mode_t cache_mode) 
181 {
182   gcry_sexp_t s_sig = NULL;
183   char *buf = NULL;
184   size_t len = 0;
185   int rc = 0;
186
187   rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode);
188   if (rc)
189     goto leave;
190
191   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
192   assert (len);
193   buf = xmalloc (len);
194   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
195   assert (len);
196
197   put_membuf (outbuf, buf, len);
198
199  leave:
200   gcry_sexp_release (s_sig);
201   xfree (buf);
202
203   return rc;
204 }