Merged silc_1_0_branch to trunk.
[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     char *pass2 = NULL;
179     pass = silc_get_input("Private key passphrase: ", TRUE);
180     if (!pass) {
181       pass = strdup("");
182     } else {
183       while (TRUE) {
184         printf("\n");
185         pass2 = silc_get_input("Retype private key passphrase: ", TRUE);
186         if (!pass2)
187           pass2 = strdup("");
188         if (!strcmp(pass, pass2))
189           break;
190         fprintf(stderr, "\nPassphrases do not match");
191       }
192       silc_free(pass2);
193     }
194   }
195
196   /* Generate keys */
197   silc_pkcs_alloc(alg, &pkcs);
198   silc_pkcs_generate_key(pkcs, key_len_bits, rng);
199
200   /* Save public key into file */
201   key = silc_pkcs_get_public_key(pkcs, &key_len);
202   pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs),
203                                        identifier, key, key_len);
204   silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
205   if (return_public_key)
206     *return_public_key = pub_key;
207   else
208     silc_pkcs_public_key_free(pub_key);
209   memset(key, 0, key_len);
210   silc_free(key);
211
212   /* Save private key into file */
213   key = silc_pkcs_get_private_key(pkcs, &key_len);
214   prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
215                                         key, key_len);
216   silc_pkcs_save_private_key(prvfile, prv_key,
217                              (unsigned char *)pass, strlen(pass),
218                              SILC_PKCS_FILE_BIN);
219   if (return_private_key)
220     *return_private_key = prv_key;
221   else
222     silc_pkcs_private_key_free(prv_key);
223   memset(key, 0, key_len);
224   silc_free(key);
225
226   printf("Public key has been saved into `%s'.\n", pkfile);
227   printf("Private key has been saved into `%s'.\n", prvfile);
228   if (interactive) {
229     printf("Press <Enter> to continue...\n");
230     getchar();
231   }
232
233   if (return_pkcs)
234     *return_pkcs = pkcs;
235   else
236     silc_pkcs_free(pkcs);
237
238   silc_rng_free(rng);
239   silc_free(alg);
240   silc_free(pkfile);
241   silc_free(prvfile);
242   silc_free(identifier);
243   memset(pass, 0, strlen(pass));
244   silc_free(pass);
245
246   return TRUE;
247 }
248
249 /* Load key pair */
250
251 bool silc_load_key_pair(const char *pub_filename,
252                         const char *prv_filename,
253                         const char *passphrase,
254                         SilcPKCS *return_pkcs,
255                         SilcPublicKey *return_public_key,
256                         SilcPrivateKey *return_private_key)
257 {
258   char *pass = passphrase ? strdup(passphrase) : NULL;
259
260   SILC_LOG_DEBUG(("Loading public and private keys"));
261
262   if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
263                                 SILC_PKCS_FILE_PEM) == FALSE)
264     if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
265                                   SILC_PKCS_FILE_BIN) == FALSE) {
266       if (pass)
267         memset(pass, 0, strlen(pass));
268       silc_free(pass);
269       return FALSE;
270     }
271
272   if (!pass) {
273     pass = silc_get_input("Private key passphrase: ", TRUE);
274     if (!pass)
275       pass = strdup("");
276   }
277
278   if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
279                                  (unsigned char *)pass, strlen(pass),
280                                  SILC_PKCS_FILE_BIN) == FALSE)
281     if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
282                                    (unsigned char *)pass, strlen(pass),
283                                    SILC_PKCS_FILE_PEM) == FALSE) {
284       memset(pass, 0, strlen(pass));
285       silc_free(pass);
286       return FALSE;
287     }
288
289   if (return_pkcs) {
290     silc_pkcs_alloc((*return_public_key)->name, return_pkcs);
291     silc_pkcs_public_key_set(*return_pkcs, *return_public_key);
292     silc_pkcs_private_key_set(*return_pkcs, *return_private_key);
293   }
294
295   memset(pass, 0, strlen(pass));
296   silc_free(pass);
297   return TRUE;
298 }
299
300 /* Dump public key into stdout */
301
302 bool silc_show_public_key(const char *pub_filename)
303 {
304   SilcPublicKey public_key;
305   SilcPublicKeyIdentifier ident;
306   char *fingerprint, *babbleprint;
307   unsigned char *pk;
308   SilcUInt32 pk_len;
309   SilcPKCS pkcs;
310   SilcUInt32 key_len = 0;
311
312   if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
313                                 SILC_PKCS_FILE_PEM) == FALSE)
314     if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
315                                   SILC_PKCS_FILE_BIN) == FALSE) {
316       fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
317       return FALSE;
318     }
319
320   ident = silc_pkcs_decode_identifier(public_key->identifier);
321
322   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
323   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
324   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
325
326   if (silc_pkcs_alloc(public_key->name, &pkcs)) {
327     key_len = silc_pkcs_public_key_set(pkcs, public_key);
328     silc_pkcs_free(pkcs);
329   }
330
331   printf("Public key file    : %s\n", pub_filename);
332   printf("Algorithm          : %s\n", public_key->name);
333   if (key_len)
334     printf("Key length (bits)  : %d\n", (unsigned int)key_len);
335   if (ident->realname)
336     printf("Real name          : %s\n", ident->realname);
337   if (ident->username)
338     printf("Username           : %s\n", ident->username);
339   if (ident->host)
340     printf("Hostname           : %s\n", ident->host);
341   if (ident->email)
342     printf("Email              : %s\n", ident->email);
343   if (ident->org)
344     printf("Organization       : %s\n", ident->org);
345   if (ident->country)
346     printf("Country            : %s\n", ident->country);
347   printf("Fingerprint (SHA1) : %s\n", fingerprint); 
348   printf("Babbleprint (SHA1) : %s\n", babbleprint); 
349
350   fflush(stdout);
351
352   silc_free(fingerprint);
353   silc_free(babbleprint);
354   silc_free(pk);
355   silc_pkcs_public_key_free(public_key);
356   silc_pkcs_free_identifier(ident);
357
358   return TRUE;
359 }
360
361 /* Change private key passphrase */
362
363 bool silc_change_private_key_passphrase(const char *prv_filename,
364                                         const char *old_passphrase,
365                                         const char *new_passphrase)
366 {
367   SilcPrivateKey private_key;
368   bool base64 = FALSE;
369   char *pass;
370
371   pass = old_passphrase ? strdup(old_passphrase) : NULL;
372   if (!pass) {
373     pass = silc_get_input("Old passphrase: ", TRUE);
374     if (!pass)
375       pass = strdup("");
376   }
377
378   if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
379                                  (unsigned char *)pass, strlen(pass),
380                                  SILC_PKCS_FILE_BIN) == FALSE) {
381     base64 = TRUE;
382     if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
383                                    (unsigned char *)pass, strlen(pass),
384                                    SILC_PKCS_FILE_PEM) == FALSE) {
385       memset(pass, 0, strlen(pass));
386       silc_free(pass);
387       fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
388       return FALSE;
389     }
390   }
391
392   memset(pass, 0, strlen(pass));
393   silc_free(pass);
394
395   pass = new_passphrase ? strdup(new_passphrase) : NULL;
396   if (!pass) {
397     char *pass2 = NULL;
398     fprintf(stdout, "\n");
399     pass = silc_get_input("New passphrase: ", TRUE);
400     if (!pass) {
401       pass = strdup("");
402     } else {
403       while (TRUE) {
404         printf("\n");
405         pass2 = silc_get_input("Retype new passphrase: ", TRUE);
406         if (!pass2)
407           pass2 = strdup("");
408         if (!strcmp(pass, pass2))
409           break;
410         fprintf(stderr, "\nPassphrases do not match");
411       }
412       silc_free(pass2);
413     }
414   }
415
416   silc_pkcs_save_private_key((char *)prv_filename, private_key,
417                              (unsigned char *)pass, strlen(pass),
418                              base64 ? SILC_PKCS_FILE_PEM : SILC_PKCS_FILE_BIN);
419
420   fprintf(stdout, "\nPassphrase changed\n");
421
422   memset(pass, 0, strlen(pass));
423   silc_free(pass);
424
425   silc_pkcs_private_key_free(private_key);
426   return TRUE;
427 }