Line data Source code
1 : /* genkey.c - Key generation.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
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.
11 :
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.
16 :
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
20 : 02111-1307, USA. */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <stdlib.h>
26 : #include <string.h>
27 : #include <errno.h>
28 :
29 : #include "gpgme.h"
30 : #include "debug.h"
31 : #include "context.h"
32 : #include "ops.h"
33 : #include "util.h"
34 :
35 :
36 : typedef struct
37 : {
38 : struct _gpgme_op_genkey_result result;
39 :
40 : /* The error code from a FAILURE status line or 0. */
41 : gpg_error_t failure_code;
42 :
43 : /* The key parameters passed to the crypto engine. */
44 : gpgme_data_t key_parameter;
45 : } *op_data_t;
46 :
47 :
48 : static void
49 1 : release_op_data (void *hook)
50 : {
51 1 : op_data_t opd = (op_data_t) hook;
52 :
53 1 : if (opd->result.fpr)
54 1 : free (opd->result.fpr);
55 1 : if (opd->key_parameter)
56 1 : gpgme_data_release (opd->key_parameter);
57 1 : }
58 :
59 :
60 : gpgme_genkey_result_t
61 0 : gpgme_op_genkey_result (gpgme_ctx_t ctx)
62 : {
63 : void *hook;
64 : op_data_t opd;
65 : gpgme_error_t err;
66 :
67 0 : TRACE_BEG (DEBUG_CTX, "gpgme_op_genkey_result", ctx);
68 :
69 0 : err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL);
70 0 : opd = hook;
71 0 : if (err || !opd)
72 : {
73 0 : TRACE_SUC0 ("result=(null)");
74 0 : return NULL;
75 : }
76 :
77 0 : TRACE_LOG3 ("fpr = %s, %s, %s", opd->result.fpr,
78 : opd->result.primary ? "primary" : "no primary",
79 : opd->result.sub ? "sub" : "no sub");
80 :
81 0 : TRACE_SUC1 ("result=%p", &opd->result);
82 0 : return &opd->result;
83 : }
84 :
85 :
86 : static gpgme_error_t
87 56 : genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
88 : {
89 56 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
90 : gpgme_error_t err;
91 : void *hook;
92 : op_data_t opd;
93 :
94 : /* Pipe the status code through the progress status handler. */
95 56 : err = _gpgme_progress_status_handler (ctx, code, args);
96 56 : if (err)
97 0 : return err;
98 :
99 56 : err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL);
100 56 : opd = hook;
101 56 : if (err)
102 0 : return err;
103 :
104 56 : switch (code)
105 : {
106 : case GPGME_STATUS_KEY_CREATED:
107 2 : if (args && *args)
108 : {
109 2 : if (*args == 'B' || *args == 'P')
110 2 : opd->result.primary = 1;
111 2 : if (*args == 'B' || *args == 'S')
112 0 : opd->result.sub = 1;
113 2 : if (args[1] == ' ')
114 : {
115 2 : if (opd->result.fpr)
116 0 : free (opd->result.fpr);
117 2 : opd->result.fpr = strdup (&args[2]);
118 2 : if (!opd->result.fpr)
119 0 : return gpg_error_from_syserror ();
120 : }
121 : }
122 2 : break;
123 :
124 : case GPGME_STATUS_FAILURE:
125 0 : opd->failure_code = _gpgme_parse_failure (args);
126 0 : break;
127 :
128 : case GPGME_STATUS_EOF:
129 : /* FIXME: Should return some more useful error value. */
130 2 : if (!opd->result.primary && !opd->result.sub)
131 0 : return gpg_error (GPG_ERR_GENERAL);
132 2 : else if (opd->failure_code)
133 0 : return opd->failure_code;
134 2 : break;
135 :
136 : case GPGME_STATUS_INQUIRE_MAXLEN:
137 0 : if (ctx->status_cb && !ctx->full_status)
138 : {
139 0 : err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
140 0 : if (err)
141 0 : return err;
142 : }
143 0 : break;
144 :
145 : default:
146 52 : break;
147 : }
148 56 : return 0;
149 : }
150 :
151 :
152 : static gpgme_error_t
153 2 : get_key_parameter (const char *parms, gpgme_data_t *key_parameter)
154 : {
155 : const char *content;
156 : const char *attrib;
157 : const char *endtag;
158 :
159 : /* Extract the key parameter from the XML structure. */
160 2 : parms = strstr (parms, "<GnupgKeyParms ");
161 2 : if (!parms)
162 0 : return gpg_error (GPG_ERR_INV_VALUE);
163 :
164 2 : content = strchr (parms, '>');
165 2 : if (!content)
166 0 : return gpg_error (GPG_ERR_INV_VALUE);
167 2 : content++;
168 :
169 2 : attrib = strstr (parms, "format=\"internal\"");
170 2 : if (!attrib || attrib >= content)
171 0 : return gpg_error (GPG_ERR_INV_VALUE);
172 :
173 2 : endtag = strstr (content, "</GnupgKeyParms>");
174 : /* FIXME: Check that there are no control statements inside. */
175 6 : while (content[0] == '\n'
176 2 : || (content[0] == '\r' && content[1] == '\n'))
177 2 : content++;
178 :
179 2 : return gpgme_data_new_from_mem (key_parameter, content,
180 2 : endtag - content, 1);
181 : }
182 :
183 :
184 : static gpgme_error_t
185 2 : genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms,
186 : gpgme_data_t pubkey, gpgme_data_t seckey)
187 : {
188 : gpgme_error_t err;
189 : void *hook;
190 : op_data_t opd;
191 2 : err = _gpgme_op_reset (ctx, synchronous);
192 2 : if (err)
193 0 : return err;
194 :
195 2 : err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
196 : sizeof (*opd), release_op_data);
197 2 : opd = hook;
198 2 : if (err)
199 0 : return err;
200 :
201 2 : err = get_key_parameter (parms, &opd->key_parameter);
202 2 : if (err)
203 0 : return err;
204 :
205 2 : _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
206 :
207 2 : if (ctx->passphrase_cb)
208 : {
209 0 : err = _gpgme_engine_set_command_handler
210 : (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
211 0 : if (err)
212 0 : return err;
213 : }
214 :
215 2 : return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
216 2 : ctx->use_armor, pubkey, seckey);
217 : }
218 :
219 :
220 : /* Generate a new keypair and add it to the keyring. PUBKEY and
221 : SECKEY should be null for now. PARMS specifies what keys should be
222 : generated. */
223 : gpgme_error_t
224 0 : gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
225 : gpgme_data_t pubkey, gpgme_data_t seckey)
226 : {
227 : gpgme_error_t err;
228 :
229 0 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_genkey_start", ctx,
230 : "pubkey=%p, seckey=%p", pubkey, seckey);
231 0 : TRACE_LOGBUF (parms, strlen (parms));
232 :
233 0 : if (!ctx)
234 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
235 :
236 0 : err = genkey_start (ctx, 0, parms, pubkey, seckey);
237 0 : return TRACE_ERR (err);
238 : }
239 :
240 :
241 : /* Generate a new keypair and add it to the keyring. PUBKEY and
242 : SECKEY should be null for now. PARMS specifies what keys should be
243 : generated. */
244 : gpgme_error_t
245 2 : gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey,
246 : gpgme_data_t seckey)
247 : {
248 : gpgme_error_t err;
249 :
250 2 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_genkey", ctx,
251 : "pubkey=%p, seckey=%p", pubkey, seckey);
252 2 : TRACE_LOGBUF (parms, strlen (parms));
253 :
254 2 : if (!ctx)
255 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
256 :
257 2 : err = genkey_start (ctx, 1, parms, pubkey, seckey);
258 2 : if (!err)
259 2 : err = _gpgme_wait_one (ctx);
260 2 : return TRACE_ERR (err);
261 : }
|