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