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