2003-04-28 Marcus Brinkmann <marcus@g10code.de>
[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   GpgmeData 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 GpgmeGenKeyResult
54 gpgme_op_genkey_result (GpgmeCtx ctx)
55 {
56   op_data_t opd;
57   GpgmeError err;
58
59   err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &opd, -1, NULL);
60   if (err || !opd)
61     return NULL;
62
63   return &opd->result;
64 }
65
66 \f
67 static GpgmeError
68 genkey_status_handler (void *priv, GpgmeStatusCode code, char *args)
69 {
70   GpgmeCtx ctx = (GpgmeCtx) priv;
71   GpgmeError err;
72   op_data_t opd;
73
74   /* Pipe the status code through the progress status handler.  */
75   err = _gpgme_progress_status_handler (ctx, code, args);
76   if (err)
77     return err;
78
79   err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &opd,
80                                -1, NULL);
81   if (err)
82     return err;
83
84   switch (code)
85     {
86     case GPGME_STATUS_KEY_CREATED:
87       if (args && *args)
88         {
89           if (*args == 'B' || *args == 'P')
90             opd->result.primary = 1;
91           if (*args == 'B' || *args == 'S')
92             opd->result.sub = 1;
93           if (args[1] == ' ')
94             {
95               if (opd->result.fpr)
96                 free (opd->result.fpr);
97               opd->result.fpr = strdup (&args[2]);
98               if (!opd->result.fpr)
99                 return GPGME_Out_Of_Core;
100             }
101         }
102       break;
103
104     case GPGME_STATUS_EOF:
105       /* FIXME: Should return some more useful error value.  */
106       if (!opd->result.primary && !opd->result.sub)
107         return GPGME_General_Error;
108       break;
109
110     default:
111       break;
112     }
113   return 0;
114 }
115
116
117 static GpgmeError
118 get_key_parameter (const char *parms, GpgmeData *key_parameter)
119 {
120   const char *content;
121   const char *attrib;
122   const char *endtag;
123
124   /* Extract the key parameter from the XML structure.  */
125   parms = strstr (parms, "<GnupgKeyParms ");
126   if (!parms)
127     return GPGME_Invalid_Value;
128
129   content = strchr (parms, '>');
130   if (!content)
131     return GPGME_Invalid_Value;
132   content++;
133
134   attrib = strstr (parms, "format=\"internal\"");
135   if (!attrib || attrib >= content)
136     return GPGME_Invalid_Value;
137
138   endtag = strstr (content, "</GnupgKeyParms>");
139   /* FIXME: Check that there are no control statements inside.  */
140   while (*content == '\n')
141     content++;
142
143   return gpgme_data_new_from_mem (key_parameter, content,
144                                   endtag - content, 0);
145 }
146
147
148 static GpgmeError
149 genkey_start (GpgmeCtx ctx, int synchronous, const char *parms,
150               GpgmeData pubkey, GpgmeData seckey)
151 {
152   GpgmeError err;
153   op_data_t opd;
154   err = _gpgme_op_reset (ctx, synchronous);
155   if (err)
156     return err;
157   
158   err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &opd,
159                                sizeof (*opd), release_op_data);
160   if (err)
161     return err;
162
163   err = get_key_parameter (parms, &opd->key_parameter);
164   if (err)
165     return err;
166
167   _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
168
169   return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
170                                   ctx->use_armor, pubkey, seckey);
171 }
172
173
174 /* Generate a new keypair and add it to the keyring.  PUBKEY and
175    SECKEY should be null for now.  PARMS specifies what keys should be
176    generated.  */
177 GpgmeError
178 gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
179                        GpgmeData pubkey, GpgmeData seckey)
180 {
181   return genkey_start (ctx, 0, parms, pubkey, seckey);
182 }
183
184
185 /* Generate a new keypair and add it to the keyring.  PUBKEY and
186    SECKEY should be null for now.  PARMS specifies what keys should be
187    generated.  */
188 GpgmeError
189 gpgme_op_genkey (GpgmeCtx ctx, const char *parms, GpgmeData pubkey,
190                  GpgmeData seckey)
191 {
192   GpgmeError err;
193
194   err = genkey_start (ctx, 1, parms, pubkey, seckey);
195   if (!err)
196     err = _gpgme_wait_one (ctx);
197   return err;
198 }