Added support for encrypted private key files. The passphrase
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.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 "silcincludes.h"
22
23 #include "rsa.h"
24 #include "pkcs1.h"
25
26 /* The main SILC PKCS structure. */
27 struct SilcPKCSStruct {
28   void *context;                /* Algorithm internal context */
29   SilcPKCSObject *pkcs;         /* Algorithm implementation */
30   SilcUInt32 key_len;           /* Key length in bits */
31 };
32
33 #ifndef SILC_EPOC
34 /* Dynamically registered list of PKCS. */
35 SilcDList silc_pkcs_list = NULL;
36 #define SILC_PKCS_LIST silc_pkcs_list
37 #else
38 #define SILC_PKCS_LIST TRUE
39 #endif /* SILC_EPOC */
40
41 /* Static list of PKCS for silc_pkcs_register_default(). */
42 const SilcPKCSObject silc_default_pkcs[] =
43 {
44   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
45   { "rsa", 
46     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
47     silc_rsa_get_private_key, silc_rsa_set_public_key,
48     silc_rsa_set_private_key, silc_rsa_context_len,
49     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
50     silc_pkcs1_sign, silc_pkcs1_verify },
51
52   /* Raw RSA operations */
53   { "rsa-raw", 
54     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
55     silc_rsa_get_private_key, silc_rsa_set_public_key,
56     silc_rsa_set_private_key, silc_rsa_context_len,
57     silc_rsa_encrypt, silc_rsa_decrypt,
58     silc_rsa_sign, silc_rsa_verify },
59
60   { NULL, NULL, NULL, NULL, NULL,
61     NULL, NULL, NULL, NULL, NULL, NULL }
62 };
63
64 /* Register a new PKCS into SILC. This is used at the initialization of
65    the SILC. */
66
67 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
68 {
69 #ifndef SILC_EPOC
70   SilcPKCSObject *new;
71
72   SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
73
74   /* Check if exists already */
75   if (silc_pkcs_list) {
76     SilcPKCSObject *entry;
77     silc_dlist_start(silc_pkcs_list);
78     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
79       if (!strcmp(entry->name, pkcs->name))
80         return FALSE;
81     }
82   }
83
84   new = silc_calloc(1, sizeof(*new));
85   new->name = strdup(pkcs->name);
86   new->init = pkcs->init;
87   new->clear_keys = pkcs->clear_keys;
88   new->get_public_key = pkcs->get_public_key;
89   new->get_private_key = pkcs->get_private_key;
90   new->set_public_key = pkcs->set_public_key;
91   new->set_private_key = pkcs->set_private_key;
92   new->context_len = pkcs->context_len;
93   new->encrypt = pkcs->encrypt;
94   new->decrypt = pkcs->decrypt;
95   new->sign = pkcs->sign;
96   new->verify = pkcs->verify;
97
98   /* Add to list */
99   if (silc_pkcs_list == NULL)
100     silc_pkcs_list = silc_dlist_init();
101   silc_dlist_add(silc_pkcs_list, new);
102
103 #endif /* SILC_EPOC */
104   return TRUE;
105 }
106
107 /* Unregister a PKCS from the SILC. */
108
109 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
110 {
111 #ifndef SILC_EPOC
112   SilcPKCSObject *entry;
113
114   SILC_LOG_DEBUG(("Unregistering PKCS"));
115
116   if (!silc_pkcs_list)
117     return FALSE;
118
119   silc_dlist_start(silc_pkcs_list);
120   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
121     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
122       silc_dlist_del(silc_pkcs_list, entry);
123       silc_free(entry->name);
124       silc_free(entry);
125
126       if (silc_dlist_count(silc_pkcs_list) == 0) {
127         silc_dlist_uninit(silc_pkcs_list);
128         silc_pkcs_list = NULL;
129       }
130
131       return TRUE;
132     }
133   }
134
135 #endif /* SILC_EPOC */
136   return FALSE;
137 }
138
139 /* Function that registers all the default PKCS (all builtin PKCS). 
140    The application may use this to register the default PKCS if specific
141    PKCS in any specific order is not wanted. */
142
143 bool silc_pkcs_register_default(void)
144 {
145 #ifndef SILC_EPOC
146   int i;
147
148   for (i = 0; silc_default_pkcs[i].name; i++)
149     silc_pkcs_register(&(silc_default_pkcs[i]));
150
151 #endif /* SILC_EPOC */
152   return TRUE;
153 }
154
155 bool silc_pkcs_unregister_all(void)
156 {
157 #ifndef SILC_EPOC
158   SilcPKCSObject *entry;
159
160   if (!silc_pkcs_list)
161     return FALSE;
162
163   silc_dlist_start(silc_pkcs_list);
164   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
165     silc_pkcs_unregister(entry);
166     if (!silc_pkcs_list)
167       break;
168   }
169 #endif /* SILC_EPOC */
170   return TRUE;
171 }
172
173 /* Allocates a new SilcPKCS object. The new allocated object is returned
174    to the 'new_pkcs' argument. */
175
176 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
177 {
178   SilcPKCSObject *entry = NULL;
179
180   SILC_LOG_DEBUG(("Allocating new PKCS object"));
181
182 #ifndef SILC_EPOC
183   if (silc_pkcs_list) {
184     silc_dlist_start(silc_pkcs_list);
185     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
186       if (!strcmp(entry->name, name))
187         break;
188     }
189   }
190 #else
191   {
192     /* On EPOC which don't have globals we check our constant hash list. */
193     int i;
194     for (i = 0; silc_default_pkcs[i].name; i++) {
195       if (!strcmp(silc_default_pkcs[i].name, name)) {
196         entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
197         break;
198       }
199     }
200   }
201 #endif /* SILC_EPOC */
202
203   if (entry) {
204     *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
205     (*new_pkcs)->pkcs = entry;
206     (*new_pkcs)->context = silc_calloc(1, entry->context_len());
207     return TRUE;
208   }
209
210   return FALSE;
211 }
212
213 /* Free's the PKCS object */
214
215 void silc_pkcs_free(SilcPKCS pkcs)
216 {
217   if (pkcs) {
218     pkcs->pkcs->clear_keys(pkcs->context);
219     silc_free(pkcs->context);
220   }
221   silc_free(pkcs);
222 }
223
224 /* Return TRUE if PKCS algorithm `name' is supported. */
225
226 bool silc_pkcs_is_supported(const unsigned char *name)
227 {
228 #ifndef SILC_EPOC
229   SilcPKCSObject *entry;
230
231   if (silc_pkcs_list) {
232     silc_dlist_start(silc_pkcs_list);
233     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
234       if (!strcmp(entry->name, name))
235         return TRUE;
236     }
237   }
238 #else
239   {
240     int i;
241     for (i = 0; silc_default_pkcs[i].name; i++)
242       if (!strcmp(silc_default_pkcs[i].name, name))
243         return TRUE;
244   }
245 #endif /* SILC_EPOC */
246   return FALSE;
247 }
248
249 /* Returns comma separated list of supported PKCS algorithms */
250
251 char *silc_pkcs_get_supported(void)
252 {
253   SilcPKCSObject *entry;
254   char *list = NULL;
255   int len = 0;
256
257 #ifndef SILC_EPOC
258   if (silc_pkcs_list) {
259     silc_dlist_start(silc_pkcs_list);
260     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
261       len += strlen(entry->name);
262       list = silc_realloc(list, len + 1);
263       
264       memcpy(list + (len - strlen(entry->name)), 
265              entry->name, strlen(entry->name));
266       memcpy(list + len, ",", 1);
267       len++;
268     }
269   }
270 #else
271   {
272     int i;
273     for (i = 0; silc_default_pkcs[i].name; i++) {
274       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
275       len += strlen(entry->name);
276       list = silc_realloc(list, len + 1);
277       
278       memcpy(list + (len - strlen(entry->name)), 
279              entry->name, strlen(entry->name));
280       memcpy(list + len, ",", 1);
281       len++;
282     }
283   }
284 #endif /* SILC_EPOC */
285
286   list[len - 1] = 0;
287
288   return list;
289 }
290
291 /* Generate new key pair into the `pkcs' context. */
292
293 bool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
294                             SilcRng rng)
295 {
296   return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
297 }
298
299 /* Returns the length of the key */
300
301 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
302 {
303   return pkcs->key_len;
304 }
305
306 const char *silc_pkcs_get_name(SilcPKCS pkcs)
307 {
308   return pkcs->pkcs->name;
309 }
310
311 /* Returns SILC style public key */
312
313 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
314 {
315   return pkcs->pkcs->get_public_key(pkcs->context, len);
316 }
317
318 /* Returns SILC style private key */
319
320 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
321 {
322   return pkcs->pkcs->get_private_key(pkcs->context, len);
323 }
324
325 /* Sets public key from SilcPublicKey. */
326
327 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
328 {
329   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
330                                              public_key->pk_len);
331   return pkcs->key_len;
332 }
333
334 /* Sets public key from data. */
335
336 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
337                                      SilcUInt32 pk_len)
338 {
339   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
340   return pkcs->key_len;
341 }
342
343 /* Sets private key from SilcPrivateKey. */
344
345 SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
346 {
347   SilcUInt32 key_len;
348   key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
349                                         private_key->prv_len);
350   if (!pkcs->key_len)
351     pkcs->key_len = key_len;
352   return pkcs->key_len;
353 }
354
355 /* Sets private key from data. */
356
357 SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
358                                           SilcUInt32 prv_len)
359 {
360   SilcUInt32 key_len;
361   key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
362   if (!pkcs->key_len)
363     pkcs->key_len = key_len;
364   return pkcs->key_len;
365 }
366
367 /* Encrypts */
368
369 bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
370                        unsigned char *dst, SilcUInt32 *dst_len)
371 {
372   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
373 }
374
375 /* Decrypts */
376
377 bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
378                        unsigned char *dst, SilcUInt32 *dst_len)
379 {
380   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
381 }
382
383 /* Generates signature */
384
385 bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
386                     unsigned char *dst, SilcUInt32 *dst_len)
387 {
388   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
389 }
390
391 /* Verifies signature */
392
393 bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
394                       SilcUInt32 signature_len, unsigned char *data, 
395                       SilcUInt32 data_len)
396 {
397   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
398                             data, data_len);
399 }
400
401 /* Generates signature with hash. The hash is signed. */
402
403 bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
404                               unsigned char *src, SilcUInt32 src_len,
405                               unsigned char *dst, SilcUInt32 *dst_len)
406 {
407   unsigned char hashr[32];
408   SilcUInt32 hash_len;
409   int ret;
410
411   silc_hash_make(hash, src, src_len, hashr);
412   hash_len = silc_hash_len(hash);
413
414   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
415
416   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
417   memset(hashr, 0, sizeof(hashr));
418
419   return ret;
420 }
421
422 /* Verifies signature with hash. The `data' is hashed and verified against
423    the `signature'. */
424
425 bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
426                                 unsigned char *signature, 
427                                 SilcUInt32 signature_len, 
428                                 unsigned char *data, 
429                                 SilcUInt32 data_len)
430 {
431   unsigned char hashr[32];
432   SilcUInt32 hash_len;
433   int ret;
434
435   silc_hash_make(hash, data, data_len, hashr);
436   hash_len = silc_hash_len(hash);
437
438   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
439
440   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
441                            hashr, hash_len);
442   memset(hashr, 0, sizeof(hashr));
443
444   return ret;
445 }
446
447 /* Encodes and returns SILC public key identifier. If some of the 
448    arguments is NULL those are not encoded into the identifier string.
449    Protocol says that at least username and host must be provided. */
450
451 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
452                                   char *email, char *org, char *country)
453 {
454   SilcBuffer buf;
455   char *identifier;
456   SilcUInt32 len, tlen = 0;
457
458   if (!username || !host)
459     return NULL;
460
461   len = (username ? strlen(username) : 0) +
462         (host     ? strlen(host)     : 0) +
463         (realname ? strlen(realname) : 0) +
464         (email    ? strlen(email)    : 0) +
465         (org      ? strlen(org)      : 0) +
466         (country  ? strlen(country)  : 0);
467   
468   if (len < 3)
469     return NULL;
470
471   len += 3 + 5 + 5 + 4 + 4 + 4;
472   buf = silc_buffer_alloc(len);
473   silc_buffer_pull_tail(buf, len);
474
475   if (username) {
476     silc_buffer_format(buf,
477                        SILC_STR_UI32_STRING("UN="),
478                        SILC_STR_UI32_STRING(username),
479                        SILC_STR_END);
480     silc_buffer_pull(buf, 3 + strlen(username));
481     tlen = 3 + strlen(username); 
482   }
483     
484   if (host) {
485     silc_buffer_format(buf,
486                        SILC_STR_UI32_STRING(", "),
487                        SILC_STR_UI32_STRING("HN="),
488                        SILC_STR_UI32_STRING(host),
489                        SILC_STR_END);
490     silc_buffer_pull(buf, 5 + strlen(host));
491     tlen += 5 + strlen(host); 
492   }
493
494   if (realname) {
495     silc_buffer_format(buf,
496                        SILC_STR_UI32_STRING(", "),
497                        SILC_STR_UI32_STRING("RN="),
498                        SILC_STR_UI32_STRING(realname),
499                        SILC_STR_END);
500     silc_buffer_pull(buf, 5 + strlen(realname));
501     tlen += 5 + strlen(realname); 
502   }
503
504   if (email) {
505     silc_buffer_format(buf,
506                        SILC_STR_UI32_STRING(", "),
507                        SILC_STR_UI32_STRING("E="),
508                        SILC_STR_UI32_STRING(email),
509                        SILC_STR_END);
510     silc_buffer_pull(buf, 4 + strlen(email));
511     tlen += 4 + strlen(email); 
512   }
513
514   if (org) {
515     silc_buffer_format(buf,
516                        SILC_STR_UI32_STRING(", "),
517                        SILC_STR_UI32_STRING("O="),
518                        SILC_STR_UI32_STRING(org),
519                        SILC_STR_END);
520     silc_buffer_pull(buf, 4 + strlen(org));
521     tlen += 4 + strlen(org); 
522   }
523
524   if (country) {
525     silc_buffer_format(buf,
526                        SILC_STR_UI32_STRING(", "),
527                        SILC_STR_UI32_STRING("C="),
528                        SILC_STR_UI32_STRING(country),
529                        SILC_STR_END);
530     silc_buffer_pull(buf, 4 + strlen(country));
531     tlen += 4 + strlen(country); 
532   }
533
534   silc_buffer_push(buf, buf->data - buf->head);
535   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
536   memcpy(identifier, buf->data, tlen);
537   silc_buffer_free(buf);
538
539   return identifier;
540 }
541
542 /* Decodes the provided `identifier' and returns allocated context for
543    the identifier. */
544
545 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
546 {
547   SilcPublicKeyIdentifier ident;
548   char *cp, *item;
549   int len;
550
551   ident = silc_calloc(1, sizeof(*ident));
552
553   cp = identifier;
554   while (cp) {
555     len = strcspn(cp, ",");
556     if (len - 1 >= 0 && cp[len - 1] == '\\') {
557       while (cp) {
558         cp += len + 1;
559         len = strcspn(cp, ",") + len;
560         if (len - 1 >= 0 && cp[len - 1] != '\\')
561           break;
562       }
563     }
564
565     item = silc_calloc(len + 1, sizeof(char));
566     memcpy(item, cp, len);
567
568     if (strstr(item, "UN="))
569       ident->username = strdup(item + strcspn(cp, "=") + 1);
570     else if (strstr(item, "HN="))
571       ident->host = strdup(item + strcspn(cp, "=") + 1);
572     else if (strstr(item, "RN="))
573       ident->realname = strdup(item + strcspn(cp, "=") + 1);
574     else if (strstr(item, "E="))
575       ident->email = strdup(item + strcspn(cp, "=") + 1);
576     else if (strstr(item, "O="))
577       ident->org = strdup(item + strcspn(cp, "=") + 1);
578     else if (strstr(item, "C="))
579       ident->country = strdup(item + strcspn(cp, "=") + 1);
580     
581     cp += len;
582     if (strlen(cp) == 0)
583       cp = NULL;
584     else
585       cp += 1;
586     
587     if (item)
588       silc_free(item);
589   }
590
591   return ident;
592 }
593
594 /* Free's decoded public key identifier context. Call this to free the
595    context returned by the silc_pkcs_decode_identifier. */
596
597 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
598 {
599   silc_free(identifier->username);
600   silc_free(identifier->host);
601   silc_free(identifier->realname);
602   silc_free(identifier->email);
603   silc_free(identifier->org);
604   silc_free(identifier->country);
605   silc_free(identifier);
606 }
607
608 /* Allocates SILC style public key formed from sent arguments. All data
609    is duplicated. */
610
611 SilcPublicKey silc_pkcs_public_key_alloc(const char *name, 
612                                          const char *identifier,
613                                          const unsigned char *pk, 
614                                          SilcUInt32 pk_len)
615 {
616   SilcPublicKey public_key;
617   char *tmp = NULL;
618
619   public_key = silc_calloc(1, sizeof(*public_key));
620   public_key->name = strdup(name);
621   public_key->pk_len = pk_len;
622   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
623   memcpy(public_key->pk, pk, pk_len);
624
625   if (!silc_utf8_valid(identifier, strlen(identifier))) {
626     int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
627     tmp = silc_calloc(len + 1, sizeof(*tmp));
628     silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
629     identifier = tmp;
630   }
631
632   public_key->identifier = strdup(identifier);
633   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
634   silc_free(tmp);
635
636   return public_key;
637 }
638
639 /* Free's public key */
640
641 void silc_pkcs_public_key_free(SilcPublicKey public_key)
642 {
643   if (public_key) {
644     silc_free(public_key->name);
645     silc_free(public_key->identifier);
646     silc_free(public_key->pk);
647     silc_free(public_key);
648   }
649 }
650
651 /* Allocates SILC private key formed from sent arguments. All data is
652    duplicated. */
653
654 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
655                                            const unsigned char *prv,
656                                            SilcUInt32 prv_len)
657 {
658   SilcPrivateKey private_key;
659
660   private_key = silc_calloc(1, sizeof(*private_key));
661   private_key->name = strdup(name);
662   private_key->prv_len = prv_len;
663   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
664   memcpy(private_key->prv, prv, prv_len);
665
666   return private_key;
667 }
668
669 /* Free's private key */
670
671 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
672 {
673   if (private_key) {
674     silc_free(private_key->name);
675     silc_free(private_key->prv);
676     silc_free(private_key);
677   }
678 }
679
680 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
681    data. */
682
683 unsigned char *
684 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
685 {
686   SilcBuffer buf;
687   unsigned char *ret;
688
689   buf = silc_buffer_alloc(public_key->len);
690   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
691
692   silc_buffer_format(buf,
693                      SILC_STR_UI_INT(public_key->len),
694                      SILC_STR_UI_SHORT(strlen(public_key->name)),
695                      SILC_STR_UI32_STRING(public_key->name),
696                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
697                      SILC_STR_UI32_STRING(public_key->identifier),
698                      SILC_STR_UI_XNSTRING(public_key->pk, 
699                                           public_key->pk_len),
700                      SILC_STR_END);
701   if (len)
702     *len = public_key->len;
703
704   ret = silc_calloc(buf->len, sizeof(*ret));
705   memcpy(ret, buf->data, buf->len);
706   silc_buffer_free(buf);
707
708   return ret;
709 }
710
711 /* Encodes SILC style public key. Returns the encoded data. */
712
713 unsigned char *
714 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
715                                  char *pkcs, char *identifier, 
716                                  SilcUInt32 *len)
717 {
718   SilcBuffer buf;
719   unsigned char *ret;
720   SilcUInt32 totlen;
721
722   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
723   buf = silc_buffer_alloc(totlen);
724   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
725
726   silc_buffer_format(buf,
727                      SILC_STR_UI_INT(totlen),
728                      SILC_STR_UI_SHORT(strlen(pkcs)),
729                      SILC_STR_UI32_STRING(pkcs),
730                      SILC_STR_UI_SHORT(strlen(identifier)),
731                      SILC_STR_UI32_STRING(identifier),
732                      SILC_STR_UI_XNSTRING(pk, pk_len),
733                      SILC_STR_END);
734   if (len)
735     *len = totlen;
736
737   ret = silc_calloc(buf->len, sizeof(*ret));
738   memcpy(ret, buf->data, buf->len);
739   silc_buffer_free(buf);
740
741   return ret;
742 }
743
744 /* Decodes SILC style public key. Returns TRUE if the decoding was
745    successful. Allocates new public key as well. */
746
747 bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
748                                  SilcPublicKey *public_key)
749 {
750   SilcBuffer buf;
751   SilcPKCS alg;
752   SilcUInt16 pkcs_len, identifier_len;
753   SilcUInt32 totlen, key_len;
754   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
755   int ret;
756
757   buf = silc_buffer_alloc(data_len);
758   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
759   silc_buffer_put(buf, data, data_len);
760
761   /* Get length */
762   ret = silc_buffer_unformat(buf,
763                              SILC_STR_UI_INT(&totlen),
764                              SILC_STR_END);
765   if (ret == -1) {
766     silc_buffer_free(buf);
767     return FALSE;
768   }
769
770   if (totlen != data_len) {
771     silc_buffer_free(buf);
772     return FALSE;
773   }
774
775   /* Get algorithm name and identifier */
776   silc_buffer_pull(buf, 4);
777   ret =
778     silc_buffer_unformat(buf,
779                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
780                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
781                          SILC_STR_END);
782   if (ret == -1)
783     goto err;
784
785   if (pkcs_len < 1 || identifier_len < 3 || 
786       pkcs_len + identifier_len > totlen)
787     goto err;
788
789   /* See if we support this algorithm (check only if PKCS are registered) */
790   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
791     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
792     goto err;
793   }
794
795   /* Protocol says that at least UN and HN must be provided as identifier,
796      check for these. */
797   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
798     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
799                     "identifiers"));
800     goto err;
801   }
802
803   /* Get key data. We assume that rest of the buffer is key data. */
804   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
805   key_len = buf->len;
806   ret = silc_buffer_unformat(buf,
807                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
808                              SILC_STR_END);
809   if (ret == -1)
810     goto err;
811
812   /* Try to set the key. If this fails the key must be malformed. This
813      code assumes that the PKCS routine checks the format of the key. 
814      (check only if PKCS are registered) */
815   if (SILC_PKCS_LIST) {
816     silc_pkcs_alloc(pkcs_name, &alg);
817     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
818       goto err;
819     silc_pkcs_free(alg);
820   }
821   
822   if (public_key) {
823     *public_key = silc_calloc(1, sizeof(**public_key));
824     (*public_key)->len = totlen;
825     (*public_key)->name = pkcs_name;
826     (*public_key)->identifier = ident;
827     (*public_key)->pk = key_data;
828     (*public_key)->pk_len = key_len;
829   }
830
831   silc_buffer_free(buf);
832   return TRUE;
833
834  err:
835   if (pkcs_name)
836     silc_free(pkcs_name);
837   if (ident)
838     silc_free(ident);
839   if (key_data)
840     silc_free(key_data);
841   silc_buffer_free(buf);
842   return FALSE;
843 }
844
845 /* Compares two public keys and returns TRUE if they are same key, and
846    FALSE if they are not same. */
847
848 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
849 {
850   if (key1 == key2)
851     return TRUE;
852
853   if (key1->len == key2->len &&
854       key1->name && key2->name && key1->identifier && key2->identifier &&
855       !strcmp(key1->name, key2->name) &&
856       !strcmp(key1->identifier, key2->identifier) &&
857       !memcmp(key1->pk, key2->pk, key1->pk_len) &&
858       key1->pk_len == key2->pk_len)
859     return TRUE;
860
861   return FALSE;
862 }
863
864 /* Copies the public key indicated by `public_key' and returns new allocated
865    public key which is indentical to the `public_key'. */
866
867 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
868 {
869   SilcPublicKey key = silc_calloc(1, sizeof(*key));
870   if (!key)
871     return NULL;
872
873   key->len = public_key->len;
874   key->name = silc_memdup(public_key->name, strlen(public_key->name));
875   key->identifier = silc_memdup(public_key->identifier,
876                                 strlen(public_key->identifier));
877   key->pk = silc_memdup(public_key->pk, public_key->pk_len);
878   key->pk_len = public_key->pk_len;
879
880   return key;
881 }
882
883 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
884
885 unsigned char *
886 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
887 {
888   SilcBuffer buf;
889   unsigned char *ret;
890   SilcUInt32 totlen;
891
892   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
893   buf = silc_buffer_alloc(totlen);
894   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
895
896   silc_buffer_format(buf,
897                      SILC_STR_UI_SHORT(strlen(private_key->name)),
898                      SILC_STR_UI32_STRING(private_key->name),
899                      SILC_STR_UI_XNSTRING(private_key->prv, 
900                                           private_key->prv_len),
901                      SILC_STR_END);
902   if (len)
903     *len = totlen;
904
905   ret = silc_calloc(buf->len, sizeof(*ret));
906   memcpy(ret, buf->data, buf->len);
907   silc_buffer_clear(buf);
908   silc_buffer_free(buf);
909
910   return ret;
911 }
912
913 /* Encodes SILC private key. Returns the encoded data. */
914
915 unsigned char *
916 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
917                                   char *pkcs, SilcUInt32 *len)
918 {
919   SilcBuffer buf;
920   unsigned char *ret;
921   SilcUInt32 totlen;
922
923   totlen = 2 + strlen(pkcs) + prv_len;
924   buf = silc_buffer_alloc(totlen);
925   silc_buffer_pull_tail(buf, totlen);
926
927   silc_buffer_format(buf,
928                      SILC_STR_UI_SHORT(strlen(pkcs)),
929                      SILC_STR_UI32_STRING(pkcs),
930                      SILC_STR_UI_XNSTRING(prv, prv_len),
931                      SILC_STR_END);
932   if (len)
933     *len = totlen;
934
935   ret = silc_calloc(buf->len, sizeof(*ret));
936   memcpy(ret, buf->data, buf->len);
937   silc_buffer_clear(buf);
938   silc_buffer_free(buf);
939
940   return ret;
941 }
942
943 /* Decodes SILC style private key. Returns TRUE if the decoding was
944    successful. Allocates new private key as well. */
945
946 bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
947                                   SilcPrivateKey *private_key)
948 {
949   SilcBuffer buf;
950   SilcPKCS alg;
951   SilcUInt16 pkcs_len;
952   SilcUInt32 key_len;
953   unsigned char *pkcs_name = NULL, *key_data = NULL;
954   int ret;
955
956   buf = silc_buffer_alloc(data_len);
957   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
958   silc_buffer_put(buf, data, data_len);
959
960   /* Get algorithm name and identifier */
961   ret = 
962     silc_buffer_unformat(buf,
963                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
964                          SILC_STR_END);
965   if (ret == -1) {
966     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
967     goto err;
968   }
969
970   if (pkcs_len < 1 || pkcs_len > buf->truelen) {
971     SILC_LOG_DEBUG(("Malformed private key buffer"));
972     goto err;
973   }
974
975   /* See if we support this algorithm (check only if PKCS are registered). */
976   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
977     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
978     goto err;
979   }
980
981   /* Get key data. We assume that rest of the buffer is key data. */
982   silc_buffer_pull(buf, 2 + pkcs_len);
983   key_len = buf->len;
984   ret = silc_buffer_unformat(buf,
985                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
986                              SILC_STR_END);
987   if (ret == -1)
988     goto err;
989
990   /* Try to set the key. If this fails the key must be malformed. This
991      code assumes that the PKCS routine checks the format of the key. 
992      (check only if PKCS are registered) */
993   if (SILC_PKCS_LIST) {
994     silc_pkcs_alloc(pkcs_name, &alg);
995     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
996       SILC_LOG_DEBUG(("Could not set private key data"));
997       goto err;
998     }
999     silc_pkcs_free(alg);
1000   }
1001   
1002   if (private_key) {
1003     *private_key = silc_calloc(1, sizeof(**private_key));
1004     (*private_key)->name = pkcs_name;
1005     (*private_key)->prv = key_data;
1006     (*private_key)->prv_len = key_len;
1007   }
1008
1009   silc_buffer_clear(buf);
1010   silc_buffer_free(buf);
1011   return TRUE;
1012
1013  err:
1014   if (pkcs_name)
1015     silc_free(pkcs_name);
1016   if (key_data)
1017     silc_free(key_data);
1018   silc_buffer_clear(buf);
1019   silc_buffer_free(buf);
1020   return FALSE;
1021 }
1022
1023 /* Internal routine to save public key */
1024
1025 static bool silc_pkcs_save_public_key_internal(char *filename,
1026                                                unsigned char *data,
1027                                                SilcUInt32 data_len,
1028                                                SilcUInt32 encoding)
1029 {
1030   SilcBuffer buf;
1031   SilcUInt32 len;
1032
1033   switch(encoding) {
1034   case SILC_PKCS_FILE_BIN:
1035     break;
1036   case SILC_PKCS_FILE_PEM:
1037     data = silc_pem_encode_file(data, data_len);
1038     data_len = strlen(data);
1039     break;
1040   }
1041
1042   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1043                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1044   buf = silc_buffer_alloc(len);
1045   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1046
1047   silc_buffer_format(buf,
1048                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1049                      SILC_STR_UI_XNSTRING(data, data_len),
1050                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1051                      SILC_STR_END);
1052
1053   /* Save into file */
1054   if (silc_file_writefile(filename, buf->data, buf->len)) {
1055     silc_buffer_free(buf);
1056     return FALSE;
1057   }
1058
1059   silc_buffer_free(buf);
1060   return TRUE;
1061 }
1062
1063 /* Saves public key into file */
1064
1065 bool silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1066                                SilcUInt32 encoding)
1067 {
1068   unsigned char *data;
1069   SilcUInt32 data_len;
1070   bool ret;
1071
1072   data = silc_pkcs_public_key_encode(public_key, &data_len);
1073   ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
1074                                            encoding);
1075   silc_free(data);
1076   return ret;
1077 }
1078
1079 /* Saves public key into file */
1080
1081 bool silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1082                                     SilcUInt32 data_len,
1083                                     SilcUInt32 encoding)
1084 {
1085   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1086                                             encoding);
1087 }
1088
1089 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
1090
1091 /* Internal routine to save private key. */
1092
1093 static bool silc_pkcs_save_private_key_internal(char *filename,
1094                                                 unsigned char *data,
1095                                                 SilcUInt32 data_len,
1096                                                 unsigned char *key,
1097                                                 SilcUInt32 key_len,
1098                                                 SilcUInt32 encoding)
1099 {
1100   SilcCipher aes;
1101   SilcHash md5;
1102   SilcHmac sha1hmac;
1103   SilcBuffer buf, enc;
1104   SilcUInt32 len, blocklen;
1105   unsigned char tmp[32], keymat[32];
1106   int i;
1107
1108   memset(tmp, 0, sizeof(tmp));
1109   memset(keymat, 0, sizeof(keymat));
1110
1111   /* Allocate the AES cipher */
1112   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1113     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1114     return FALSE;
1115   }
1116   blocklen = silc_cipher_get_block_len(aes);
1117   if (blocklen * 2 > sizeof(tmp))
1118     return FALSE;
1119
1120   /* Allocate MD5 hash */
1121   if (!silc_hash_alloc("md5", &md5)) {
1122     SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
1123     silc_cipher_free(aes);
1124     return FALSE;
1125   }
1126
1127   /* Allocate HMAC */
1128   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1129     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1130     silc_hash_free(md5);
1131     silc_cipher_free(aes);
1132     return FALSE;
1133   }
1134
1135   /* Derive the encryption key from the provided key material.  The key
1136      is 256 bits length, and derived by taking hash of the data, then 
1137      re-hashing the data and the previous digest, and using the first and
1138      second digest as the key. */
1139   silc_hash_init(md5);
1140   silc_hash_update(md5, key, key_len);
1141   silc_hash_final(md5, keymat);
1142   silc_hash_init(md5);
1143   silc_hash_update(md5, key, key_len);
1144   silc_hash_update(md5, keymat, 16);
1145   silc_hash_final(md5, keymat + 16);
1146
1147   /* Set the key to the cipher */
1148   silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
1149
1150   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1151      block size of the cipher. */
1152
1153   /* Allocate buffer for encryption */
1154   len = silc_hmac_len(sha1hmac);
1155   enc = silc_buffer_alloc_size(data_len + 4 + 4 +
1156                                (blocklen + (data_len % blocklen)) + len);
1157   if (!enc) {
1158     silc_hmac_free(sha1hmac);
1159     silc_hash_free(md5);
1160     silc_cipher_free(aes);
1161     return FALSE;
1162   }
1163
1164   /* Generate padding */
1165   for (i = 0; i < blocklen + (data_len % blocklen); i++)
1166     tmp[i] = silc_rng_global_get_byte_fast();
1167
1168   /* Put magic number */
1169   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1170   silc_buffer_pull(enc, 4);
1171
1172   /* Encode the buffer */
1173   silc_buffer_format(enc,
1174                      SILC_STR_UI_INT(data_len),
1175                      SILC_STR_UI_XNSTRING(data, data_len),
1176                      SILC_STR_UI_XNSTRING(tmp, blocklen + (data_len %
1177                                                            blocklen)),
1178                      SILC_STR_END);
1179
1180   /* Encrypt. */
1181   silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
1182                       silc_cipher_get_iv(aes));
1183
1184   silc_buffer_push(enc, 4);
1185
1186   /* Compute HMAC over the encrypted data and append the MAC to data.
1187      The key is the first digest of the original key material. */
1188   data_len = enc->len - len;
1189   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1190   silc_hmac_update(sha1hmac, enc->data, data_len);
1191   silc_buffer_pull(enc, data_len);
1192   silc_hmac_final(sha1hmac, enc->data, NULL);
1193   silc_buffer_push(enc, data_len);
1194
1195   /* Cleanup */
1196   memset(keymat, 0, sizeof(keymat));
1197   memset(tmp, 0, sizeof(tmp));
1198   silc_hmac_free(sha1hmac);
1199   silc_hash_free(md5);
1200   silc_cipher_free(aes);
1201
1202   data = enc->data;
1203   data_len = enc->len;
1204
1205   switch (encoding) {
1206   case SILC_PKCS_FILE_BIN:
1207     break;
1208   case SILC_PKCS_FILE_PEM:
1209     data = silc_pem_encode_file(data, data_len);
1210     data_len = strlen(data);
1211     break;
1212   }
1213
1214   /* Encode the data and save to file */
1215   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1216                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1217   buf = silc_buffer_alloc_size(len);
1218   silc_buffer_format(buf,
1219                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1220                      SILC_STR_UI_XNSTRING(data, data_len),
1221                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1222                      SILC_STR_END);
1223
1224   /* Save into a file */
1225   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1226     silc_buffer_clear(buf);
1227     silc_buffer_free(buf);
1228     silc_buffer_clear(enc);
1229     silc_buffer_free(enc);
1230     return FALSE;
1231   }
1232
1233   silc_buffer_clear(buf);
1234   silc_buffer_free(buf);
1235   silc_buffer_clear(enc);
1236   silc_buffer_free(enc);
1237   return TRUE;
1238 }
1239
1240 /* Saves private key into file. */
1241
1242 bool silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
1243                                 unsigned char *passphrase,
1244                                 SilcUInt32 passphrase_len,
1245                                 SilcUInt32 encoding)
1246 {
1247   unsigned char *data;
1248   SilcUInt32 data_len;
1249   bool ret;
1250
1251   data = silc_pkcs_private_key_encode(private_key, &data_len);
1252   ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
1253                                             passphrase, passphrase_len,
1254                                             encoding);
1255   memset(data, 0, data_len);
1256   silc_free(data);
1257   return ret;
1258 }
1259
1260 /* Loads public key from file and allocates new public key. Returns TRUE
1261    if loading was successful. */
1262
1263 bool silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1264                                SilcUInt32 encoding)
1265 {
1266   unsigned char *cp, *old, *data, byte;
1267   SilcUInt32 i, data_len, len;
1268
1269   old = data = silc_file_readfile(filename, &data_len);
1270   if (!data)
1271     return FALSE;
1272
1273   /* Check start of file and remove header from the data. */
1274   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1275   cp = data;
1276   for (i = 0; i < len; i++) {
1277     byte = cp[0];
1278     cp++;
1279     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1280       memset(old, 0, data_len);
1281       silc_free(old);
1282       return FALSE;
1283     }
1284   }
1285   data = cp;
1286
1287   /* Decode public key */
1288   if (public_key) {
1289     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1290                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1291
1292     switch(encoding) {
1293     case SILC_PKCS_FILE_BIN:
1294       break;
1295     case SILC_PKCS_FILE_PEM:
1296       data = silc_pem_decode(data, len, &len);
1297       memset(old, 0, data_len);
1298       silc_free(old);
1299       old = data; 
1300       data_len = len;
1301       break;
1302     }
1303
1304     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1305       memset(old, 0, data_len);
1306       silc_free(old);
1307       return FALSE;
1308     }
1309   }
1310
1311   memset(old, 0, data_len);
1312   silc_free(old);
1313   return TRUE;
1314 }
1315
1316 /* Load private key from file and allocates new private key. Returns TRUE
1317    if loading was successful. */
1318
1319 bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1320                                 unsigned char *passphrase,
1321                                 SilcUInt32 passphrase_len,
1322                                 SilcUInt32 encoding)
1323 {
1324   SilcCipher aes;
1325   SilcHash md5;
1326   SilcHmac sha1hmac;
1327   SilcUInt32 blocklen;
1328   unsigned char tmp[32], keymat[32];
1329   unsigned char *cp, *old, *data, byte;
1330   SilcUInt32 i, data_len, len, magic, mac_len;
1331
1332   old = data = silc_file_readfile(filename, &data_len);
1333   if (!data)
1334     return FALSE;
1335
1336   /* Check start of file and remove header from the data. */
1337   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1338   cp = data;
1339   for (i = 0; i < len; i++) {
1340     byte = cp[0];
1341     cp++;
1342     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1343       memset(old, 0, data_len);
1344       silc_free(old);
1345       return FALSE;
1346     }
1347   }
1348   data = cp;
1349
1350   /* Decode private key */
1351   len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1352                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1353
1354   switch(encoding) {
1355   case SILC_PKCS_FILE_BIN:
1356     break;
1357   case SILC_PKCS_FILE_PEM:
1358     data = silc_pem_decode(data, len, &len);
1359     if (!data) {
1360       memset(old, 0, data_len);
1361       silc_free(old);
1362       return FALSE;
1363     }
1364     break;
1365   }
1366
1367   memset(tmp, 0, sizeof(tmp));
1368   memset(keymat, 0, sizeof(keymat));
1369
1370   /* Private key files without the specific magic number are assumed
1371      to be the old-style private keys that are not encrypted. */
1372   SILC_GET32_MSB(magic, data);
1373   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
1374     /* Now decode the actual private key */
1375     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1376       memset(old, 0, data_len);
1377       silc_free(old);
1378       return FALSE;
1379     }
1380
1381     memset(old, 0, data_len);
1382     silc_free(old);
1383     return TRUE;
1384   }
1385
1386   /* Allocate the AES cipher */
1387   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1388     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1389     memset(old, 0, data_len);
1390     silc_free(old);
1391     return FALSE;
1392   }
1393   blocklen = silc_cipher_get_block_len(aes);
1394   if (blocklen * 2 > sizeof(tmp)) {
1395     memset(old, 0, data_len);
1396     silc_free(old);
1397     return FALSE;
1398   }
1399
1400   /* Allocate MD5 hash */
1401   if (!silc_hash_alloc("md5", &md5)) {
1402     SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
1403     silc_cipher_free(aes);
1404     memset(old, 0, data_len);
1405     silc_free(old);
1406     return FALSE;
1407   }
1408
1409   /* Allocate HMAC */
1410   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1411     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1412     silc_hash_free(md5);
1413     silc_cipher_free(aes);
1414     memset(old, 0, data_len);
1415     silc_free(old);
1416     return FALSE;
1417   }
1418
1419   /* Derive the decryption key from the provided key material.  The key
1420      is 256 bits length, and derived by taking hash of the data, then 
1421      re-hashing the data and the previous digest, and using the first and
1422      second digest as the key. */
1423   silc_hash_init(md5);
1424   silc_hash_update(md5, passphrase, passphrase_len);
1425   silc_hash_final(md5, keymat);
1426   silc_hash_init(md5);
1427   silc_hash_update(md5, passphrase, passphrase_len);
1428   silc_hash_update(md5, keymat, 16);
1429   silc_hash_final(md5, keymat + 16);
1430
1431   /* Set the key to the cipher */
1432   silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
1433
1434   /* First, verify the MAC of the private key data */
1435   mac_len = silc_hmac_len(sha1hmac);
1436   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1437   silc_hmac_update(sha1hmac, data, len - mac_len);
1438   silc_hmac_final(sha1hmac, tmp, NULL);
1439   if (memcmp(tmp, data + (len - mac_len), mac_len)) {
1440     SILC_LOG_DEBUG(("Integrity check for private key failed"));
1441     memset(keymat, 0, sizeof(keymat));
1442     memset(tmp, 0, sizeof(tmp));
1443     silc_hmac_free(sha1hmac);
1444     silc_hash_free(md5);
1445     silc_cipher_free(aes);
1446     memset(old, 0, data_len);
1447     silc_free(old);
1448     return FALSE;
1449   }
1450   data += 4;
1451   len -= 4;
1452
1453   /* Decrypt the private key buffer */
1454   silc_cipher_decrypt(aes, data, data, len - mac_len, silc_cipher_get_iv(aes));
1455   SILC_GET32_MSB(i, data);
1456   if (i > len) {
1457     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
1458     memset(keymat, 0, sizeof(keymat));
1459     memset(tmp, 0, sizeof(tmp));
1460     silc_hmac_free(sha1hmac);
1461     silc_hash_free(md5);
1462     silc_cipher_free(aes);
1463     memset(old, 0, data_len);
1464     silc_free(old);
1465     return FALSE;
1466   }
1467   data += 4;
1468   len = i;
1469
1470   /* Cleanup */
1471   memset(keymat, 0, sizeof(keymat));
1472   memset(tmp, 0, sizeof(tmp));
1473   silc_hmac_free(sha1hmac);
1474   silc_hash_free(md5);
1475   silc_cipher_free(aes);
1476
1477   /* Now decode the actual private key */
1478   if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1479     memset(old, 0, data_len);
1480     silc_free(old);
1481     return FALSE;
1482   }
1483
1484   memset(old, 0, data_len);
1485   silc_free(old);
1486   return TRUE;
1487 }