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