Use silc_pkcs_get_name. SilcPKCS cannot be accessed directly.
[silc.git] / apps / irssi / src / silc / core / clientutil.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 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 "module.h"
22
23 #include "net-nonblock.h"
24 #include "net-sendbuffer.h"
25 #include "signals.h"
26 #include "servers.h"
27 #include "commands.h"
28 #include "levels.h"
29 #include "modules.h"
30 #include "rawlog.h"
31 #include "misc.h"
32 #include "settings.h"
33
34 #include "channels-setup.h"
35
36 #include "silc-servers.h"
37 #include "silc-channels.h"
38 #include "silc-queries.h"
39 #include "silc-nicklist.h"
40 #include "window-item-def.h"
41
42 #include "fe-common/core/printtext.h"
43 #include "fe-common/core/keyboard.h"
44
45 #include "core.h"
46
47 /* Lists supported ciphers */
48
49 void silc_client_list_ciphers()
50 {
51   char *ciphers = silc_cipher_get_supported();
52   fprintf(stdout, "%s\n", ciphers);
53   silc_free(ciphers);
54 }
55
56 /* Lists supported hash functions */
57
58 void silc_client_list_hash_funcs()
59 {
60   char *hash = silc_hash_get_supported();
61   fprintf(stdout, "%s\n", hash);
62   silc_free(hash);
63 }
64
65 /* Lists supported hash functions */
66
67 void silc_client_list_hmacs()
68 {
69   char *hash = silc_hmac_get_supported();
70   fprintf(stdout, "%s\n", hash);
71   silc_free(hash);
72 }
73
74 /* Lists supported PKCS algorithms */
75
76 void silc_client_list_pkcs()
77 {
78   char *pkcs = silc_pkcs_get_supported();
79   fprintf(stdout, "%s\n", pkcs);
80   silc_free(pkcs);
81 }
82
83 /* Returns identifier string for public key generation. */
84
85 char *silc_client_create_identifier()
86 {
87   char *username = NULL, *realname = NULL;
88   char *hostname, email[256];
89   char *ident;
90   
91   /* Get realname */
92   realname = silc_get_real_name();
93
94   /* Get hostname */
95   hostname = silc_net_localhost();
96   if (!hostname)
97     return NULL;
98
99   /* Get username (mandatory) */
100   username = silc_get_username();
101   if (!username)
102     return NULL;
103
104   /* Create default email address, whether it is right or not */
105   snprintf(email, sizeof(email), "%s@%s", username, hostname);
106
107   ident = silc_pkcs_encode_identifier(username, hostname, realname, email,
108                                       NULL, NULL);
109   if (realname)
110     silc_free(realname);
111   silc_free(hostname);
112   silc_free(username);
113
114   return ident;
115 }
116
117 /* Creates new public key and private key pair. This is used only
118    when user wants to create new key pair from command line. */
119
120 int silc_client_create_key_pair(char *pkcs_name, int bits,
121                                 char *public_key, char *private_key,
122                                 char *identifier, 
123                                 SilcPublicKey *ret_pub_key,
124                                 SilcPrivateKey *ret_prv_key)
125 {
126   SilcPKCS pkcs;
127   SilcPublicKey pub_key;
128   SilcPrivateKey prv_key;
129   SilcRng rng;
130   unsigned char *key;
131   SilcUInt32 key_len;
132   char line[256];
133   char *pkfile = NULL, *prvfile = NULL;
134
135   if (!pkcs_name || !public_key || !private_key)
136     printf("\
137 New pair of keys will be created.  Please, answer to following questions.\n\
138 ");
139
140   if (!pkcs_name) {
141   again_name:
142     pkcs_name = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
143     if (!pkcs_name)
144       pkcs_name = strdup("rsa");
145
146     if (*pkcs_name == 'l' || *pkcs_name == 'L') {
147       silc_client_list_pkcs();
148       silc_free(pkcs_name);
149       goto again_name;
150     }
151   }
152
153   if (!silc_pkcs_is_supported(pkcs_name)) {
154     fprintf(stderr, "Unknown PKCS `%s'", pkcs_name);
155     return FALSE;
156   }
157
158   if (!bits) {
159     char *length = NULL;
160     length = silc_get_input("Key length in bits [1024]: ", FALSE);
161     if (!length)
162       bits = 1024;
163     else
164       bits = atoi(length);
165   }
166
167   if (!identifier) {
168     char *def = silc_client_create_identifier();
169
170     memset(line, 0, sizeof(line));
171     if (def)
172       snprintf(line, sizeof(line), "Identifier [%s]: ", def);
173     else
174       snprintf(line, sizeof(line),
175                "Identifier (eg. UN=jon, HN=jon.dummy.com, "
176                "RN=Jon Johnson, E=jon@dummy.com): ");
177
178     while (!identifier) {
179       identifier = silc_get_input(line, FALSE);
180       if (!identifier && def)
181         identifier = strdup(def);
182     }
183
184     if (def)
185       silc_free(def);
186   }
187
188   rng = silc_rng_alloc();
189   silc_rng_init(rng);
190   silc_rng_global_init(rng);
191
192   if (!public_key) {
193     memset(line, 0, sizeof(line));
194     snprintf(line, sizeof(line), "Public key filename [%s] ", 
195              SILC_CLIENT_PUBLIC_KEY_NAME);
196     pkfile = silc_get_input(line, FALSE);
197     if (!pkfile)
198       pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
199   } else {
200     pkfile = public_key;
201   }
202
203   if (!private_key) {
204     memset(line, 0, sizeof(line));
205     snprintf(line, sizeof(line), "Public key filename [%s] ", 
206              SILC_CLIENT_PRIVATE_KEY_NAME);
207     prvfile = silc_get_input(line, FALSE);
208     if (!prvfile)
209       prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
210   } else {
211     prvfile = private_key;
212   }
213
214   /* Generate keys */
215   silc_pkcs_alloc(pkcs_name, &pkcs);
216   silc_pkcs_generate_key(pkcs, bits, rng);
217
218   /* Save public key into file */
219   key = silc_pkcs_get_public_key(pkcs, &key_len);
220   pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs), identifier,
221                                        key, key_len);
222   silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
223   if (ret_pub_key)
224     *ret_pub_key = pub_key;
225
226   memset(key, 0, key_len);
227   silc_free(key);
228
229   /* Save private key into file */
230   key = silc_pkcs_get_private_key(pkcs, &key_len);
231   prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
232                                         key, key_len);
233   silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
234   if (ret_prv_key)
235     *ret_prv_key = prv_key;
236
237   printf("Public key has been saved into `%s'.\n", pkfile);
238   printf("Private key has been saved into `%s'.\n", prvfile);
239   printf("Press <Enter> to continue...\n");
240   getchar();
241
242   memset(key, 0, key_len);
243   silc_free(key);
244
245   silc_rng_free(rng);
246   silc_pkcs_free(pkcs);
247
248   return TRUE;
249 }
250
251 /* This checks stats for various SILC files and directories. First it 
252    checks if ~/.silc directory exist and is owned by the correct user. If 
253    it doesn't exist, it will create the directory. After that it checks if
254    user's Public and Private key files exists and that they aren't expired.
255    If they doesn't exist or they are expired, they will be (re)created
256    after return. */
257
258 int silc_client_check_silc_dir()
259 {
260   char filename[256], file_public_key[256], file_private_key[256];
261   char servfilename[256], clientfilename[256];
262   char *identifier;
263   struct stat st;
264   struct passwd *pw;
265   int firstime = FALSE;
266   time_t curtime, modtime;
267
268   SILC_LOG_DEBUG(("Checking ~./silc directory"));
269
270   memset(filename, 0, sizeof(filename));
271   memset(file_public_key, 0, sizeof(file_public_key));
272   memset(file_private_key, 0, sizeof(file_private_key));
273
274   identifier = silc_client_create_identifier();
275
276   pw = getpwuid(getuid());
277   if (!pw) {
278     fprintf(stderr, "silc: %s\n", strerror(errno));
279     if (identifier)
280       silc_free(identifier);
281     return FALSE;
282   }
283
284   /* We'll take home path from /etc/passwd file to be sure. */
285   snprintf(filename, sizeof(filename) - 1, "%s/", get_irssi_dir());
286   snprintf(servfilename, sizeof(servfilename) - 1, "%s/serverkeys", 
287            get_irssi_dir());
288   snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/clientkeys", 
289            get_irssi_dir());
290
291   /*
292    * Check ~/.silc directory
293    */
294   if ((stat(filename, &st)) == -1) {
295     /* If dir doesn't exist */
296     if (errno == ENOENT) {
297       if (pw->pw_uid == geteuid()) {
298         if ((mkdir(filename, 0755)) == -1) {
299           fprintf(stderr, "Couldn't create `%s' directory\n", filename);
300           return FALSE;
301         }
302
303         /* Directory was created. First time running SILC */
304         firstime = TRUE;
305       } else {
306         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
307                 filename);
308         return FALSE;
309       }
310     } else {
311       fprintf(stderr, "%s\n", strerror(errno));
312       return FALSE;
313     }
314   } else {
315     
316     /* Check the owner of the dir */
317     if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
318       fprintf(stderr, "You don't seem to own `%s' directory\n",
319               filename);
320       return FALSE;
321     }
322     
323 #if 0
324     /* Check the permissions of the dir */
325     if ((st.st_mode & 0777) != 0755) {
326       if ((chmod(filename, 0755)) == -1) {
327         fprintf(stderr, "Permissions for `%s' directory must be 0755\n", 
328                 filename);
329         return FALSE;
330       }
331     }
332 #endif
333   }
334
335   /*
336    * Check ~./silc/serverkeys directory
337    */
338   if ((stat(servfilename, &st)) == -1) {
339     /* If dir doesn't exist */
340     if (errno == ENOENT) {
341       if (pw->pw_uid == geteuid()) {
342         if ((mkdir(servfilename, 0755)) == -1) {
343           fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
344           return FALSE;
345         }
346       } else {
347         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
348                 servfilename);
349         return FALSE;
350       }
351     } else {
352       fprintf(stderr, "%s\n", strerror(errno));
353       return FALSE;
354     }
355   }
356   
357   /*
358    * Check ~./silc/clientkeys directory
359    */
360   if ((stat(clientfilename, &st)) == -1) {
361     /* If dir doesn't exist */
362     if (errno == ENOENT) {
363       if (pw->pw_uid == geteuid()) {
364         if ((mkdir(clientfilename, 0755)) == -1) {
365           fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
366           return FALSE;
367         }
368       } else {
369         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
370                 clientfilename);
371         return FALSE;
372       }
373     } else {
374       fprintf(stderr, "%s\n", strerror(errno));
375       return FALSE;
376     }
377   }
378   
379   /*
380    * Check Public and Private keys
381    */
382   snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", 
383            filename, SILC_CLIENT_PUBLIC_KEY_NAME);
384   snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", 
385            filename, SILC_CLIENT_PRIVATE_KEY_NAME);
386   
387   /* If running SILC first time */
388   if (firstime) {
389     fprintf(stdout, "Running SILC for the first time\n");
390     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
391                                 SILC_CLIENT_DEF_PKCS_LEN,
392                                 file_public_key, file_private_key, 
393                                 identifier, NULL, NULL);
394     return TRUE;
395   }
396   
397   if ((stat(file_public_key, &st)) == -1) {
398     /* If file doesn't exist */
399     if (errno == ENOENT) {
400       fprintf(stdout, "Your public key doesn't exist\n");
401       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
402                                   SILC_CLIENT_DEF_PKCS_LEN,
403                                   file_public_key, 
404                                   file_private_key, identifier, NULL, NULL);
405     } else {
406       fprintf(stderr, "%s\n", strerror(errno));
407       return FALSE;
408     }
409   }
410
411   /* Check the owner of the public key */
412   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
413     fprintf(stderr, "You don't seem to own your public key!?\n");
414     return FALSE;
415   }
416   
417   if ((stat(file_private_key, &st)) == -1) {
418     /* If file doesn't exist */
419     if (errno == ENOENT) {
420       fprintf(stdout, "Your private key doesn't exist\n");
421       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
422                                   SILC_CLIENT_DEF_PKCS_LEN,
423                                   file_public_key, 
424                                   file_private_key, identifier, NULL, NULL);
425     } else {
426       fprintf(stderr, "%s\n", strerror(errno));
427       return FALSE;
428     }
429   }
430     
431   /* Check the owner of the private key */
432   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
433     fprintf(stderr, "You don't seem to own your private key!?\n");
434     return FALSE;
435   }
436     
437   /* Check the permissions for the private key */
438   if ((st.st_mode & 0777) != 0600) {
439     fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
440             "Trying to change them ... ", file_private_key);
441     if ((chmod(file_private_key, 0600)) == -1) {
442       fprintf(stderr,
443               "Failed to change permissions for private key file!\n" 
444               "Permissions for your private key file must be 0600.\n");
445       return FALSE;
446     }
447     fprintf(stderr, "Done.\n\n");
448   }
449
450   /* See if the key has expired. */
451   modtime = st.st_mtime;        /* last modified */
452   curtime = time(0) - modtime;
453     
454   /* 86400 is seconds in a day. */
455   if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
456     char *answer;
457
458     fprintf(stdout, 
459             "----------------------------------------------------\n"
460             "Your private key has expired and needs to be\n" 
461             "recreated.  Would you like to create a new key pair\n"
462             "now?  If you answer Yes, the new key will expire in\n"
463             "%d days from today.  If you answer No, the old key\n"
464             "will expire again in %d days from today.\n"
465             "----------------------------------------------------\n",
466             SILC_CLIENT_KEY_EXPIRES, SILC_CLIENT_KEY_EXPIRES);
467
468     answer = silc_get_input("Would you like to create a new key pair "
469                             "([y]/n)?: ", FALSE);
470     if (!answer || answer[0] == 'Y' || answer[0] == 'y') {
471       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
472                                   SILC_CLIENT_DEF_PKCS_LEN,
473                                   file_public_key, 
474                                   file_private_key, identifier, NULL, NULL);
475     } else {
476 #ifdef HAVE_UTIME
477       struct utimbuf utim;
478       utim.actime = time(NULL);
479       utim.modtime = time(NULL);
480       utime(file_private_key, &utim);
481 #endif
482     }
483     silc_free(answer);
484   }
485   
486   if (identifier)
487     silc_free(identifier);
488
489   return TRUE;
490 }
491
492 /* Loads public and private key from files. */
493
494 int silc_client_load_keys(SilcClient client)
495 {
496   char filename[256];
497   struct passwd *pw;
498
499   SILC_LOG_DEBUG(("Loading public and private keys"));
500
501   pw = getpwuid(getuid());
502   if (!pw)
503     return FALSE;
504
505   memset(filename, 0, sizeof(filename));
506   snprintf(filename, sizeof(filename) - 1, "%s/%s", 
507            get_irssi_dir(), SILC_CLIENT_PRIVATE_KEY_NAME);
508
509   if (silc_pkcs_load_private_key(filename, &client->private_key,
510                                  SILC_PKCS_FILE_BIN) == FALSE)
511     if (silc_pkcs_load_private_key(filename, &client->private_key,
512                                    SILC_PKCS_FILE_PEM) == FALSE)
513       return FALSE;
514
515   memset(filename, 0, sizeof(filename));
516   snprintf(filename, sizeof(filename) - 1, "%s/%s", 
517            get_irssi_dir(), SILC_CLIENT_PUBLIC_KEY_NAME);
518
519   if (silc_pkcs_load_public_key(filename, &client->public_key,
520                                 SILC_PKCS_FILE_PEM) == FALSE)
521     if (silc_pkcs_load_public_key(filename, &client->public_key,
522                                   SILC_PKCS_FILE_BIN) == FALSE)
523       return FALSE;
524
525   silc_pkcs_alloc(client->public_key->name, &client->pkcs);
526   silc_pkcs_public_key_set(client->pkcs, client->public_key);
527   silc_pkcs_private_key_set(client->pkcs, client->private_key);
528
529   return TRUE;
530 }
531
532 /* Dumps the public key on screen. Used from the command line option. */
533
534 int silc_client_show_key(char *keyfile)
535 {
536   SilcPublicKey public_key;
537   SilcPublicKeyIdentifier ident;
538   char *fingerprint, *babbleprint;
539   unsigned char *pk;
540   SilcUInt32 pk_len;
541   SilcPKCS pkcs;
542   int key_len = 0;
543
544   if (silc_pkcs_load_public_key(keyfile, &public_key,
545                                 SILC_PKCS_FILE_PEM) == FALSE)
546     if (silc_pkcs_load_public_key(keyfile, &public_key,
547                                   SILC_PKCS_FILE_BIN) == FALSE) {
548       fprintf(stderr, "Could not load public key file `%s'\n", keyfile);
549       return FALSE;
550     }
551
552   ident = silc_pkcs_decode_identifier(public_key->identifier);
553
554   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
555   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
556   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
557
558   if (silc_pkcs_alloc(public_key->name, &pkcs)) {
559     key_len = silc_pkcs_public_key_set(pkcs, public_key);
560     silc_pkcs_free(pkcs);
561   }
562
563   printf("Public key file    : %s\n", keyfile);
564   printf("Algorithm          : %s\n", public_key->name);
565   if (key_len)
566     printf("Key length (bits)  : %d\n", key_len);
567   if (ident->realname)
568     printf("Real name          : %s\n", ident->realname);
569   if (ident->username)
570     printf("Username           : %s\n", ident->username);
571   if (ident->host)
572     printf("Hostname           : %s\n", ident->host);
573   if (ident->email)
574     printf("Email              : %s\n", ident->email);
575   if (ident->org)
576     printf("Organization       : %s\n", ident->org);
577   if (ident->country)
578     printf("Country            : %s\n", ident->country);
579   printf("Fingerprint (SHA1) : %s\n", fingerprint); 
580   printf("Babbleprint (SHA1) : %s\n", babbleprint); 
581
582   fflush(stdout);
583
584   silc_free(fingerprint);
585   silc_free(babbleprint);
586   silc_free(pk);
587   silc_pkcs_public_key_free(public_key);
588   silc_pkcs_free_identifier(ident);
589
590   return TRUE;
591 }