1 /* sign.c - Signing function.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
5 This file is part of GPGME.
7 GPGME is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
12 GPGME is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
29 /* Suppress warning for accessing deprecated member "class". */
30 #define _GPGME_IN_GPGME 1
40 struct _gpgme_op_sign_result result;
42 /* A pointer to the next pointer of the last invalid signer in
43 the list. This makes appending new invalid signers painless
44 while preserving the order. */
45 gpgme_invalid_key_t *last_signer_p;
47 /* Likewise for signature information. */
48 gpgme_new_signature_t *last_sig_p;
50 /* Flags used while processing the status lines. */
51 unsigned int ignore_inv_recp:1;
52 unsigned int inv_sgnr_seen:1;
53 unsigned int sig_created_seen:1;
58 release_op_data (void *hook)
60 op_data_t opd = (op_data_t) hook;
61 gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
62 gpgme_new_signature_t sig = opd->result.signatures;
64 while (invalid_signer)
66 gpgme_invalid_key_t next = invalid_signer->next;
67 if (invalid_signer->fpr)
68 free (invalid_signer->fpr);
69 free (invalid_signer);
70 invalid_signer = next;
75 gpgme_new_signature_t next = sig->next;
84 gpgme_op_sign_result (gpgme_ctx_t ctx)
90 TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx);
92 err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
96 TRACE_SUC0 ("result=(null)");
100 if (_gpgme_debug_trace ())
102 gpgme_invalid_key_t inv_key = opd->result.invalid_signers;
103 gpgme_new_signature_t sig = opd->result.signatures;
110 inv_key = inv_key->next;
118 TRACE_LOG2 ("result: invalid signers: %i, signatures: %i",
119 inv_signers, signatures);
120 inv_key = opd->result.invalid_signers;
123 TRACE_LOG3 ("result: invalid signer: fpr=%s, reason=%s <%s>",
124 inv_key->fpr, gpgme_strerror (inv_key->reason),
125 gpgme_strsource (inv_key->reason));
126 inv_key = inv_key->next;
128 sig = opd->result.signatures;
131 TRACE_LOG6 ("result: signature: type=%i, pubkey_algo=%i, "
132 "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
133 sig->type, sig->pubkey_algo, sig->hash_algo,
134 sig->timestamp, sig->fpr, sig->sig_class);
139 TRACE_SUC1 ("result=%p", &opd->result);
145 parse_sig_created (char *args, gpgme_new_signature_t *sigp)
147 gpgme_new_signature_t sig;
150 sig = malloc (sizeof (*sig));
152 return gpg_error_from_errno (errno);
158 sig->type = GPGME_SIG_MODE_NORMAL;
162 sig->type = GPGME_SIG_MODE_DETACH;
166 sig->type = GPGME_SIG_MODE_CLEAR;
170 /* The backend engine is not behaving. */
172 return gpg_error (GPG_ERR_INV_ENGINE);
179 return gpg_error (GPG_ERR_INV_ENGINE);
183 sig->pubkey_algo = strtol (args, &tail, 0);
184 if (errno || args == tail || *tail != ' ')
186 /* The crypto backend does not behave. */
188 return gpg_error (GPG_ERR_INV_ENGINE);
192 sig->hash_algo = strtol (args, &tail, 0);
193 if (errno || args == tail || *tail != ' ')
195 /* The crypto backend does not behave. */
197 return gpg_error (GPG_ERR_INV_ENGINE);
201 sig->sig_class = strtol (args, &tail, 0);
202 sig->class = sig->sig_class;
203 sig->_obsolete_class = sig->sig_class;
204 if (errno || args == tail || *tail != ' ')
206 /* The crypto backend does not behave. */
208 return gpg_error (GPG_ERR_INV_ENGINE);
212 sig->timestamp = _gpgme_parse_timestamp (args, &tail);
213 if (sig->timestamp == -1 || args == tail || *tail != ' ')
215 /* The crypto backend does not behave. */
217 return gpg_error (GPG_ERR_INV_ENGINE);
225 /* The crypto backend does not behave. */
227 return gpg_error (GPG_ERR_INV_ENGINE);
230 tail = strchr (args, ' ');
234 sig->fpr = strdup (args);
237 int saved_errno = errno;
239 return gpg_error_from_errno (saved_errno);
247 _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
249 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
254 err = _gpgme_passphrase_status_handler (priv, code, args);
258 err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
265 case GPGME_STATUS_SIG_CREATED:
266 opd->sig_created_seen = 1;
267 err = parse_sig_created (args, opd->last_sig_p);
271 opd->last_sig_p = &(*opd->last_sig_p)->next;
274 case GPGME_STATUS_INV_RECP:
275 if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
278 case GPGME_STATUS_INV_SGNR:
279 if (code == GPGME_STATUS_INV_SGNR)
280 opd->inv_sgnr_seen = 1;
281 err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
285 opd->last_signer_p = &(*opd->last_signer_p)->next;
288 case GPGME_STATUS_EOF:
289 if (opd->result.invalid_signers)
290 err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
291 else if (!opd->sig_created_seen)
292 err = gpg_error (GPG_ERR_GENERAL);
303 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
307 err = _gpgme_progress_status_handler (priv, code, args);
309 err = _gpgme_sign_status_handler (priv, code, args);
315 sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
321 err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
322 sizeof (*opd), release_op_data);
326 opd->last_signer_p = &opd->result.invalid_signers;
327 opd->last_sig_p = &opd->result.signatures;
328 opd->ignore_inv_recp = !!ignore_inv_recp;
329 opd->inv_sgnr_seen = 0;
330 opd->sig_created_seen = 0;
335 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
337 return sign_init_result (ctx, 0);
342 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
343 gpgme_data_t sig, gpgme_sig_mode_t mode)
347 err = _gpgme_op_reset (ctx, synchronous);
351 /* If we are using the CMS protocol, we ignore the INV_RECP status
352 code if a newer GPGSM is in use. GPGMS does not support combined
353 sign+encrypt and thus this can't harm. */
354 err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
358 if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
359 && mode != GPGME_SIG_MODE_CLEAR)
360 return gpg_error (GPG_ERR_INV_VALUE);
363 return gpg_error (GPG_ERR_NO_DATA);
365 return gpg_error (GPG_ERR_INV_VALUE);
367 if (ctx->passphrase_cb)
369 err = _gpgme_engine_set_command_handler
370 (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
375 _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
378 return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
379 ctx->use_textmode, ctx->include_certs,
384 /* Sign the plaintext PLAIN and store the signature in SIG. */
386 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
387 gpgme_sig_mode_t mode)
389 TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
390 "plain=%p, sig=%p, mode=%i", plain, sig, mode);
391 return TRACE_ERR (sign_start (ctx, 0, plain, sig, mode));
395 /* Sign the plaintext PLAIN and store the signature in SIG. */
397 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
398 gpgme_sig_mode_t mode)
402 TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
403 "plain=%p, sig=%p, mode=%i", plain, sig, mode);
404 err = sign_start (ctx, 1, plain, sig, mode);
406 err = _gpgme_wait_one (ctx);
407 return TRACE_ERR (err);