1 /* keysign.c - OpenPGP key signing
2 * Copyright (C) 2016 g10 Code GmbH
3 *
4 * This file is part of GPGME.
5 *
6 * GPGME is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * GPGME is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <https://gnu.org/licenses/>.
18 * SPDX-License-Identifier: LGPL-2.1-or-later
19 */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include "gpgme.h"
29 #include "debug.h"
30 #include "context.h"
31 #include "ops.h"
32 #include "util.h"
33
34
35 typedef struct
36 {
37 /* The error code from a FAILURE status line or 0. */
38 gpg_error_t failure_code;
39
40 /* The error code from certain ERROR status lines or 0. */
41 gpg_error_t error_code;
42
43 } *op_data_t;
44
45
46 static void
release_op_data(void * hook)47 release_op_data (void *hook)
48 {
49 op_data_t opd = (op_data_t) hook;
50
51 (void)opd;
52 }
53
54
55 /* Parse an error status line. Return the error location and the
56 error code. The function may modify ARGS. */
57 static char *
parse_error(char * args,gpg_error_t * r_err)58 parse_error (char *args, gpg_error_t *r_err)
59 {
60 char *where = strchr (args, ' ');
61 char *which;
62
63 if (where)
64 {
65 *where = '\0';
66 which = where + 1;
67
68 where = strchr (which, ' ');
69 if (where)
70 *where = '\0';
71
72 where = args;
73 }
74 else
75 {
76 *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
77 return NULL;
78 }
79
80 *r_err = atoi (which);
81
82 return where;
83 }
84
85
86 static gpgme_error_t
keysign_status_handler(void * priv,gpgme_status_code_t code,char * args)87 keysign_status_handler (void *priv, gpgme_status_code_t code, char *args)
88 {
89 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
90 gpgme_error_t err;
91 void *hook;
92 op_data_t opd;
93 char *loc;
94
95 /* Pipe the status code through the progress status handler. */
96 err = _gpgme_progress_status_handler (ctx, code, args);
97 if (err)
98 return err;
99
100 err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook, -1, NULL);
101 opd = hook;
102 if (err)
103 return err;
104
105 switch (code)
106 {
107 case GPGME_STATUS_ERROR:
108 loc = parse_error (args, &err);
109 if (!loc)
110 return err;
111 if (!opd->error_code)
112 opd->error_code = err;
113 break;
114
115 case GPGME_STATUS_FAILURE:
116 opd->failure_code = _gpgme_parse_failure (args);
117 break;
118
119 case GPGME_STATUS_EOF:
120 if (opd->error_code)
121 return opd->error_code;
122 else if (opd->failure_code)
123 return opd->failure_code;
124 break;
125
126 case GPGME_STATUS_INQUIRE_MAXLEN:
127 if (ctx->status_cb && !ctx->full_status)
128 {
129 err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
130 if (err)
131 return err;
132 }
133 break;
134
135 default:
136 break;
137 }
138 return 0;
139 }
140
141
142 /* Sign the USERID of KEY using the current set of signers. If USERID
143 * is NULL, sign all user ids. To put several user ids into USERID,
144 * separate them by LF and set the flag GPGME_KEYSIGN_LFSEP. */
145 static gpgme_error_t
keysign_start(gpgme_ctx_t ctx,int synchronous,gpgme_key_t key,const char * userid,unsigned long expires,unsigned int flags)146 keysign_start (gpgme_ctx_t ctx, int synchronous,
147 gpgme_key_t key, const char *userid,
148 unsigned long expires, unsigned int flags)
149 {
150 gpgme_error_t err;
151 void *hook;
152 op_data_t opd;
153
154 if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
155 return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
156
157 err = _gpgme_op_reset (ctx, synchronous);
158 if (err)
159 return err;
160
161 if (!key)
162 return gpg_error (GPG_ERR_INV_ARG);
163
164 err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook,
165 sizeof (*opd), release_op_data);
166 opd = hook;
167 if (err)
168 return err;
169
170 _gpgme_engine_set_status_handler (ctx->engine, keysign_status_handler, ctx);
171
172 if (ctx->passphrase_cb)
173 {
174 err = _gpgme_engine_set_command_handler
175 (ctx->engine, _gpgme_passphrase_command_handler, ctx);
176 if (err)
177 return err;
178 }
179
180 return _gpgme_engine_op_keysign (ctx->engine,
181 key, userid, expires, flags, ctx);
182 }
183
184
185 /* Sign the USERID of KEY using the current set of signers. */
186 gpgme_error_t
gpgme_op_keysign_start(gpgme_ctx_t ctx,gpgme_key_t key,const char * userid,unsigned long expires,unsigned int flags)187 gpgme_op_keysign_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
188 unsigned long expires, unsigned int flags)
189 {
190 gpgme_error_t err;
191
192 TRACE_BEG (DEBUG_CTX, "gpgme_op_keysign_start", ctx,
193 "key=%p, uid='%s' flags=0x%x", key, userid, flags);
194
195 if (!ctx)
196 return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
197
198 err = keysign_start (ctx, 0, key, userid, expires, flags);
199 return TRACE_ERR (err);
200 }
201
202
203 gpgme_error_t
gpgme_op_keysign(gpgme_ctx_t ctx,gpgme_key_t key,const char * userid,unsigned long expires,unsigned int flags)204 gpgme_op_keysign (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
205 unsigned long expires, unsigned int flags)
206 {
207 gpgme_error_t err;
208
209 TRACE_BEG (DEBUG_CTX, "gpgme_op_keysign", ctx,
210 "key=%p, uid='%s' flags=0x%x", key, userid, flags);
211
212 if (!ctx)
213 return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
214
215 err = keysign_start (ctx, 1, key, userid, expires, flags);
216 if (!err)
217 err = _gpgme_wait_one (ctx);
218 return TRACE_ERR (err);
219 }
220