2006-10-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / pksign.c
blobc187eccaedc21584ca5975d81012eea07d698608
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 2 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
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>
32 #include "agent.h"
35 static int
36 do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
37 int raw_value)
39 gcry_sexp_t hash;
40 int rc;
42 if (!raw_value)
44 const char *s;
45 char tmp[16+1];
46 int i;
48 s = gcry_md_algo_name (algo);
49 if (s && strlen (s) < 16)
51 for (i=0; i < strlen (s); i++)
52 tmp[i] = tolower (s[i]);
53 tmp[i] = '\0';
56 rc = gcry_sexp_build (&hash, NULL,
57 "(data (flags pkcs1) (hash %s %b))",
58 tmp, (int)mdlen, md);
60 else
62 gcry_mpi_t mpi;
64 rc = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
65 if (! rc)
67 rc = gcry_sexp_build (&hash, NULL,
68 "(data (flags raw) (value %m))",
69 mpi);
70 gcry_mpi_release (mpi);
75 *r_hash = hash;
76 return rc;
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)
88 int rc;
89 gcry_sexp_t hash;
90 unsigned char *frame;
91 size_t i, n, nframe;
93 nframe = (nbits+7) / 8;
94 if ( !mdlen || mdlen + 8 + 4 > nframe )
96 /* Can't encode this hash into a frame of size NFRAME. */
97 return gpg_error (GPG_ERR_TOO_SHORT);
100 frame = xtrymalloc (nframe);
101 if (!frame)
102 return gpg_error_from_syserror ();
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);
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);
123 *r_hash = hash;
124 return rc;
129 /* SIGN whatever information we have accumulated in CTRL and return
130 the signature S-Expression. */
132 agent_pksign_do (ctrl_t ctrl, const char *desc_text,
133 gcry_sexp_t *signature_sexp, cache_mode_t cache_mode)
135 gcry_sexp_t s_skey = NULL, s_sig = NULL;
136 unsigned char *shadow_info = NULL;
137 unsigned int rc = 0; /* FIXME: gpg-error? */
139 if (! ctrl->have_keygrip)
140 return gpg_error (GPG_ERR_NO_SECKEY);
142 rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
143 &shadow_info, cache_mode, &s_skey);
144 if (rc)
146 log_error ("failed to read the secret key\n");
147 goto leave;
150 if (!s_skey)
152 /* Divert operation to the smartcard */
154 unsigned char *buf = NULL;
155 size_t len = 0;
157 rc = divert_pksign (ctrl,
158 ctrl->digest.value,
159 ctrl->digest.valuelen,
160 ctrl->digest.algo,
161 shadow_info, &buf);
162 if (rc)
164 log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
165 goto leave;
167 len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
168 assert (len);
170 rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
171 xfree (buf);
172 if (rc)
174 log_error ("failed to convert sigbuf returned by divert_pksign "
175 "into S-Exp: %s", gpg_strerror (rc));
176 goto leave;
179 else
181 /* No smartcard, but a private key */
183 gcry_sexp_t s_hash = NULL;
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;
200 if (DBG_CRYPTO)
202 log_debug ("skey: ");
203 gcry_sexp_dump (s_skey);
206 /* sign */
207 rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
208 gcry_sexp_release (s_hash);
209 if (rc)
211 log_error ("signing failed: %s\n", gpg_strerror (rc));
212 goto leave;
215 if (DBG_CRYPTO)
217 log_debug ("result: ");
218 gcry_sexp_dump (s_sig);
222 leave:
224 *signature_sexp = s_sig;
226 gcry_sexp_release (s_skey);
227 xfree (shadow_info);
229 return rc;
232 /* SIGN whatever information we have accumulated in CTRL and write it
233 back to OUTFP. */
235 agent_pksign (ctrl_t ctrl, const char *desc_text,
236 membuf_t *outbuf, cache_mode_t cache_mode)
238 gcry_sexp_t s_sig = NULL;
239 char *buf = NULL;
240 size_t len = 0;
241 int rc = 0;
243 rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode);
244 if (rc)
245 goto leave;
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);
253 put_membuf (outbuf, buf, len);
255 leave:
256 gcry_sexp_release (s_sig);
257 xfree (buf);
259 return rc;