Code cleanups, more comments.
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2003 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   bool ret = pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
297   if (ret)
298     pkcs->key_len = bits_key_len;
299   return ret;
300 }
301
302 /* Returns the length of the key */
303
304 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
305 {
306   return pkcs->key_len;
307 }
308
309 const char *silc_pkcs_get_name(SilcPKCS pkcs)
310 {
311   return pkcs->pkcs->name;
312 }
313
314 /* Returns SILC style public key */
315
316 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
317 {
318   return pkcs->pkcs->get_public_key(pkcs->context, len);
319 }
320
321 /* Returns SILC style private key */
322
323 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
324 {
325   return pkcs->pkcs->get_private_key(pkcs->context, len);
326 }
327
328 /* Sets public key from SilcPublicKey. */
329
330 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
331 {
332   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
333                                              public_key->pk_len);
334   return pkcs->key_len;
335 }
336
337 /* Sets public key from data. */
338
339 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
340                                      SilcUInt32 pk_len)
341 {
342   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
343   return pkcs->key_len;
344 }
345
346 /* Sets private key from SilcPrivateKey. */
347
348 SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
349 {
350   SilcUInt32 key_len;
351   key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
352                                         private_key->prv_len);
353   if (!pkcs->key_len)
354     pkcs->key_len = key_len;
355   return pkcs->key_len;
356 }
357
358 /* Sets private key from data. */
359
360 SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
361                                           SilcUInt32 prv_len)
362 {
363   SilcUInt32 key_len;
364   key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
365   if (!pkcs->key_len)
366     pkcs->key_len = key_len;
367   return pkcs->key_len;
368 }
369
370 /* Encrypts */
371
372 bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
373                        unsigned char *dst, SilcUInt32 *dst_len)
374 {
375   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
376 }
377
378 /* Decrypts */
379
380 bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
381                        unsigned char *dst, SilcUInt32 *dst_len)
382 {
383   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
384 }
385
386 /* Generates signature */
387
388 bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
389                     unsigned char *dst, SilcUInt32 *dst_len)
390 {
391   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
392 }
393
394 /* Verifies signature */
395
396 bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
397                       SilcUInt32 signature_len, unsigned char *data,
398                       SilcUInt32 data_len)
399 {
400   return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
401                             data, data_len);
402 }
403
404 /* Generates signature with hash. The hash is signed. */
405
406 bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
407                               unsigned char *src, SilcUInt32 src_len,
408                               unsigned char *dst, SilcUInt32 *dst_len)
409 {
410   unsigned char hashr[32];
411   SilcUInt32 hash_len;
412   int ret;
413
414   silc_hash_make(hash, src, src_len, hashr);
415   hash_len = silc_hash_len(hash);
416
417   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
418
419   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
420   memset(hashr, 0, sizeof(hashr));
421
422   return ret;
423 }
424
425 /* Verifies signature with hash. The `data' is hashed and verified against
426    the `signature'. */
427
428 bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
429                                 unsigned char *signature,
430                                 SilcUInt32 signature_len,
431                                 unsigned char *data,
432                                 SilcUInt32 data_len)
433 {
434   unsigned char hashr[32];
435   SilcUInt32 hash_len;
436   int ret;
437
438   silc_hash_make(hash, data, data_len, hashr);
439   hash_len = silc_hash_len(hash);
440
441   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
442
443   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
444                            hashr, hash_len);
445   memset(hashr, 0, sizeof(hashr));
446
447   return ret;
448 }
449
450 /* Encodes and returns SILC public key identifier. If some of the
451    arguments is NULL those are not encoded into the identifier string.
452    Protocol says that at least username and host must be provided. */
453
454 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
455                                   char *email, char *org, char *country)
456 {
457   SilcBuffer buf;
458   char *identifier;
459   SilcUInt32 len, tlen = 0;
460
461   if (!username || !host)
462     return NULL;
463
464   len = (username ? strlen(username) : 0) +
465         (host     ? strlen(host)     : 0) +
466         (realname ? strlen(realname) : 0) +
467         (email    ? strlen(email)    : 0) +
468         (org      ? strlen(org)      : 0) +
469         (country  ? strlen(country)  : 0);
470
471   if (len < 3)
472     return NULL;
473
474   len += 3 + 5 + 5 + 4 + 4 + 4;
475   buf = silc_buffer_alloc(len);
476   silc_buffer_pull_tail(buf, len);
477
478   if (username) {
479     silc_buffer_format(buf,
480                        SILC_STR_UI32_STRING("UN="),
481                        SILC_STR_UI32_STRING(username),
482                        SILC_STR_END);
483     silc_buffer_pull(buf, 3 + strlen(username));
484     tlen = 3 + strlen(username);
485   }
486
487   if (host) {
488     silc_buffer_format(buf,
489                        SILC_STR_UI32_STRING(", "),
490                        SILC_STR_UI32_STRING("HN="),
491                        SILC_STR_UI32_STRING(host),
492                        SILC_STR_END);
493     silc_buffer_pull(buf, 5 + strlen(host));
494     tlen += 5 + strlen(host);
495   }
496
497   if (realname) {
498     silc_buffer_format(buf,
499                        SILC_STR_UI32_STRING(", "),
500                        SILC_STR_UI32_STRING("RN="),
501                        SILC_STR_UI32_STRING(realname),
502                        SILC_STR_END);
503     silc_buffer_pull(buf, 5 + strlen(realname));
504     tlen += 5 + strlen(realname);
505   }
506
507   if (email) {
508     silc_buffer_format(buf,
509                        SILC_STR_UI32_STRING(", "),
510                        SILC_STR_UI32_STRING("E="),
511                        SILC_STR_UI32_STRING(email),
512                        SILC_STR_END);
513     silc_buffer_pull(buf, 4 + strlen(email));
514     tlen += 4 + strlen(email);
515   }
516
517   if (org) {
518     silc_buffer_format(buf,
519                        SILC_STR_UI32_STRING(", "),
520                        SILC_STR_UI32_STRING("O="),
521                        SILC_STR_UI32_STRING(org),
522                        SILC_STR_END);
523     silc_buffer_pull(buf, 4 + strlen(org));
524     tlen += 4 + strlen(org);
525   }
526
527   if (country) {
528     silc_buffer_format(buf,
529                        SILC_STR_UI32_STRING(", "),
530                        SILC_STR_UI32_STRING("C="),
531                        SILC_STR_UI32_STRING(country),
532                        SILC_STR_END);
533     silc_buffer_pull(buf, 4 + strlen(country));
534     tlen += 4 + strlen(country);
535   }
536
537   silc_buffer_push(buf, buf->data - buf->head);
538   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
539   memcpy(identifier, buf->data, tlen);
540   silc_buffer_free(buf);
541
542   return identifier;
543 }
544
545 /* Decodes the provided `identifier' and returns allocated context for
546    the identifier. */
547
548 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
549 {
550   SilcPublicKeyIdentifier ident;
551   char *cp, *item;
552   int len;
553
554   ident = silc_calloc(1, sizeof(*ident));
555
556   cp = identifier;
557   while (cp) {
558     len = strcspn(cp, ",");
559     if (len < 1) {
560       cp = NULL;
561       break;
562     }
563     if (len - 1 >= 0 && cp[len - 1] == '\\') {
564       while (cp) {
565         if (len + 1 > strlen(cp)) {
566           cp = NULL;
567           break;
568         }
569         cp += len + 1;
570         len = strcspn(cp, ",") + len;
571         if (len < 1) {
572           cp = NULL;
573           break;
574         }
575         if (len - 1 >= 0 && cp[len - 1] != '\\')
576           break;
577       }
578     }
579
580     if (!cp)
581       break;
582
583     item = silc_calloc(len + 1, sizeof(char));
584     if (len > strlen(cp))
585       break;
586     memcpy(item, cp, len);
587
588     if (strstr(item, "UN="))
589       ident->username = strdup(item + strcspn(cp, "=") + 1);
590     else if (strstr(item, "HN="))
591       ident->host = strdup(item + strcspn(cp, "=") + 1);
592     else if (strstr(item, "RN="))
593       ident->realname = strdup(item + strcspn(cp, "=") + 1);
594     else if (strstr(item, "E="))
595       ident->email = strdup(item + strcspn(cp, "=") + 1);
596     else if (strstr(item, "O="))
597       ident->org = strdup(item + strcspn(cp, "=") + 1);
598     else if (strstr(item, "C="))
599       ident->country = strdup(item + strcspn(cp, "=") + 1);
600
601     cp += len;
602     if (strlen(cp) < 1)
603       cp = NULL;
604     else
605       cp += 1;
606
607     if (item)
608       silc_free(item);
609   }
610
611   return ident;
612 }
613
614 /* Free's decoded public key identifier context. Call this to free the
615    context returned by the silc_pkcs_decode_identifier. */
616
617 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
618 {
619   silc_free(identifier->username);
620   silc_free(identifier->host);
621   silc_free(identifier->realname);
622   silc_free(identifier->email);
623   silc_free(identifier->org);
624   silc_free(identifier->country);
625   silc_free(identifier);
626 }
627
628 /* Allocates SILC style public key formed from sent arguments. All data
629    is duplicated. */
630
631 SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
632                                          const char *identifier,
633                                          const unsigned char *pk,
634                                          SilcUInt32 pk_len)
635 {
636   SilcPublicKey public_key;
637   char *tmp = NULL;
638
639   public_key = silc_calloc(1, sizeof(*public_key));
640   public_key->name = strdup(name);
641   public_key->pk_len = pk_len;
642   public_key->pk = silc_memdup(pk, pk_len);
643   public_key->pk_type = SILC_SKE_PK_TYPE_SILC;
644
645   if (!silc_utf8_valid(identifier, strlen(identifier))) {
646     int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
647     tmp = silc_calloc(len + 1, sizeof(*tmp));
648     silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
649     identifier = tmp;
650   }
651
652   public_key->identifier = strdup(identifier);
653   public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
654   silc_free(tmp);
655
656   return public_key;
657 }
658
659 /* Free's public key */
660
661 void silc_pkcs_public_key_free(SilcPublicKey public_key)
662 {
663   if (public_key) {
664     silc_free(public_key->name);
665     silc_free(public_key->identifier);
666     silc_free(public_key->pk);
667     silc_free(public_key);
668   }
669 }
670
671 /* Allocates SILC private key formed from sent arguments. All data is
672    duplicated. */
673
674 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
675                                            const unsigned char *prv,
676                                            SilcUInt32 prv_len)
677 {
678   SilcPrivateKey private_key;
679
680   private_key = silc_calloc(1, sizeof(*private_key));
681   private_key->name = strdup(name);
682   private_key->prv_len = prv_len;
683   private_key->prv = silc_memdup(prv, prv_len);
684
685   return private_key;
686 }
687
688 /* Free's private key */
689
690 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
691 {
692   if (private_key) {
693     silc_free(private_key->name);
694     if (private_key->prv) {
695       memset(private_key->prv, 0, private_key->prv_len);
696       silc_free(private_key->prv);
697     }
698     silc_free(private_key);
699   }
700 }
701
702 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
703    data. */
704
705 unsigned char *
706 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
707 {
708   return silc_pkcs_public_key_data_encode(public_key->pk,
709                                           public_key->pk_len,
710                                           public_key->name,
711                                           public_key->identifier, len);
712 }
713
714 /* Encodes SILC style public key. Returns the encoded data. */
715
716 unsigned char *
717 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
718                                  char *pkcs, char *identifier,
719                                  SilcUInt32 *len)
720 {
721   SilcBuffer buf;
722   unsigned char *ret;
723   SilcUInt32 totlen;
724
725   totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
726   buf = silc_buffer_alloc_size(totlen + 4);
727   if (!buf)
728     return NULL;
729
730   silc_buffer_format(buf,
731                      SILC_STR_UI_INT(totlen),
732                      SILC_STR_UI_SHORT(strlen(pkcs)),
733                      SILC_STR_UI32_STRING(pkcs),
734                      SILC_STR_UI_SHORT(strlen(identifier)),
735                      SILC_STR_UI32_STRING(identifier),
736                      SILC_STR_UI_XNSTRING(pk, pk_len),
737                      SILC_STR_END);
738
739   ret = silc_buffer_steal(buf, len);
740   silc_buffer_free(buf);
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   SilcBufferStruct 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   silc_buffer_set(&buf, data, data_len);
758
759   /* Get length */
760   ret = silc_buffer_unformat(&buf,
761                              SILC_STR_UI_INT(&totlen),
762                              SILC_STR_END);
763   if (ret == -1)
764     return FALSE;
765
766 #if 1 /* Backwards support, remove! */
767   if (totlen == data_len)
768     totlen -= 4;
769 #endif
770
771   if (totlen + 4 != data_len)
772     return FALSE;
773
774   /* Get algorithm name and identifier */
775   silc_buffer_pull(&buf, 4);
776   ret =
777     silc_buffer_unformat(&buf,
778                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
779                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
780                          SILC_STR_END);
781   if (ret == -1)
782     goto err;
783
784   if (pkcs_len < 1 || identifier_len < 3 ||
785       pkcs_len + identifier_len > totlen)
786     goto err;
787
788   /* See if we support this algorithm (check only if PKCS are registered) */
789   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
790     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
791     goto err;
792   }
793
794   /* Protocol says that at least UN and HN must be provided as identifier,
795      check for these. */
796   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
797     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
798                     "identifiers"));
799     goto err;
800   }
801
802   /* Get key data. We assume that rest of the buffer is key data. */
803   silc_buffer_pull(&buf, 2 + pkcs_len + 2 + identifier_len);
804   key_len = buf.len;
805   ret = silc_buffer_unformat(&buf,
806                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
807                              SILC_STR_END);
808   if (ret == -1)
809     goto err;
810
811   /* Try to set the key. If this fails the key must be malformed. This
812      code assumes that the PKCS routine checks the format of the key.
813      (check only if PKCS are registered) */
814   if (SILC_PKCS_LIST) {
815     silc_pkcs_alloc(pkcs_name, &alg);
816     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
817       goto err;
818     silc_pkcs_free(alg);
819   }
820
821   if (public_key) {
822     *public_key = silc_calloc(1, sizeof(**public_key));
823     (*public_key)->len = totlen;
824     (*public_key)->name = pkcs_name;
825     (*public_key)->identifier = ident;
826     (*public_key)->pk = key_data;
827     (*public_key)->pk_len = key_len;
828     (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
829   }
830
831   return TRUE;
832
833  err:
834   silc_free(pkcs_name);
835   silc_free(ident);
836   silc_free(key_data);
837   return FALSE;
838 }
839
840 /* Encodes Public Key Payload for transmitting public keys and certificates. */
841
842 SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key)
843 {
844   SilcBuffer buffer;
845   unsigned char *pk;
846   SilcUInt32 pk_len;
847
848   if (!public_key)
849     return NULL;
850
851   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
852   if (!pk)
853     return NULL;
854
855   buffer = silc_buffer_alloc_size(4 + pk_len);
856   if (!buffer) {
857     silc_free(pk);
858     return NULL;
859   }
860
861   silc_buffer_format(buffer,
862                      SILC_STR_UI_SHORT(pk_len),
863                      SILC_STR_UI_SHORT(public_key->pk_type),
864                      SILC_STR_UI_XNSTRING(pk, pk_len),
865                      SILC_STR_END);
866
867   silc_free(pk);
868   return buffer;
869 }
870
871 /* Decode Public Key Payload and decodes the public key inside it to
872    to `payload'. */
873
874 bool silc_pkcs_public_key_payload_decode(unsigned char *data,
875                                          SilcUInt32 data_len,
876                                          SilcPublicKey *public_key)
877 {
878   SilcBufferStruct buf;
879   SilcUInt16 pk_len, pk_type;
880   unsigned char *pk;
881   int ret;
882
883   if (!public_key)
884     return FALSE;
885
886   silc_buffer_set(&buf, data, data_len);
887   ret = silc_buffer_unformat(&buf,
888                              SILC_STR_UI_SHORT(&pk_len),
889                              SILC_STR_UI_SHORT(&pk_type),
890                              SILC_STR_END);
891   if (ret < 0 || pk_len > data_len - 4)
892     return FALSE;
893
894   /* For now we support only SILC public keys */
895   if (pk_type != SILC_SKE_PK_TYPE_SILC)
896     return FALSE;
897
898   silc_buffer_pull(&buf, 4);
899   ret = silc_buffer_unformat(&buf,
900                              SILC_STR_UI_XNSTRING(&pk, pk_len),
901                              SILC_STR_END);
902   silc_buffer_push(&buf, 4);
903   if (ret < 0)
904     return FALSE;
905
906   if (!silc_pkcs_public_key_decode(pk, pk_len, public_key))
907     return FALSE;
908   (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
909
910   return TRUE;
911 }
912
913 /* Compares two public keys and returns TRUE if they are same key, and
914    FALSE if they are not same. */
915
916 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
917 {
918   if (key1 == key2)
919     return TRUE;
920
921   if (key1->len == key2->len &&
922       key1->name && key2->name && key1->identifier && key2->identifier &&
923       !strcmp(key1->name, key2->name) &&
924       !strcmp(key1->identifier, key2->identifier) &&
925       !memcmp(key1->pk, key2->pk, key1->pk_len) &&
926       key1->pk_len == key2->pk_len)
927     return TRUE;
928
929   return FALSE;
930 }
931
932 /* Copies the public key indicated by `public_key' and returns new allocated
933    public key which is indentical to the `public_key'. */
934
935 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
936 {
937   SilcPublicKey key = silc_calloc(1, sizeof(*key));
938   if (!key)
939     return NULL;
940
941   key->len = public_key->len;
942   key->name = silc_memdup(public_key->name, strlen(public_key->name));
943   key->identifier = silc_memdup(public_key->identifier,
944                                 strlen(public_key->identifier));
945   key->pk = silc_memdup(public_key->pk, public_key->pk_len);
946   key->pk_len = public_key->pk_len;
947   key->pk_type = public_key->pk_type;
948
949   return key;
950 }
951
952 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
953
954 unsigned char *
955 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
956 {
957   return silc_pkcs_private_key_data_encode(private_key->prv,
958                                            private_key->prv_len,
959                                            private_key->name, len);
960 }
961
962 /* Encodes SILC private key. Returns the encoded data. */
963
964 unsigned char *
965 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
966                                   char *pkcs, SilcUInt32 *len)
967 {
968   SilcBuffer buf;
969   unsigned char *ret;
970   SilcUInt32 totlen;
971
972   totlen = 2 + strlen(pkcs) + prv_len;
973   buf = silc_buffer_alloc_size(totlen);
974   if (!buf)
975     return NULL;
976
977   silc_buffer_format(buf,
978                      SILC_STR_UI_SHORT(strlen(pkcs)),
979                      SILC_STR_UI32_STRING(pkcs),
980                      SILC_STR_UI_XNSTRING(prv, prv_len),
981                      SILC_STR_END);
982
983   ret = silc_buffer_steal(buf, len);
984   silc_buffer_free(buf);
985   return ret;
986 }
987
988 /* Decodes SILC style private key. Returns TRUE if the decoding was
989    successful. Allocates new private key as well. */
990
991 bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
992                                   SilcPrivateKey *private_key)
993 {
994   SilcBufferStruct buf;
995   SilcPKCS alg;
996   SilcUInt16 pkcs_len;
997   SilcUInt32 key_len;
998   unsigned char *pkcs_name = NULL, *key_data = NULL;
999   int ret;
1000
1001   silc_buffer_set(&buf, data, data_len);
1002
1003   /* Get algorithm name and identifier */
1004   ret =
1005     silc_buffer_unformat(&buf,
1006                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1007                          SILC_STR_END);
1008   if (ret == -1) {
1009     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1010     goto err;
1011   }
1012
1013   if (pkcs_len < 1 || pkcs_len > buf.truelen) {
1014     SILC_LOG_DEBUG(("Malformed private key buffer"));
1015     goto err;
1016   }
1017
1018   /* See if we support this algorithm (check only if PKCS are registered). */
1019   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
1020     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
1021     goto err;
1022   }
1023
1024   /* Get key data. We assume that rest of the buffer is key data. */
1025   silc_buffer_pull(&buf, 2 + pkcs_len);
1026   key_len = buf.len;
1027   ret = silc_buffer_unformat(&buf,
1028                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
1029                              SILC_STR_END);
1030   if (ret == -1)
1031     goto err;
1032
1033   /* Try to set the key. If this fails the key must be malformed. This
1034      code assumes that the PKCS routine checks the format of the key.
1035      (check only if PKCS are registered) */
1036   if (SILC_PKCS_LIST) {
1037     silc_pkcs_alloc(pkcs_name, &alg);
1038     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
1039       SILC_LOG_DEBUG(("Could not set private key data"));
1040       goto err;
1041     }
1042     silc_pkcs_free(alg);
1043   }
1044
1045   if (private_key) {
1046     *private_key = silc_calloc(1, sizeof(**private_key));
1047     (*private_key)->name = pkcs_name;
1048     (*private_key)->prv = key_data;
1049     (*private_key)->prv_len = key_len;
1050   }
1051
1052   return TRUE;
1053
1054  err:
1055   silc_free(pkcs_name);
1056   silc_free(key_data);
1057   return FALSE;
1058 }
1059
1060 /* Internal routine to save public key */
1061
1062 static bool silc_pkcs_save_public_key_internal(const char *filename,
1063                                                unsigned char *data,
1064                                                SilcUInt32 data_len,
1065                                                SilcUInt32 encoding)
1066 {
1067   SilcBuffer buf;
1068   SilcUInt32 len;
1069   unsigned char *tmp = NULL;
1070
1071   switch(encoding) {
1072   case SILC_PKCS_FILE_BIN:
1073     break;
1074   case SILC_PKCS_FILE_PEM:
1075     tmp = data = silc_pem_encode_file(data, data_len);
1076     data_len = strlen(data);
1077     break;
1078   }
1079
1080   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1081                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1082   buf = silc_buffer_alloc_size(len);
1083   if (!buf) {
1084     silc_free(tmp);
1085     return FALSE;
1086   }
1087
1088   silc_buffer_format(buf,
1089                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1090                      SILC_STR_UI_XNSTRING(data, data_len),
1091                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1092                      SILC_STR_END);
1093
1094   /* Save into file */
1095   if (silc_file_writefile(filename, buf->data, buf->len)) {
1096     silc_free(tmp);
1097     silc_buffer_free(buf);
1098     return FALSE;
1099   }
1100
1101   silc_free(tmp);
1102   silc_buffer_free(buf);
1103   return TRUE;
1104 }
1105
1106 /* Saves public key into file */
1107
1108 bool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
1109                                SilcUInt32 encoding)
1110 {
1111   unsigned char *data;
1112   SilcUInt32 data_len;
1113   bool ret;
1114
1115   data = silc_pkcs_public_key_encode(public_key, &data_len);
1116   ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
1117                                            encoding);
1118   silc_free(data);
1119   return ret;
1120 }
1121
1122 /* Saves public key into file */
1123
1124 bool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
1125                                     SilcUInt32 data_len, SilcUInt32 encoding)
1126 {
1127   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1128                                             encoding);
1129 }
1130
1131 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
1132
1133 /* Internal routine to save private key. */
1134
1135 static bool silc_pkcs_save_private_key_internal(const char *filename,
1136                                                 unsigned char *data,
1137                                                 SilcUInt32 data_len,
1138                                                 unsigned char *key,
1139                                                 SilcUInt32 key_len,
1140                                                 SilcUInt32 encoding)
1141 {
1142   SilcCipher aes;
1143   SilcHash sha1;
1144   SilcHmac sha1hmac;
1145   SilcBuffer buf, enc;
1146   SilcUInt32 len, blocklen, padlen;
1147   unsigned char tmp[32], keymat[64];
1148   int i;
1149
1150   memset(tmp, 0, sizeof(tmp));
1151   memset(keymat, 0, sizeof(keymat));
1152
1153   /* Allocate the AES cipher */
1154   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1155     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1156     return FALSE;
1157   }
1158   blocklen = silc_cipher_get_block_len(aes);
1159   if (blocklen * 2 > sizeof(tmp))
1160     return FALSE;
1161
1162   /* Allocate SHA1 hash */
1163   if (!silc_hash_alloc("sha1", &sha1)) {
1164     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1165     silc_cipher_free(aes);
1166     return FALSE;
1167   }
1168
1169   /* Allocate HMAC */
1170   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1171     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1172     silc_hash_free(sha1);
1173     silc_cipher_free(aes);
1174     return FALSE;
1175   }
1176
1177   /* Derive the encryption key from the provided key material.  The key
1178      is 256 bits length, and derived by taking hash of the data, then
1179      re-hashing the data and the previous digest, and using the first and
1180      second digest as the key. */
1181   silc_hash_init(sha1);
1182   silc_hash_update(sha1, key, key_len);
1183   silc_hash_final(sha1, keymat);
1184   silc_hash_init(sha1);
1185   silc_hash_update(sha1, key, key_len);
1186   silc_hash_update(sha1, keymat, 16);
1187   silc_hash_final(sha1, keymat + 16);
1188
1189   /* Set the key to the cipher */
1190   silc_cipher_set_key(aes, keymat, 256);
1191
1192   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1193      block size of the cipher. */
1194
1195   /* Allocate buffer for encryption */
1196   len = silc_hmac_len(sha1hmac);
1197   padlen = 16 + (16 - ((data_len + 4) % blocklen));
1198   enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len);
1199   if (!enc) {
1200     silc_hmac_free(sha1hmac);
1201     silc_hash_free(sha1);
1202     silc_cipher_free(aes);
1203     return FALSE;
1204   }
1205
1206   /* Generate padding */
1207   for (i = 0; i < padlen; i++)
1208     tmp[i] = silc_rng_global_get_byte_fast();
1209
1210   /* Put magic number */
1211   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1212   silc_buffer_pull(enc, 4);
1213
1214   /* Encode the buffer */
1215   silc_buffer_format(enc,
1216                      SILC_STR_UI_INT(data_len),
1217                      SILC_STR_UI_XNSTRING(data, data_len),
1218                      SILC_STR_UI_XNSTRING(tmp, padlen),
1219                      SILC_STR_END);
1220
1221   /* Encrypt. */
1222   silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
1223                       silc_cipher_get_iv(aes));
1224
1225   silc_buffer_push(enc, 4);
1226
1227   /* Compute HMAC over the encrypted data and append the MAC to data.
1228      The key is the first digest of the original key material. */
1229   data_len = enc->len - len;
1230   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1231   silc_hmac_update(sha1hmac, enc->data, data_len);
1232   silc_buffer_pull(enc, data_len);
1233   silc_hmac_final(sha1hmac, enc->data, NULL);
1234   silc_buffer_push(enc, data_len);
1235
1236   /* Cleanup */
1237   memset(keymat, 0, sizeof(keymat));
1238   memset(tmp, 0, sizeof(tmp));
1239   silc_hmac_free(sha1hmac);
1240   silc_hash_free(sha1);
1241   silc_cipher_free(aes);
1242
1243   data = enc->data;
1244   data_len = enc->len;
1245
1246   switch (encoding) {
1247   case SILC_PKCS_FILE_BIN:
1248     break;
1249   case SILC_PKCS_FILE_PEM:
1250     data = silc_pem_encode_file(data, data_len);
1251     data_len = strlen(data);
1252     break;
1253   }
1254
1255   /* Encode the data and save to file */
1256   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1257                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1258   buf = silc_buffer_alloc_size(len);
1259   silc_buffer_format(buf,
1260                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1261                      SILC_STR_UI_XNSTRING(data, data_len),
1262                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1263                      SILC_STR_END);
1264
1265   /* Save into a file */
1266   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1267     silc_buffer_clear(buf);
1268     silc_buffer_free(buf);
1269     silc_buffer_clear(enc);
1270     silc_buffer_free(enc);
1271     return FALSE;
1272   }
1273
1274   silc_buffer_clear(buf);
1275   silc_buffer_free(buf);
1276   silc_buffer_clear(enc);
1277   silc_buffer_free(enc);
1278   return TRUE;
1279 }
1280
1281 /* Saves private key into file. */
1282
1283 bool silc_pkcs_save_private_key(const char *filename,
1284                                 SilcPrivateKey private_key,
1285                                 unsigned char *passphrase,
1286                                 SilcUInt32 passphrase_len,
1287                                 SilcUInt32 encoding)
1288 {
1289   unsigned char *data;
1290   SilcUInt32 data_len;
1291   bool ret;
1292
1293   data = silc_pkcs_private_key_encode(private_key, &data_len);
1294   ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
1295                                             passphrase, passphrase_len,
1296                                             encoding);
1297   memset(data, 0, data_len);
1298   silc_free(data);
1299   return ret;
1300 }
1301
1302 /* Loads public key from file and allocates new public key. Returns TRUE
1303    if loading was successful. */
1304
1305 bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
1306                                SilcUInt32 encoding)
1307 {
1308   unsigned char *cp, *old, *data, byte;
1309   SilcUInt32 i, data_len, len;
1310
1311   SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
1312                   encoding == SILC_PKCS_FILE_PEM ? "Base64" :
1313                   encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
1314
1315   old = data = silc_file_readfile(filename, &data_len);
1316   if (!data)
1317     return FALSE;
1318
1319   /* Check start of file and remove header from the data. */
1320   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1321   cp = data;
1322   for (i = 0; i < len; i++) {
1323     byte = cp[0];
1324     cp++;
1325     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1326       memset(old, 0, data_len);
1327       silc_free(old);
1328       return FALSE;
1329     }
1330   }
1331   data = cp;
1332
1333   /* Decode public key */
1334   if (public_key) {
1335     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1336                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1337
1338     switch(encoding) {
1339     case SILC_PKCS_FILE_BIN:
1340       break;
1341     case SILC_PKCS_FILE_PEM:
1342       data = silc_pem_decode(data, len, &len);
1343       memset(old, 0, data_len);
1344       silc_free(old);
1345       old = data;
1346       data_len = len;
1347       break;
1348     }
1349
1350     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1351       memset(old, 0, data_len);
1352       silc_free(old);
1353       return FALSE;
1354     }
1355   }
1356
1357   memset(old, 0, data_len);
1358   silc_free(old);
1359   return TRUE;
1360 }
1361
1362 /* Load private key from file and allocates new private key. Returns TRUE
1363    if loading was successful. */
1364
1365 bool silc_pkcs_load_private_key(const char *filename,
1366                                 SilcPrivateKey *private_key,
1367                                 unsigned char *passphrase,
1368                                 SilcUInt32 passphrase_len,
1369                                 SilcUInt32 encoding)
1370 {
1371   SilcCipher aes;
1372   SilcHash sha1;
1373   SilcHmac sha1hmac;
1374   SilcUInt32 blocklen;
1375   unsigned char tmp[32], keymat[64];
1376   unsigned char *cp, *old, *data, byte;
1377   SilcUInt32 i, data_len, len, magic, mac_len;
1378
1379   SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
1380                   encoding == SILC_PKCS_FILE_PEM ? "Base64" :
1381                   encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
1382
1383   old = data = silc_file_readfile(filename, &data_len);
1384   if (!data)
1385     return FALSE;
1386
1387   /* Check start of file and remove header from the data. */
1388   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1389   cp = data;
1390   for (i = 0; i < len; i++) {
1391     byte = cp[0];
1392     cp++;
1393     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1394       memset(old, 0, data_len);
1395       silc_free(old);
1396       return FALSE;
1397     }
1398   }
1399   data = cp;
1400
1401   /* Decode private key */
1402   len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1403                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1404
1405   switch(encoding) {
1406   case SILC_PKCS_FILE_BIN:
1407     break;
1408   case SILC_PKCS_FILE_PEM:
1409     data = silc_pem_decode(data, len, &len);
1410     if (!data) {
1411       memset(old, 0, data_len);
1412       silc_free(old);
1413       return FALSE;
1414     }
1415     break;
1416   }
1417
1418   memset(tmp, 0, sizeof(tmp));
1419   memset(keymat, 0, sizeof(keymat));
1420
1421   /* Private key files without the specific magic number are assumed
1422      to be the old-style private keys that are not encrypted. */
1423   SILC_GET32_MSB(magic, data);
1424   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
1425     SILC_LOG_DEBUG(("Private key does not have correct magic!"));
1426
1427     /* Now decode the actual private key */
1428     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1429       memset(old, 0, data_len);
1430       silc_free(old);
1431       return FALSE;
1432     }
1433
1434     memset(old, 0, data_len);
1435     silc_free(old);
1436     return TRUE;
1437   }
1438
1439   /* Allocate the AES cipher */
1440   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1441     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1442     memset(old, 0, data_len);
1443     silc_free(old);
1444     return FALSE;
1445   }
1446   blocklen = silc_cipher_get_block_len(aes);
1447   if (blocklen * 2 > sizeof(tmp)) {
1448     memset(old, 0, data_len);
1449     silc_free(old);
1450     return FALSE;
1451   }
1452
1453   /* Allocate SHA1 hash */
1454   if (!silc_hash_alloc("sha1", &sha1)) {
1455     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1456     silc_cipher_free(aes);
1457     memset(old, 0, data_len);
1458     silc_free(old);
1459     return FALSE;
1460   }
1461
1462   /* Allocate HMAC */
1463   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1464     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1465     silc_hash_free(sha1);
1466     silc_cipher_free(aes);
1467     memset(old, 0, data_len);
1468     silc_free(old);
1469     return FALSE;
1470   }
1471
1472   /* Derive the decryption key from the provided key material.  The key
1473      is 256 bits length, and derived by taking hash of the data, then
1474      re-hashing the data and the previous digest, and using the first and
1475      second digest as the key. */
1476   silc_hash_init(sha1);
1477   silc_hash_update(sha1, passphrase, passphrase_len);
1478   silc_hash_final(sha1, keymat);
1479   silc_hash_init(sha1);
1480   silc_hash_update(sha1, passphrase, passphrase_len);
1481   silc_hash_update(sha1, keymat, 16);
1482   silc_hash_final(sha1, keymat + 16);
1483
1484   /* Set the key to the cipher */
1485   silc_cipher_set_key(aes, keymat, 256);
1486
1487   /* First, verify the MAC of the private key data */
1488   mac_len = silc_hmac_len(sha1hmac);
1489   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1490   silc_hmac_update(sha1hmac, data, len - mac_len);
1491   silc_hmac_final(sha1hmac, tmp, NULL);
1492   if (memcmp(tmp, data + (len - mac_len), mac_len)) {
1493     SILC_LOG_DEBUG(("Integrity check for private key failed"));
1494     memset(keymat, 0, sizeof(keymat));
1495     memset(tmp, 0, sizeof(tmp));
1496     silc_hmac_free(sha1hmac);
1497     silc_hash_free(sha1);
1498     silc_cipher_free(aes);
1499     memset(old, 0, data_len);
1500     silc_free(old);
1501     return FALSE;
1502   }
1503   data += 4;
1504   len -= 4;
1505
1506   /* Decrypt the private key buffer */
1507   silc_cipher_decrypt(aes, data, data, len - mac_len, NULL);
1508   SILC_GET32_MSB(i, data);
1509   if (i > len) {
1510     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
1511     memset(keymat, 0, sizeof(keymat));
1512     memset(tmp, 0, sizeof(tmp));
1513     silc_hmac_free(sha1hmac);
1514     silc_hash_free(sha1);
1515     silc_cipher_free(aes);
1516     memset(old, 0, data_len);
1517     silc_free(old);
1518     return FALSE;
1519   }
1520   data += 4;
1521   len = i;
1522
1523   /* Cleanup */
1524   memset(keymat, 0, sizeof(keymat));
1525   memset(tmp, 0, sizeof(tmp));
1526   silc_hmac_free(sha1hmac);
1527   silc_hash_free(sha1);
1528   silc_cipher_free(aes);
1529
1530   /* Now decode the actual private key */
1531   if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1532     memset(old, 0, data_len);
1533     silc_free(old);
1534     return FALSE;
1535   }
1536
1537   memset(old, 0, data_len);
1538   silc_free(old);
1539   return TRUE;
1540 }