New SILC PKCS API, enabling support for other public keys/certs.
[silc.git] / lib / silcutil / silcapputil.c
1 /*
2
3   silcapputil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2005 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 "silc.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_silc_encode_identifier(username, hostname, realname,
46                                            email, 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 SilcBool 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                               SilcPublicKey *return_public_key,
64                               SilcPrivateKey *return_private_key,
65                               SilcBool interactive)
66 {
67   SilcRng rng;
68   char line[256];
69   char *pkfile = pub_filename ? strdup(pub_filename) : NULL;
70   char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
71   char *alg = pkcs_name ? strdup(pkcs_name) : NULL;
72   char *identifier = pub_identifier ? strdup(pub_identifier) : NULL;
73   char *pass = passphrase ? strdup(passphrase) : NULL;
74
75   if (interactive && (!alg || !pub_filename || !prv_filename))
76     printf("\
77 New pair of keys will be created.  Please, answer to following questions.\n\
78 ");
79
80   if (!alg) {
81     if (interactive) {
82       while (!alg) {
83         alg = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
84         if (!alg)
85           alg = strdup("rsa");
86
87         if (*alg == 'l' || *alg == 'L') {
88           char *list = silc_pkcs_get_supported();
89           printf("%s\n", list);
90           silc_free(list);
91           silc_free(alg);
92           alg = NULL;
93         }
94       }
95     } else {
96       alg = strdup("rsa");
97     }
98   }
99
100   if (!silc_pkcs_find_algorithm(alg, NULL)) {
101     fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library"
102             "is not initialized", alg);
103     return FALSE;
104   }
105
106   if (!key_len_bits) {
107     if (interactive) {
108       char *length = NULL;
109       length = silc_get_input("Key length in key_len_bits [2048]: ", FALSE);
110       if (length)
111         key_len_bits = atoi(length);
112       silc_free(length);
113     }
114     if (!key_len_bits)
115       key_len_bits = 2048;
116   }
117
118   if (!identifier) {
119     char *def = silc_create_pk_identifier();
120
121     if (interactive) {
122       memset(line, 0, sizeof(line));
123       if (def)
124         snprintf(line, sizeof(line), "Identifier [%s]: ", def);
125       else
126         snprintf(line, sizeof(line),
127                "Identifier (eg. UN=jon, HN=jon.dummy.com, "
128                "RN=Jon Johnson, E=jon@dummy.com): ");
129
130       while (!identifier) {
131         identifier = silc_get_input(line, FALSE);
132         if (!identifier && def)
133           identifier = strdup(def);
134       }
135     } else {
136       if (!def) {
137         fprintf(stderr, "Could not create public key identifier: %s\n",
138                 strerror(errno));
139         return FALSE;
140       }
141       identifier = strdup(def);
142     }
143
144     silc_free(def);
145   }
146
147   rng = silc_rng_alloc();
148   silc_rng_init(rng);
149   silc_rng_global_init(rng);
150
151   if (!pkfile) {
152     if (interactive) {
153       memset(line, 0, sizeof(line));
154       snprintf(line, sizeof(line), "Public key filename [public_key.pub]: ");
155       pkfile = silc_get_input(line, FALSE);
156     }
157     if (!pkfile)
158       pkfile = strdup("public_key.pub");
159   }
160
161   if (!prvfile) {
162     if (interactive) {
163       memset(line, 0, sizeof(line));
164       snprintf(line, sizeof(line), "Private key filename [private_key.prv]: ");
165       prvfile = silc_get_input(line, FALSE);
166     }
167     if (!prvfile)
168       prvfile = strdup("private_key.prv");
169   }
170
171   if (!pass) {
172     while (TRUE) {
173       char *pass2 = NULL;
174       pass = silc_get_input("Private key passphrase: ", TRUE);
175       if (!pass) {
176         pass = strdup("");
177         break;
178       } else {
179         SilcBool match;
180         printf("\n");
181         pass2 = silc_get_input("Retype private key passphrase: ", TRUE);
182         if (!pass2)
183           pass2 = strdup("");
184         match = !strcmp(pass, pass2);
185         silc_free(pass2);
186         if (match)
187           break;
188         fprintf(stderr, "\nPassphrases do not match\n\n");
189       }
190     }
191   }
192
193   /* Generate keys */
194   if (!silc_pkcs_silc_generate_key(alg, "pkcs1-no-oid", key_len_bits,
195                                    identifier, rng, return_public_key,
196                                    return_private_key))
197     return FALSE;
198
199   /* Save public key into file */
200   silc_pkcs_save_public_key(pkfile, *return_public_key, SILC_PKCS_FILE_BASE64);
201
202   /* Save private key into file */
203   silc_pkcs_save_private_key(prvfile, *return_private_key,
204                              (const unsigned char *)pass, strlen(pass),
205                              SILC_PKCS_FILE_BIN, rng);
206
207   printf("Public key has been saved into `%s'.\n", pkfile);
208   printf("Private key has been saved into `%s'.\n", prvfile);
209   if (interactive) {
210     printf("Press <Enter> to continue...\n");
211     getchar();
212   }
213
214   silc_rng_free(rng);
215   silc_free(alg);
216   silc_free(pkfile);
217   silc_free(prvfile);
218   silc_free(identifier);
219   memset(pass, 0, strlen(pass));
220   silc_free(pass);
221
222   return TRUE;
223 }
224
225 /* Load key pair */
226
227 SilcBool silc_load_key_pair(const char *pub_filename,
228                             const char *prv_filename,
229                             const char *passphrase,
230                             SilcPublicKey *return_public_key,
231                             SilcPrivateKey *return_private_key)
232 {
233   char *pass = passphrase ? strdup(passphrase) : NULL;
234
235   SILC_LOG_DEBUG(("Loading public and private keys"));
236
237   if (!silc_pkcs_load_public_key(pub_filename, return_public_key)) {
238     if (pass)
239       memset(pass, 0, strlen(pass));
240     silc_free(pass);
241     return FALSE;
242   }
243
244   if (!pass) {
245     pass = silc_get_input("Private key passphrase: ", TRUE);
246     if (!pass)
247       pass = strdup("");
248   }
249
250   if (!silc_pkcs_load_private_key(prv_filename,
251                                   (const unsigned char *)pass, strlen(pass),
252                                   return_private_key)) {
253     memset(pass, 0, strlen(pass));
254     silc_free(pass);
255     return FALSE;
256   }
257
258   memset(pass, 0, strlen(pass));
259   silc_free(pass);
260   return TRUE;
261 }
262
263 /* Dump public key into stdout */
264
265 SilcBool silc_show_public_key(const char *pub_filename)
266 {
267   SilcPublicKey public_key;
268   SilcSILCPublicKey silc_pubkey;
269   SilcPublicKeyIdentifier ident;
270   char *fingerprint, *babbleprint;
271   unsigned char *pk;
272   SilcUInt32 pk_len;
273   SilcUInt32 key_len = 0;
274
275   if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
276     fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
277     return FALSE;
278   }
279
280   silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
281   if (!silc_pubkey) {
282     silc_pkcs_public_key_free(public_key);
283     return FALSE;
284   }
285
286   ident = &silc_pubkey->identifier;
287   key_len = silc_pkcs_public_key_get_len(public_key);
288   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
289   if (!pk) {
290     silc_pkcs_public_key_free(public_key);
291     return FALSE;
292   }
293   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
294   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
295
296   printf("Public key file    : %s\n", pub_filename);
297   printf("Algorithm          : %s\n", silc_pkcs_get_name(public_key));
298   if (key_len)
299     printf("Key length (bits)  : %d\n", (unsigned int)key_len);
300   if (ident->realname)
301     printf("Real name          : %s\n", ident->realname);
302   if (ident->username)
303     printf("Username           : %s\n", ident->username);
304   if (ident->host)
305     printf("Hostname           : %s\n", ident->host);
306   if (ident->email)
307     printf("Email              : %s\n", ident->email);
308   if (ident->org)
309     printf("Organization       : %s\n", ident->org);
310   if (ident->country)
311     printf("Country            : %s\n", ident->country);
312   printf("Fingerprint (SHA1) : %s\n", fingerprint);
313   printf("Babbleprint (SHA1) : %s\n", babbleprint);
314
315   fflush(stdout);
316
317   silc_free(fingerprint);
318   silc_free(babbleprint);
319   silc_free(pk);
320   silc_pkcs_public_key_free(public_key);
321
322   return TRUE;
323 }
324
325 /* Change private key passphrase */
326
327 SilcBool silc_change_private_key_passphrase(const char *prv_filename,
328                                             const char *old_passphrase,
329                                             const char *new_passphrase)
330 {
331   SilcPrivateKey private_key;
332   char *pass;
333   SilcRng rng;
334
335   pass = old_passphrase ? strdup(old_passphrase) : NULL;
336   if (!pass) {
337     pass = silc_get_input("Old passphrase: ", TRUE);
338     if (!pass)
339       pass = strdup("");
340   }
341
342   if (!silc_pkcs_load_private_key(prv_filename,
343                                   (const unsigned char *)pass, strlen(pass),
344                                   &private_key)) {
345     memset(pass, 0, strlen(pass));
346     silc_free(pass);
347     fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
348     return FALSE;
349   }
350
351   memset(pass, 0, strlen(pass));
352   silc_free(pass);
353
354   pass = new_passphrase ? strdup(new_passphrase) : NULL;
355   if (!pass) {
356     char *pass2 = NULL;
357     fprintf(stdout, "\n");
358     pass = silc_get_input("New passphrase: ", TRUE);
359     if (!pass) {
360       pass = strdup("");
361     } else {
362       while (TRUE) {
363         printf("\n");
364         pass2 = silc_get_input("Retype new passphrase: ", TRUE);
365         if (!pass2)
366           pass2 = strdup("");
367         if (!strcmp(pass, pass2))
368           break;
369         fprintf(stderr, "\nPassphrases do not match");
370       }
371       silc_free(pass2);
372     }
373   }
374
375   rng = silc_rng_alloc();
376   silc_rng_init(rng);
377
378   silc_pkcs_save_private_key((char *)prv_filename, private_key,
379                              (unsigned char *)pass, strlen(pass),
380                              SILC_PKCS_FILE_BIN, rng);
381
382   fprintf(stdout, "\nPassphrase changed\n");
383
384   memset(pass, 0, strlen(pass));
385   silc_free(pass);
386
387   silc_pkcs_private_key_free(private_key);
388   silc_rng_free(rng);
389
390   return TRUE;
391 }