0d5c52f9bad30b6edf89368c70c91aaf50d69ab5
[gpgme.git] / gpgme / genkey.c
1 /* genkey.c - Key generation.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 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 General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (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    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "gpgme.h"
28 #include "context.h"
29 #include "ops.h"
30
31 \f
32 typedef struct
33 {
34   struct _gpgme_op_genkey_result result;
35
36   /* The key parameters passed to the crypto engine.  */
37   gpgme_data_t key_parameter;
38 } *op_data_t;
39
40
41 static void
42 release_op_data (void *hook)
43 {
44   op_data_t opd = (op_data_t) hook;
45   
46   if (opd->result.fpr)
47     free (opd->result.fpr);
48   if (opd->key_parameter)
49     gpgme_data_release (opd->key_parameter);
50 }
51
52
53 gpgme_genkey_result_t
54 gpgme_op_genkey_result (gpgme_ctx_t ctx)
55 {
56   void *hook;
57   op_data_t opd;
58   gpgme_error_t err;
59
60   err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL);
61   opd = hook;
62   if (err || !opd)
63     return NULL;
64
65   return &opd->result;
66 }
67
68 \f
69 static gpgme_error_t
70 genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
71 {
72   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
73   gpgme_error_t err;
74   void *hook;
75   op_data_t opd;
76
77   /* Pipe the status code through the progress status handler.  */
78   err = _gpgme_progress_status_handler (ctx, code, args);
79   if (err)
80     return err;
81
82   err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL);
83   opd = hook;
84   if (err)
85     return err;
86
87   switch (code)
88     {
89     case GPGME_STATUS_KEY_CREATED:
90       if (args && *args)
91         {
92           if (*args == 'B' || *args == 'P')
93             opd->result.primary = 1;
94           if (*args == 'B' || *args == 'S')
95             opd->result.sub = 1;
96           if (args[1] == ' ')
97             {
98               if (opd->result.fpr)
99                 free (opd->result.fpr);
100               opd->result.fpr = strdup (&args[2]);
101               if (!opd->result.fpr)
102                 return GPGME_Out_Of_Core;
103             }
104         }
105       break;
106
107     case GPGME_STATUS_EOF:
108       /* FIXME: Should return some more useful error value.  */
109       if (!opd->result.primary && !opd->result.sub)
110         return GPGME_General_Error;
111       break;
112
113     default:
114       break;
115     }
116   return 0;
117 }
118
119
120 static gpgme_error_t
121 get_key_parameter (const char *parms, gpgme_data_t *key_parameter)
122 {
123   const char *content;
124   const char *attrib;
125   const char *endtag;
126
127   /* Extract the key parameter from the XML structure.  */
128   parms = strstr (parms, "<GnupgKeyParms ");
129   if (!parms)
130     return GPGME_Invalid_Value;
131
132   content = strchr (parms, '>');
133   if (!content)
134     return GPGME_Invalid_Value;
135   content++;
136
137   attrib = strstr (parms, "format=\"internal\"");
138   if (!attrib || attrib >= content)
139     return GPGME_Invalid_Value;
140
141   endtag = strstr (content, "</GnupgKeyParms>");
142   /* FIXME: Check that there are no control statements inside.  */
143   while (*content == '\n')
144     content++;
145
146   return gpgme_data_new_from_mem (key_parameter, content,
147                                   endtag - content, 0);
148 }
149
150
151 static gpgme_error_t
152 genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms,
153               gpgme_data_t pubkey, gpgme_data_t seckey)
154 {
155   gpgme_error_t err;
156   void *hook;
157   op_data_t opd;
158   err = _gpgme_op_reset (ctx, synchronous);
159   if (err)
160     return err;
161   
162   err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
163                                sizeof (*opd), release_op_data);
164   opd = hook;
165   if (err)
166     return err;
167
168   err = get_key_parameter (parms, &opd->key_parameter);
169   if (err)
170     return err;
171
172   _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
173
174   return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
175                                   ctx->use_armor, pubkey, seckey);
176 }
177
178
179 /* Generate a new keypair and add it to the keyring.  PUBKEY and
180    SECKEY should be null for now.  PARMS specifies what keys should be
181    generated.  */
182 gpgme_error_t
183 gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
184                        gpgme_data_t pubkey, gpgme_data_t seckey)
185 {
186   return genkey_start (ctx, 0, parms, pubkey, seckey);
187 }
188
189
190 /* Generate a new keypair and add it to the keyring.  PUBKEY and
191    SECKEY should be null for now.  PARMS specifies what keys should be
192    generated.  */
193 gpgme_error_t
194 gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey,
195                  gpgme_data_t seckey)
196 {
197   gpgme_error_t err;
198
199   err = genkey_start (ctx, 1, parms, pubkey, seckey);
200   if (!err)
201     err = _gpgme_wait_one (ctx);
202   return err;
203 }