Warning fixes.
[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       if (pass)
256         memset(pass, 0, strlen(pass));
257       silc_free(pass);
258       return FALSE;
259     }
260
261   if (!pass) {
262     pass = silc_get_input("Private key passphrase: ", TRUE);
263     if (!pass)
264       pass = strdup("");
265   }
266
267   if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
268                                  (unsigned char *)pass, strlen(pass),
269                                  SILC_PKCS_FILE_BIN) == FALSE)
270     if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
271                                    (unsigned char *)pass, strlen(pass),
272                                    SILC_PKCS_FILE_PEM) == FALSE) {
273       memset(pass, 0, strlen(pass));
274       silc_free(pass);
275       return FALSE;
276     }
277
278   if (return_pkcs) {
279     silc_pkcs_alloc((*return_public_key)->name, return_pkcs);
280     silc_pkcs_public_key_set(*return_pkcs, *return_public_key);
281     silc_pkcs_private_key_set(*return_pkcs, *return_private_key);
282   }
283
284   memset(pass, 0, strlen(pass));
285   silc_free(pass);
286   return TRUE;
287 }
288
289 /* Dump public key into stdout */
290
291 bool silc_show_public_key(const char *pub_filename)
292 {
293   SilcPublicKey public_key;
294   SilcPublicKeyIdentifier ident;
295   char *fingerprint, *babbleprint;
296   unsigned char *pk;
297   SilcUInt32 pk_len;
298   SilcPKCS pkcs;
299   SilcUInt32 key_len = 0;
300
301   if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
302                                 SILC_PKCS_FILE_PEM) == FALSE)
303     if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
304                                   SILC_PKCS_FILE_BIN) == FALSE) {
305       fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
306       return FALSE;
307     }
308
309   ident = silc_pkcs_decode_identifier(public_key->identifier);
310
311   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
312   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
313   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
314
315   if (silc_pkcs_alloc(public_key->name, &pkcs)) {
316     key_len = silc_pkcs_public_key_set(pkcs, public_key);
317     silc_pkcs_free(pkcs);
318   }
319
320   printf("Public key file    : %s\n", pub_filename);
321   printf("Algorithm          : %s\n", public_key->name);
322   if (key_len)
323     printf("Key length (bits)  : %d\n", (unsigned int)key_len);
324   if (ident->realname)
325     printf("Real name          : %s\n", ident->realname);
326   if (ident->username)
327     printf("Username           : %s\n", ident->username);
328   if (ident->host)
329     printf("Hostname           : %s\n", ident->host);
330   if (ident->email)
331     printf("Email              : %s\n", ident->email);
332   if (ident->org)
333     printf("Organization       : %s\n", ident->org);
334   if (ident->country)
335     printf("Country            : %s\n", ident->country);
336   printf("Fingerprint (SHA1) : %s\n", fingerprint); 
337   printf("Babbleprint (SHA1) : %s\n", babbleprint); 
338
339   fflush(stdout);
340
341   silc_free(fingerprint);
342   silc_free(babbleprint);
343   silc_free(pk);
344   silc_pkcs_public_key_free(public_key);
345   silc_pkcs_free_identifier(ident);
346
347   return TRUE;
348 }
349
350 /* Change private key passphrase */
351
352 bool silc_change_private_key_passphrase(const char *prv_filename,
353                                         const char *old_passphrase,
354                                         const char *new_passphrase)
355 {
356   SilcPrivateKey private_key;
357   bool base64 = FALSE;
358   char *pass;
359
360   pass = old_passphrase ? strdup(old_passphrase) : NULL;
361   if (!pass) {
362     pass = silc_get_input("Old passphrase: ", TRUE);
363     if (!pass)
364       pass = strdup("");
365   }
366
367   if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
368                                  (unsigned char *)pass, strlen(pass),
369                                  SILC_PKCS_FILE_BIN) == FALSE) {
370     base64 = TRUE;
371     if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
372                                    (unsigned char *)pass, strlen(pass),
373                                    SILC_PKCS_FILE_PEM) == FALSE) {
374       memset(pass, 0, strlen(pass));
375       silc_free(pass);
376       fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
377       return FALSE;
378     }
379   }
380
381   memset(pass, 0, strlen(pass));
382   silc_free(pass);
383
384   pass = new_passphrase ? strdup(new_passphrase) : NULL;
385   if (!pass) {
386     fprintf(stdout, "\n");
387     pass = silc_get_input("New passphrase: ", TRUE);
388     if (!pass)
389       pass = strdup("");
390   }
391
392   silc_pkcs_save_private_key((char *)prv_filename, private_key,
393                              (unsigned char *)pass, strlen(pass),
394                              base64 ? SILC_PKCS_FILE_PEM : SILC_PKCS_FILE_BIN);
395
396   fprintf(stdout, "\nPassphrase changed\n");
397
398   memset(pass, 0, strlen(pass));
399   silc_free(pass);
400
401   silc_pkcs_private_key_free(private_key);
402   return TRUE;
403 }