Added support for encrypted private key files. The passphrase
[silc.git] / lib / silcutil / silcapputil.c
1 /*
2
3   silcapputil.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22
23 static char *silc_create_pk_identifier(void)
24 {
25   char *username = NULL, *realname = NULL;
26   char *hostname, email[256];
27   char *ident;
28   
29   /* Get realname */
30   realname = silc_get_real_name();
31
32   /* Get hostname */
33   hostname = silc_net_localhost();
34   if (!hostname)
35     return NULL;
36
37   /* Get username (mandatory) */
38   username = silc_get_username();
39   if (!username)
40     return NULL;
41
42   /* Create default email address, whether it is right or not */
43   snprintf(email, sizeof(email), "%s@%s", username, hostname);
44
45   ident = silc_pkcs_encode_identifier(username, hostname, realname, email,
46                                       NULL, NULL);
47   if (realname)
48     silc_free(realname);
49   silc_free(hostname);
50   silc_free(username);
51
52   return ident;
53 }
54
55 /* Generate key pair */
56
57 bool silc_create_key_pair(const char *pkcs_name,
58                           SilcUInt32 key_len_bits,
59                           const char *pub_filename,
60                           const char *prv_filename,
61                           const char *pub_identifier,
62                           const char *passphrase,
63                           SilcPKCS *return_pkcs,
64                           SilcPublicKey *return_public_key,
65                           SilcPrivateKey *return_private_key,
66                           bool interactive)
67 {
68   SilcPKCS pkcs;
69   SilcPublicKey pub_key;
70   SilcPrivateKey prv_key;
71   SilcRng rng;
72   unsigned char *key;
73   SilcUInt32 key_len;
74   char line[256];
75   char *pkfile = pub_filename ? strdup(pub_filename) : NULL;
76   char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
77   char *alg = pkcs_name ? strdup(pkcs_name) : NULL;
78   char *identifier = pub_identifier ? strdup(pub_identifier) : NULL;
79   char *pass = passphrase ? strdup(passphrase) : NULL;
80
81   if (interactive && (!alg || !pub_filename || !prv_filename))
82     printf("\
83 New pair of keys will be created.  Please, answer to following questions.\n\
84 ");
85
86   if (!alg) {
87     if (interactive) {
88       while (!alg) {
89         alg = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
90         if (!alg)
91           alg = strdup("rsa");
92     
93         if (*alg == 'l' || *alg == 'L') {
94           char *list = silc_pkcs_get_supported();
95           printf("%s\n", list);
96           silc_free(list);
97           silc_free(alg);
98           alg = NULL;
99         }
100       }
101     } else {
102       alg = strdup("rsa");
103     }
104   }
105
106   if (!silc_pkcs_is_supported(alg)) {
107     fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library"
108             "is not initialized", alg);
109     return FALSE;
110   }
111
112   if (!key_len_bits) {
113     if (interactive) {
114       char *length = NULL;
115       length = silc_get_input("Key length in key_len_bits [2048]: ", FALSE);
116       if (length)
117         key_len_bits = atoi(length);
118       silc_free(length);
119     }
120     if (!key_len_bits)
121       key_len_bits = 2048;
122   }
123
124   if (!identifier) {
125     char *def = silc_create_pk_identifier();
126
127     if (interactive) {
128       memset(line, 0, sizeof(line));
129       if (def)
130         snprintf(line, sizeof(line), "Identifier [%s]: ", def);
131       else
132         snprintf(line, sizeof(line),
133                "Identifier (eg. UN=jon, HN=jon.dummy.com, "
134                "RN=Jon Johnson, E=jon@dummy.com): ");
135
136       while (!identifier) {
137         identifier = silc_get_input(line, FALSE);
138         if (!identifier && def)
139           identifier = strdup(def);
140       }
141     } else {
142       if (!def) {
143         fprintf(stderr, "Could not create public key identifier: %s\n",
144                 strerror(errno));
145         return FALSE;
146       }
147       identifier = strdup(def);
148     }
149
150     silc_free(def);
151   }
152
153   rng = silc_rng_alloc();
154   silc_rng_init(rng);
155   silc_rng_global_init(rng);
156
157   if (!pkfile) {
158     if (interactive) {
159       memset(line, 0, sizeof(line));
160       snprintf(line, sizeof(line), "Public key filename [public_key.pub]: ");
161       pkfile = silc_get_input(line, FALSE);
162     }
163     if (!pkfile)
164       pkfile = strdup("public_key.pub");
165   }
166
167   if (!prvfile) {
168     if (interactive) {
169       memset(line, 0, sizeof(line));
170       snprintf(line, sizeof(line), "Private key filename [private_key.prv]: ");
171       prvfile = silc_get_input(line, FALSE);
172     }
173     if (!prvfile)
174       prvfile = strdup("private_key.prv");
175   }
176
177   if (!pass) {
178     memset(line, 0, sizeof(line));
179     snprintf(line, sizeof(line), "Private key passphrase: ");
180     pass = silc_get_input(line, TRUE);
181     if (!pass)
182       pass = strdup("");
183   }
184
185   /* Generate keys */
186   silc_pkcs_alloc(alg, &pkcs);
187   silc_pkcs_generate_key(pkcs, key_len_bits, rng);
188
189   /* Save public key into file */
190   key = silc_pkcs_get_public_key(pkcs, &key_len);
191   pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs),
192                                        identifier, key, key_len);
193   silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
194   if (return_public_key)
195     *return_public_key = pub_key;
196   else
197     silc_pkcs_public_key_free(pub_key);
198   memset(key, 0, key_len);
199   silc_free(key);
200
201   /* Save private key into file */
202   key = silc_pkcs_get_private_key(pkcs, &key_len);
203   prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
204                                         key, key_len);
205   silc_pkcs_save_private_key(prvfile, prv_key,
206                              (unsigned char *)pass, strlen(pass),
207                              SILC_PKCS_FILE_BIN);
208   if (return_private_key)
209     *return_private_key = prv_key;
210   else
211     silc_pkcs_private_key_free(prv_key);
212   memset(key, 0, key_len);
213   silc_free(key);
214
215   printf("Public key has been saved into `%s'.\n", pkfile);
216   printf("Private key has been saved into `%s'.\n", prvfile);
217   if (interactive) {
218     printf("Press <Enter> to continue...\n");
219     getchar();
220   }
221
222   if (return_pkcs)
223     *return_pkcs = pkcs;
224   else
225     silc_pkcs_free(pkcs);
226
227   silc_rng_free(rng);
228   silc_free(alg);
229   silc_free(pkfile);
230   silc_free(prvfile);
231   silc_free(identifier);
232   memset(pass, 0, strlen(pass));
233   silc_free(pass);
234
235   return TRUE;
236 }
237
238 /* Load key pair */
239
240 bool silc_load_key_pair(const char *pub_filename,
241                         const char *prv_filename,
242                         const char *passphrase,
243                         SilcPKCS *return_pkcs,
244                         SilcPublicKey *return_public_key,
245                         SilcPrivateKey *return_private_key)
246 {
247   char *pass = passphrase ? strdup(passphrase) : NULL;
248
249   SILC_LOG_DEBUG(("Loading public and private keys"));
250
251   if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
252                                 SILC_PKCS_FILE_PEM) == FALSE)
253     if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
254                                   SILC_PKCS_FILE_BIN) == FALSE) {
255       memset(pass, 0, strlen(pass));
256       return FALSE;
257     }
258
259   if (!pass) {
260     pass = silc_get_input("Private key passphrase: ", TRUE);
261     if (!pass)
262       pass = strdup("");
263   }
264
265   if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
266                                  (unsigned char *)pass, strlen(pass),
267                                  SILC_PKCS_FILE_BIN) == FALSE)
268     if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
269                                    (unsigned char *)pass, strlen(pass),
270                                    SILC_PKCS_FILE_PEM) == FALSE) {
271       memset(pass, 0, strlen(pass));
272       return FALSE;
273     }
274
275   if (return_pkcs) {
276     silc_pkcs_alloc((*return_public_key)->name, return_pkcs);
277     silc_pkcs_public_key_set(*return_pkcs, *return_public_key);
278     silc_pkcs_private_key_set(*return_pkcs, *return_private_key);
279   }
280
281   memset(pass, 0, strlen(pass));
282   return TRUE;
283 }
284
285 /* Dump public key into stdout */
286
287 bool silc_show_public_key(const char *pub_filename)
288 {
289   SilcPublicKey public_key;
290   SilcPublicKeyIdentifier ident;
291   char *fingerprint, *babbleprint;
292   unsigned char *pk;
293   SilcUInt32 pk_len;
294   SilcPKCS pkcs;
295   SilcUInt32 key_len = 0;
296
297   if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
298                                 SILC_PKCS_FILE_PEM) == FALSE)
299     if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
300                                   SILC_PKCS_FILE_BIN) == FALSE) {
301       fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
302       return FALSE;
303     }
304
305   ident = silc_pkcs_decode_identifier(public_key->identifier);
306
307   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
308   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
309   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
310
311   if (silc_pkcs_alloc(public_key->name, &pkcs)) {
312     key_len = silc_pkcs_public_key_set(pkcs, public_key);
313     silc_pkcs_free(pkcs);
314   }
315
316   printf("Public key file    : %s\n", pub_filename);
317   printf("Algorithm          : %s\n", public_key->name);
318   if (key_len)
319     printf("Key length (bits)  : %d\n", (unsigned int)key_len);
320   if (ident->realname)
321     printf("Real name          : %s\n", ident->realname);
322   if (ident->username)
323     printf("Username           : %s\n", ident->username);
324   if (ident->host)
325     printf("Hostname           : %s\n", ident->host);
326   if (ident->email)
327     printf("Email              : %s\n", ident->email);
328   if (ident->org)
329     printf("Organization       : %s\n", ident->org);
330   if (ident->country)
331     printf("Country            : %s\n", ident->country);
332   printf("Fingerprint (SHA1) : %s\n", fingerprint); 
333   printf("Babbleprint (SHA1) : %s\n", babbleprint); 
334
335   fflush(stdout);
336
337   silc_free(fingerprint);
338   silc_free(babbleprint);
339   silc_free(pk);
340   silc_pkcs_public_key_free(public_key);
341   silc_pkcs_free_identifier(ident);
342
343   return TRUE;
344 }