* genkey.c: Store the secret part and return the public part.
[gnupg.git] / agent / genkey.c
1 /* pksign.c - Generate a keypair
2  *      Copyright (C) 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30
31 #include "agent.h"
32
33 static int
34 store_key (GCRY_SEXP private)
35 {
36   int i;
37   char *fname;
38   FILE *fp;
39   char *buf;
40   size_t len;
41   unsigned char grip[20];
42   char hexgrip[41];
43   
44   if ( !gcry_pk_get_keygrip (private, grip) )
45     {
46       log_error ("can't calculate keygrip\n");
47       return seterr (General_Error);
48     }
49   for (i=0; i < 20; i++)
50     sprintf (hexgrip+2*i, "%02X", grip[i]);
51   hexgrip[40] = 0;
52
53   fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
54   if (!access (fname, F_OK))
55     {
56       log_error ("secret key file `%s' already exists - very strange\n",
57                  fname);
58       xfree (fname);
59       return seterr (General_Error);
60     }
61   fp = fopen (fname, "wbx");
62   if (!fp)
63     {
64       log_error ("can't create `%s': %s\n", fname, strerror (errno));
65       xfree (fname);
66       return seterr (File_Create_Error);
67     }
68
69   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
70   assert (len);
71   buf = gcry_malloc_secure (len);
72   if (!buf)
73     {
74       fclose (fp);
75       remove (fname);
76       xfree (fname);
77       return seterr (Out_Of_Core);
78     }
79   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
80   assert (len);
81
82   if (fwrite (buf, len, 1, fp) != 1)
83     {
84       log_error ("error writing `%s': %s\n", fname, strerror (errno));
85       fclose (fp);
86       remove (fname);
87       xfree (fname);
88       xfree (buf);
89       return seterr (File_Create_Error);
90     }
91   if ( fclose (fp) )
92     {
93       log_error ("error closing `%s': %s\n", fname, strerror (errno));
94       remove (fname);
95       xfree (fname);
96       xfree (buf);
97       return seterr (File_Create_Error);
98     }
99
100   xfree (fname);
101   xfree (buf);
102   return 0;
103 }
104
105
106
107 /* Generate a new keypair according to the parameters given in
108    KEYPARAM */
109 int
110 agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
111               FILE *outfp) 
112 {
113   GCRY_SEXP s_keyparam, s_key, s_private, s_public;
114   int rc;
115   size_t len;
116   char *buf;
117
118   rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
119   if (rc)
120     {
121       log_error ("failed to convert keyparam: %s\n", gcry_strerror (rc));
122       return seterr (Invalid_Data);
123     }
124
125   /* fixme: Get the passphrase now, cause key generation may take a while */
126
127   rc = gcry_pk_genkey (&s_key, s_keyparam );
128   gcry_sexp_release (s_keyparam);
129   if (rc)
130     {
131       log_error ("key generation failed: %s\n", gcry_strerror (rc));
132       return map_gcry_err (rc);
133     }
134
135   /* break out the parts */
136   s_private = gcry_sexp_find_token (s_key, "private-key", 0);
137   if (!s_private)
138     {
139       log_error ("key generation failed: invalid return value\n");
140       gcry_sexp_release (s_key);
141       return seterr (Invalid_Data);
142     }
143   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
144   if (!s_public)
145     {
146       log_error ("key generation failed: invalid return value\n");
147       gcry_sexp_release (s_private);
148       gcry_sexp_release (s_key);
149       return seterr (Invalid_Data);
150     }
151   gcry_sexp_release (s_key); s_key = NULL;
152   
153   /* store the secret key */
154   log_debug ("storing private key\n");
155   rc = store_key (s_private);
156   gcry_sexp_release (s_private);
157   if (rc)
158     {
159       gcry_sexp_release (s_public);
160       return rc;
161     }
162
163   /* return the public key */
164   log_debug ("returning public key\n");
165   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
166   assert (len);
167   buf = xmalloc (len);
168   if (!buf)
169     {
170       gcry_sexp_release (s_private);
171       gcry_sexp_release (s_public);
172       return seterr (Out_Of_Core);
173     }
174   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
175   assert (len);
176   if (fwrite (buf, len, 1, outfp) != 1)
177     {
178       log_error ("error writing public key: %s\n", strerror (errno));
179       gcry_sexp_release (s_private);
180       gcry_sexp_release (s_public);
181       xfree (buf);
182       return seterr (File_Create_Error);
183     }
184   gcry_sexp_release (s_public);
185   xfree (buf);
186
187   return 0;
188 }
189