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,
36 do_encode_md (const byte
* md
, size_t mdlen
, int algo
, gcry_sexp_t
* r_hash
,
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
]);
56 rc
= gcry_sexp_build (&hash
, NULL
,
57 "(data (flags pkcs1) (hash %s %b))",
64 rc
= gcry_mpi_scan (&mpi
, GCRYMPI_FMT_USG
, md
, mdlen
, NULL
);
67 rc
= gcry_sexp_build (&hash
, NULL
,
68 "(data (flags raw) (value %m))",
70 gcry_mpi_release (mpi
);
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. */
85 do_encode_raw_pkcs1 (const byte
*md
, size_t mdlen
, unsigned int nbits
,
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
);
102 return gpg_error_from_syserror ();
104 /* Assemble the pkcs#1 block type 1. */
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
);
113 memcpy (frame
+n
, md
, mdlen
);
115 assert (n
== nframe
);
117 /* Create the S-expression. */
118 rc
= gcry_sexp_build (&hash
, NULL
,
119 "(data (flags raw) (value %b))",
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
);
146 log_error ("failed to read the secret key\n");
152 /* Divert operation to the smartcard */
154 unsigned char *buf
= NULL
;
157 rc
= divert_pksign (ctrl
,
159 ctrl
->digest
.valuelen
,
164 log_error ("smartcard signing failed: %s\n", gpg_strerror (rc
));
167 len
= gcry_sexp_canon_len (buf
, 0, NULL
, NULL
);
170 rc
= gcry_sexp_sscan (&s_sig
, NULL
, (char*)buf
, len
);
174 log_error ("failed to convert sigbuf returned by divert_pksign "
175 "into S-Exp: %s", gpg_strerror (rc
));
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
),
192 rc
= do_encode_md (ctrl
->digest
.value
,
193 ctrl
->digest
.valuelen
,
196 ctrl
->digest
.raw_value
);
202 log_debug ("skey: ");
203 gcry_sexp_dump (s_skey
);
207 rc
= gcry_pk_sign (&s_sig
, s_hash
, s_skey
);
208 gcry_sexp_release (s_hash
);
211 log_error ("signing failed: %s\n", gpg_strerror (rc
));
217 log_debug ("result: ");
218 gcry_sexp_dump (s_sig
);
224 *signature_sexp
= s_sig
;
226 gcry_sexp_release (s_skey
);
232 /* SIGN whatever information we have accumulated in CTRL and write it
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
;
243 rc
= agent_pksign_do (ctrl
, desc_text
, &s_sig
, cache_mode
);
247 len
= gcry_sexp_sprint (s_sig
, GCRYSEXP_FMT_CANON
, NULL
, 0);
250 len
= gcry_sexp_sprint (s_sig
, GCRYSEXP_FMT_CANON
, buf
, len
);
253 put_membuf (outbuf
, buf
, len
);
256 gcry_sexp_release (s_sig
);