Line data Source code
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://www.gnu.org/licenses/>.
18 : */
19 :
20 : #if HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <errno.h>
26 :
27 : #include "gpgme.h"
28 : #include "debug.h"
29 : #include "context.h"
30 : #include "ops.h"
31 : #include "util.h"
32 :
33 :
34 : typedef struct
35 : {
36 : /* The error code from a FAILURE status line or 0. */
37 : gpg_error_t failure_code;
38 :
39 : /* The error code from certain ERROR status lines or 0. */
40 : gpg_error_t error_code;
41 :
42 : } *op_data_t;
43 :
44 :
45 : static void
46 8 : release_op_data (void *hook)
47 : {
48 8 : op_data_t opd = (op_data_t) hook;
49 :
50 : (void)opd;
51 8 : }
52 :
53 :
54 : /* Parse an error status line. Return the error location and the
55 : error code. The function may modify ARGS. */
56 : static char *
57 0 : parse_error (char *args, gpg_error_t *r_err)
58 : {
59 0 : char *where = strchr (args, ' ');
60 : char *which;
61 :
62 0 : if (where)
63 : {
64 0 : *where = '\0';
65 0 : which = where + 1;
66 :
67 0 : where = strchr (which, ' ');
68 0 : if (where)
69 0 : *where = '\0';
70 :
71 0 : where = args;
72 : }
73 : else
74 : {
75 0 : *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE);
76 0 : return NULL;
77 : }
78 :
79 0 : *r_err = atoi (which);
80 :
81 0 : return where;
82 : }
83 :
84 :
85 : static gpgme_error_t
86 26 : keysign_status_handler (void *priv, gpgme_status_code_t code, char *args)
87 : {
88 26 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
89 : gpgme_error_t err;
90 : void *hook;
91 : op_data_t opd;
92 : char *loc;
93 :
94 : /* Pipe the status code through the progress status handler. */
95 26 : err = _gpgme_progress_status_handler (ctx, code, args);
96 26 : if (err)
97 0 : return err;
98 :
99 26 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook, -1, NULL);
100 26 : opd = hook;
101 26 : if (err)
102 0 : return err;
103 :
104 26 : switch (code)
105 : {
106 : case GPGME_STATUS_ERROR:
107 0 : loc = parse_error (args, &err);
108 0 : if (!loc)
109 0 : return err;
110 0 : if (!opd->error_code)
111 0 : opd->error_code = err;
112 0 : break;
113 :
114 : case GPGME_STATUS_FAILURE:
115 0 : opd->failure_code = _gpgme_parse_failure (args);
116 0 : break;
117 :
118 : case GPGME_STATUS_EOF:
119 8 : if (opd->error_code)
120 0 : return opd->error_code;
121 8 : else if (opd->failure_code)
122 0 : return opd->failure_code;
123 8 : break;
124 :
125 : case GPGME_STATUS_INQUIRE_MAXLEN:
126 0 : if (ctx->status_cb && !ctx->full_status)
127 : {
128 0 : err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
129 0 : if (err)
130 0 : return err;
131 : }
132 0 : break;
133 :
134 : default:
135 18 : break;
136 : }
137 26 : return 0;
138 : }
139 :
140 :
141 : /* Sign the USERID of KEY using the current set of signers. If USERID
142 : * is NULL, sign all user ids. To put several user ids into USERID,
143 : * separate them by LF and set the flag GPGME_KEYSIGN_LFSEP. */
144 : static gpgme_error_t
145 8 : keysign_start (gpgme_ctx_t ctx, int synchronous,
146 : gpgme_key_t key, const char *userid,
147 : unsigned long expires, unsigned int flags)
148 : {
149 : gpgme_error_t err;
150 : void *hook;
151 : op_data_t opd;
152 :
153 8 : if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
154 0 : return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
155 :
156 8 : err = _gpgme_op_reset (ctx, synchronous);
157 8 : if (err)
158 0 : return err;
159 :
160 8 : if (!key)
161 0 : return gpg_error (GPG_ERR_INV_ARG);
162 :
163 8 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYSIGN, &hook,
164 : sizeof (*opd), release_op_data);
165 8 : opd = hook;
166 8 : if (err)
167 0 : return err;
168 :
169 8 : _gpgme_engine_set_status_handler (ctx->engine, keysign_status_handler, ctx);
170 :
171 8 : if (ctx->passphrase_cb)
172 : {
173 0 : err = _gpgme_engine_set_command_handler
174 : (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
175 0 : if (err)
176 0 : return err;
177 : }
178 :
179 8 : return _gpgme_engine_op_keysign (ctx->engine,
180 : key, userid, expires, flags, ctx);
181 : }
182 :
183 :
184 : /* Sign the USERID of KEY using the current set of signers. */
185 : gpgme_error_t
186 0 : gpgme_op_keysign_start (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
187 : unsigned long expires, unsigned int flags)
188 : {
189 : gpgme_error_t err;
190 :
191 0 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign_start", ctx,
192 : "key=%p, uid='%s' flags=0x%x", key, userid, flags);
193 :
194 0 : if (!ctx)
195 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
196 :
197 0 : err = keysign_start (ctx, 0, key, userid, expires, flags);
198 0 : return TRACE_ERR (err);
199 : }
200 :
201 :
202 : gpgme_error_t
203 8 : gpgme_op_keysign (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid,
204 : unsigned long expires, unsigned int flags)
205 : {
206 : gpgme_error_t err;
207 :
208 8 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_keysign", ctx,
209 : "key=%p, uid='%s' flags=0x%x", key, userid, flags);
210 :
211 8 : if (!ctx)
212 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
213 :
214 8 : err = keysign_start (ctx, 1, key, userid, expires, flags);
215 8 : if (!err)
216 8 : err = _gpgme_wait_one (ctx);
217 8 : return TRACE_ERR (err);
218 : }
|