Prepare for OpenPGP cards with extended length support.
[gnupg.git] / agent / pksign.c
blob926438e878e2047525563267c60d3dee7f734b54
1 /* pksign.c - public key signing (well, actually using a secret key)
2 * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
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>
30 #include "agent.h"
33 static int
34 do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
35 int raw_value)
37 gcry_sexp_t hash;
38 int rc;
40 if (!raw_value)
42 const char *s;
43 char tmp[16+1];
44 int i;
46 s = gcry_md_algo_name (algo);
47 if (s && strlen (s) < 16)
49 for (i=0; i < strlen (s); i++)
50 tmp[i] = tolower (s[i]);
51 tmp[i] = '\0';
54 rc = gcry_sexp_build (&hash, NULL,
55 "(data (flags pkcs1) (hash %s %b))",
56 tmp, (int)mdlen, md);
58 else
60 gcry_mpi_t mpi;
62 rc = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
63 if (! rc)
65 rc = gcry_sexp_build (&hash, NULL,
66 "(data (flags raw) (value %m))",
67 mpi);
68 gcry_mpi_release (mpi);
73 *r_hash = hash;
74 return rc;
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)
86 int rc;
87 gcry_sexp_t hash;
88 unsigned char *frame;
89 size_t i, n, nframe;
91 nframe = (nbits+7) / 8;
92 if ( !mdlen || mdlen + 8 + 4 > nframe )
94 /* Can't encode this hash into a frame of size NFRAME. */
95 return gpg_error (GPG_ERR_TOO_SHORT);
98 frame = xtrymalloc (nframe);
99 if (!frame)
100 return gpg_error_from_syserror ();
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);
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);
121 *r_hash = hash;
122 return rc;
127 /* SIGN whatever information we have accumulated in CTRL and return
128 the signature S-Expression. */
130 agent_pksign_do (ctrl_t ctrl, const char *desc_text,
131 gcry_sexp_t *signature_sexp, cache_mode_t cache_mode)
133 gcry_sexp_t s_skey = NULL, s_sig = NULL;
134 unsigned char *shadow_info = NULL;
135 unsigned int rc = 0; /* FIXME: gpg-error? */
137 if (! ctrl->have_keygrip)
138 return gpg_error (GPG_ERR_NO_SECKEY);
140 rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
141 &shadow_info, cache_mode, &s_skey);
142 if (rc)
144 log_error ("failed to read the secret key\n");
145 goto leave;
148 if (!s_skey)
150 /* Divert operation to the smartcard */
152 unsigned char *buf = NULL;
153 size_t len = 0;
155 rc = divert_pksign (ctrl,
156 ctrl->digest.value,
157 ctrl->digest.valuelen,
158 ctrl->digest.algo,
159 shadow_info, &buf);
160 if (rc)
162 log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
163 goto leave;
165 len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
166 assert (len);
168 rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
169 xfree (buf);
170 if (rc)
172 log_error ("failed to convert sigbuf returned by divert_pksign "
173 "into S-Exp: %s", gpg_strerror (rc));
174 goto leave;
177 else
179 /* No smartcard, but a private key */
181 gcry_sexp_t s_hash = NULL;
183 /* Put the hash into a sexp */
184 if (ctrl->digest.algo == 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;
198 if (DBG_CRYPTO)
200 log_debug ("skey: ");
201 gcry_sexp_dump (s_skey);
204 /* sign */
205 rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
206 gcry_sexp_release (s_hash);
207 if (rc)
209 log_error ("signing failed: %s\n", gpg_strerror (rc));
210 goto leave;
213 if (DBG_CRYPTO)
215 log_debug ("result: ");
216 gcry_sexp_dump (s_sig);
220 leave:
222 *signature_sexp = s_sig;
224 gcry_sexp_release (s_skey);
225 xfree (shadow_info);
227 return rc;
230 /* SIGN whatever information we have accumulated in CTRL and write it
231 back to OUTFP. */
233 agent_pksign (ctrl_t ctrl, const char *desc_text,
234 membuf_t *outbuf, cache_mode_t cache_mode)
236 gcry_sexp_t s_sig = NULL;
237 char *buf = NULL;
238 size_t len = 0;
239 int rc = 0;
241 rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode);
242 if (rc)
243 goto leave;
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);
251 put_membuf (outbuf, buf, len);
253 leave:
254 gcry_sexp_release (s_sig);
255 xfree (buf);
257 return rc;