Preparing a new release. Updated gettext
[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 ctrl, const char *desc_text,
83                  gcry_sexp_t *signature_sexp, int ignore_cache)
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, ignore_cache, &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, 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 ctrl, const char *desc_text, FILE *outfp, int ignore_cache) 
180 {
181   gcry_sexp_t s_sig = NULL;
182   char *buf = NULL;
183   size_t len = 0;
184   int rc = 0;
185
186   rc = agent_pksign_do (ctrl, desc_text, &s_sig, ignore_cache);
187   if (rc)
188     goto leave;
189
190   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
191   assert (len);
192   buf = xmalloc (len);
193   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
194   assert (len);
195
196   /* FIXME: we must make sure that no buffering takes place or we are
197      in full control of the buffer memory (easy to do) - should go
198      into assuan. */
199   fwrite (buf, 1, len, outfp);
200
201  leave:
202   gcry_sexp_release (s_sig);
203   xfree (buf);
204
205   return rc;
206 }