updates.
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 #include "rsa.h"
25 #include "pkcs1.h"
26
27 /* Dynamically registered list of PKCS. */
28 SilcDList silc_pkcs_list = NULL;
29
30 /* Static list of PKCS for silc_pkcs_register_default(). */
31 SilcPKCSObject silc_default_pkcs[] =
32 {
33   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
34   { "rsa", 
35     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
36     silc_rsa_get_private_key, silc_rsa_set_public_key,
37     silc_rsa_set_private_key, silc_rsa_context_len,
38     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
39     silc_pkcs1_sign, silc_pkcs1_verify },
40
41   /* Raw RSA operations */
42   { "rsa-raw", 
43     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
44     silc_rsa_get_private_key, silc_rsa_set_public_key,
45     silc_rsa_set_private_key, silc_rsa_context_len,
46     silc_rsa_encrypt, silc_rsa_decrypt,
47     silc_rsa_sign, silc_rsa_verify },
48
49   { NULL, NULL, NULL, NULL, NULL,
50     NULL, NULL, NULL, NULL, NULL, NULL }
51 };
52
53 /* Register a new PKCS into SILC. This is used at the initialization of
54    the SILC. */
55
56 bool silc_pkcs_register(SilcPKCSObject *pkcs)
57 {
58   SilcPKCSObject *new;
59
60   SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
61
62   new = silc_calloc(1, sizeof(*new));
63   new->name = strdup(pkcs->name);
64   new->init = pkcs->init;
65   new->clear_keys = pkcs->clear_keys;
66   new->get_public_key = pkcs->get_public_key;
67   new->get_private_key = pkcs->get_private_key;
68   new->set_public_key = pkcs->set_public_key;
69   new->set_private_key = pkcs->set_private_key;
70   new->context_len = pkcs->context_len;
71   new->encrypt = pkcs->encrypt;
72   new->decrypt = pkcs->decrypt;
73   new->sign = pkcs->sign;
74   new->verify = pkcs->verify;
75
76   /* Add to list */
77   if (silc_pkcs_list == NULL)
78     silc_pkcs_list = silc_dlist_init();
79   silc_dlist_add(silc_pkcs_list, new);
80
81   return TRUE;
82 }
83
84 /* Unregister a PKCS from the SILC. */
85
86 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
87 {
88   SilcPKCSObject *entry;
89
90   SILC_LOG_DEBUG(("Unregistering PKCS"));
91
92   if (!silc_pkcs_list)
93     return FALSE;
94
95   silc_dlist_start(silc_pkcs_list);
96   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
97     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
98       silc_dlist_del(silc_pkcs_list, entry);
99
100       if (silc_dlist_count(silc_pkcs_list) == 0) {
101         silc_dlist_uninit(silc_pkcs_list);
102         silc_pkcs_list = NULL;
103       }
104
105       return TRUE;
106     }
107   }
108
109   return FALSE;
110 }
111
112 /* Function that registers all the default PKCS (all builtin PKCS). 
113    The application may use this to register the default PKCS if specific
114    PKCS in any specific order is not wanted. */
115
116 bool silc_pkcs_register_default(void)
117 {
118   int i;
119
120   for (i = 0; silc_default_pkcs[i].name; i++)
121     silc_pkcs_register(&(silc_default_pkcs[i]));
122
123   return TRUE;
124 }
125
126 /* Allocates a new SilcPKCS object. The new allocated object is returned
127    to the 'new_pkcs' argument. */
128
129 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
130 {
131   SilcPKCSObject *entry;
132
133   SILC_LOG_DEBUG(("Allocating new PKCS object"));
134
135   if (silc_pkcs_list) {
136     silc_dlist_start(silc_pkcs_list);
137     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
138       if (!strcmp(entry->name, name)) {
139         *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
140         (*new_pkcs)->pkcs = entry;
141         (*new_pkcs)->context = silc_calloc(1, entry->context_len());
142         (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
143         return TRUE;
144       }
145     }
146   }
147
148   return FALSE;
149 }
150
151 /* Free's the PKCS object */
152
153 void silc_pkcs_free(SilcPKCS pkcs)
154 {
155   if (pkcs)
156     silc_free(pkcs->context);
157   silc_free(pkcs);
158 }
159
160 /* Return TRUE if PKCS algorithm `name' is supported. */
161
162 int silc_pkcs_is_supported(const unsigned char *name)
163 {
164   SilcPKCSObject *entry;
165
166   if (silc_pkcs_list) {
167     silc_dlist_start(silc_pkcs_list);
168     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
169       if (!strcmp(entry->name, name))
170         return TRUE;
171     }
172   }
173
174   return FALSE;
175 }
176
177 /* Returns comma separated list of supported PKCS algorithms */
178
179 char *silc_pkcs_get_supported(void)
180 {
181   SilcPKCSObject *entry;
182   char *list = NULL;
183   int len;
184
185   len = 0;
186   if (silc_pkcs_list) {
187     silc_dlist_start(silc_pkcs_list);
188     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
189       len += strlen(entry->name);
190       list = silc_realloc(list, len + 1);
191       
192       memcpy(list + (len - strlen(entry->name)), 
193              entry->name, strlen(entry->name));
194       memcpy(list + len, ",", 1);
195       len++;
196     }
197     list[len - 1] = 0;
198   }
199
200   return list;
201 }
202
203 /* Returns the length of the key */
204
205 uint32 silc_pkcs_get_key_len(SilcPKCS self)
206 {
207   return self->key_len;
208 }
209
210 /* Returns SILC style public key */
211
212 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, uint32 *len)
213 {
214   return pkcs->pkcs->get_public_key(pkcs->context, len);
215 }
216
217 /* Returns SILC style private key */
218
219 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, uint32 *len)
220 {
221   return pkcs->pkcs->get_private_key(pkcs->context, len);
222 }
223
224 /* Sets public key from SilcPublicKey. */
225
226 uint32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
227 {
228   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
229                                              public_key->pk_len);
230   return pkcs->key_len;
231 }
232
233 /* Sets public key from data. */
234
235 uint32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
236                                      uint32 pk_len)
237 {
238   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
239   return pkcs->key_len;
240 }
241
242 /* Sets private key from SilcPrivateKey. */
243
244 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
245 {
246   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
247                                      private_key->prv_len);
248 }
249
250 /* Sets private key from data. */
251
252 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
253                                    uint32 prv_len)
254 {
255   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
256 }
257
258 /* Encrypts */
259
260 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
261                       unsigned char *dst, uint32 *dst_len)
262 {
263   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
264 }
265
266 /* Decrypts */
267
268 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
269                       unsigned char *dst, uint32 *dst_len)
270 {
271   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
272 }
273
274 /* Generates signature */
275
276 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
277                    unsigned char *dst, uint32 *dst_len)
278 {
279   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
280 }
281
282 /* Verifies signature */
283
284 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
285                      uint32 signature_len, unsigned char *data, 
286                      uint32 data_len)
287 {
288   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
289                             data, data_len);
290 }
291
292 /* Generates signature with hash. The hash is signed. */
293
294 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
295                              unsigned char *src, uint32 src_len,
296                              unsigned char *dst, uint32 *dst_len)
297 {
298   unsigned char hashr[32];
299   uint32 hash_len;
300   int ret;
301
302   silc_hash_make(hash, src, src_len, hashr);
303   hash_len = hash->hash->hash_len;
304
305   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
306
307   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
308   memset(hashr, 0, sizeof(hashr));
309
310   return ret;
311 }
312
313 /* Verifies signature with hash. The `data' is hashed and verified against
314    the `signature'. */
315
316 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
317                                unsigned char *signature, 
318                                uint32 signature_len, 
319                                unsigned char *data, 
320                                uint32 data_len)
321 {
322   unsigned char hashr[32];
323   uint32 hash_len;
324   int ret;
325
326   silc_hash_make(hash, data, data_len, hashr);
327   hash_len = hash->hash->hash_len;
328
329   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
330
331   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
332                            hashr, hash_len);
333   memset(hashr, 0, sizeof(hashr));
334
335   return ret;
336 }
337
338 /* Encodes and returns SILC public key identifier. If some of the 
339    arguments is NULL those are not encoded into the identifier string.
340    Protocol says that at least username and host must be provided. */
341
342 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
343                                   char *email, char *org, char *country)
344 {
345   SilcBuffer buf;
346   char *identifier;
347   uint32 len, tlen = 0;
348
349   if (!username || !host)
350     return NULL;
351
352   len = (username ? strlen(username) : 0) +
353         (host     ? strlen(host)     : 0) +
354         (realname ? strlen(realname) : 0) +
355         (email    ? strlen(email)    : 0) +
356         (org      ? strlen(org)      : 0) +
357         (country  ? strlen(country)  : 0);
358   
359   if (len < 3)
360     return NULL;
361
362   len += 3 + 5 + 5 + 4 + 4 + 4;
363   buf = silc_buffer_alloc(len);
364   silc_buffer_pull_tail(buf, len);
365
366   if (username) {
367     silc_buffer_format(buf,
368                        SILC_STR_UI32_STRING("UN="),
369                        SILC_STR_UI32_STRING(username),
370                        SILC_STR_END);
371     silc_buffer_pull(buf, 3 + strlen(username));
372     tlen = 3 + strlen(username); 
373   }
374     
375   if (host) {
376     silc_buffer_format(buf,
377                        SILC_STR_UI32_STRING(", "),
378                        SILC_STR_UI32_STRING("HN="),
379                        SILC_STR_UI32_STRING(host),
380                        SILC_STR_END);
381     silc_buffer_pull(buf, 5 + strlen(host));
382     tlen += 5 + strlen(host); 
383   }
384
385   if (realname) {
386     silc_buffer_format(buf,
387                        SILC_STR_UI32_STRING(", "),
388                        SILC_STR_UI32_STRING("RN="),
389                        SILC_STR_UI32_STRING(realname),
390                        SILC_STR_END);
391     silc_buffer_pull(buf, 5 + strlen(realname));
392     tlen += 5 + strlen(realname); 
393   }
394
395   if (email) {
396     silc_buffer_format(buf,
397                        SILC_STR_UI32_STRING(", "),
398                        SILC_STR_UI32_STRING("E="),
399                        SILC_STR_UI32_STRING(email),
400                        SILC_STR_END);
401     silc_buffer_pull(buf, 4 + strlen(email));
402     tlen += 4 + strlen(email); 
403   }
404
405   if (org) {
406     silc_buffer_format(buf,
407                        SILC_STR_UI32_STRING(", "),
408                        SILC_STR_UI32_STRING("O="),
409                        SILC_STR_UI32_STRING(org),
410                        SILC_STR_END);
411     silc_buffer_pull(buf, 4 + strlen(org));
412     tlen += 4 + strlen(org); 
413   }
414
415   if (country) {
416     silc_buffer_format(buf,
417                        SILC_STR_UI32_STRING(", "),
418                        SILC_STR_UI32_STRING("C="),
419                        SILC_STR_UI32_STRING(country),
420                        SILC_STR_END);
421     silc_buffer_pull(buf, 4 + strlen(country));
422     tlen += 4 + strlen(country); 
423   }
424
425   silc_buffer_push(buf, buf->data - buf->head);
426   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
427   memcpy(identifier, buf->data, tlen);
428   silc_buffer_free(buf);
429
430   return identifier;
431 }
432
433 /* Decodes the provided `identifier' and returns allocated context for
434    the identifier. */
435
436 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
437 {
438   SilcPublicKeyIdentifier ident;
439   char *cp, *item;
440   int len;
441
442   ident = silc_calloc(1, sizeof(*ident));
443
444   cp = identifier;
445   while (cp) {
446     len = strcspn(cp, ",");
447     if (len - 1 >= 0 && cp[len - 1] == '\\') {
448       while (cp) {
449         cp += len + 1;
450         len = strcspn(cp, ",") + len;
451         if (len - 1 >= 0 && cp[len - 1] != '\\')
452           break;
453       }
454     }
455
456     item = silc_calloc(len + 1, sizeof(char));
457     memcpy(item, cp, len);
458
459     if (strstr(item, "UN="))
460       ident->username = strdup(item + strcspn(cp, "=") + 1);
461     else if (strstr(item, "HN="))
462       ident->host = strdup(item + strcspn(cp, "=") + 1);
463     else if (strstr(item, "RN="))
464       ident->realname = strdup(item + strcspn(cp, "=") + 1);
465     else if (strstr(item, "E="))
466       ident->email = strdup(item + strcspn(cp, "=") + 1);
467     else if (strstr(item, "O="))
468       ident->org = strdup(item + strcspn(cp, "=") + 1);
469     else if (strstr(item, "C="))
470       ident->country = strdup(item + strcspn(cp, "=") + 1);
471     
472     cp += len;
473     if (strlen(cp) == 0)
474       cp = NULL;
475     else
476       cp += 1;
477     
478     if (item)
479       silc_free(item);
480   }
481
482   return ident;
483 }
484
485 /* Free's decoded public key identifier context. Call this to free the
486    context returned by the silc_pkcs_decode_identifier. */
487
488 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
489 {
490   silc_free(identifier->username);
491   silc_free(identifier->host);
492   silc_free(identifier->realname);
493   silc_free(identifier->email);
494   silc_free(identifier->org);
495   silc_free(identifier->country);
496   silc_free(identifier);
497 }
498
499 /* Allocates SILC style public key formed from sent arguments. All data
500    is duplicated. */
501
502 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
503                                          unsigned char *pk, 
504                                          uint32 pk_len)
505 {
506   SilcPublicKey public_key;
507
508   public_key = silc_calloc(1, sizeof(*public_key));
509   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
510   public_key->name = strdup(name);
511   public_key->identifier = strdup(identifier);
512   public_key->pk_len = pk_len;
513   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
514   memcpy(public_key->pk, pk, pk_len);
515
516   return public_key;
517 }
518
519 /* Free's public key */
520
521 void silc_pkcs_public_key_free(SilcPublicKey public_key)
522 {
523   if (public_key) {
524     silc_free(public_key->name);
525     silc_free(public_key->identifier);
526     silc_free(public_key->pk);
527     silc_free(public_key);
528   }
529 }
530
531 /* Allocates SILC private key formed from sent arguments. All data is
532    duplicated. */
533
534 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
535                                            uint32 prv_len)
536 {
537   SilcPrivateKey private_key;
538
539   private_key = silc_calloc(1, sizeof(*private_key));
540   private_key->name = strdup(name);
541   private_key->prv_len = prv_len;
542   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
543   memcpy(private_key->prv, prv, prv_len);
544
545   return private_key;
546 }
547
548 /* Free's private key */
549
550 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
551 {
552   if (private_key) {
553     silc_free(private_key->name);
554     silc_free(private_key->prv);
555     silc_free(private_key);
556   }
557 }
558
559 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
560    data. */
561
562 unsigned char *
563 silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
564 {
565   SilcBuffer buf;
566   unsigned char *ret;
567
568   buf = silc_buffer_alloc(public_key->len);
569   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
570
571   silc_buffer_format(buf,
572                      SILC_STR_UI_INT(public_key->len),
573                      SILC_STR_UI_SHORT(strlen(public_key->name)),
574                      SILC_STR_UI32_STRING(public_key->name),
575                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
576                      SILC_STR_UI32_STRING(public_key->identifier),
577                      SILC_STR_UI_XNSTRING(public_key->pk, 
578                                           public_key->pk_len),
579                      SILC_STR_END);
580   if (len)
581     *len = public_key->len;
582
583   ret = silc_calloc(buf->len, sizeof(*ret));
584   memcpy(ret, buf->data, buf->len);
585   silc_buffer_free(buf);
586
587   return ret;
588 }
589
590 /* Encodes SILC style public key. Returns the encoded data. */
591
592 unsigned char *
593 silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
594                                  char *pkcs, char *identifier, 
595                                  uint32 *len)
596 {
597   SilcBuffer buf;
598   unsigned char *ret;
599   uint32 totlen;
600
601   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
602   buf = silc_buffer_alloc(totlen);
603   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
604
605   silc_buffer_format(buf,
606                      SILC_STR_UI_INT(totlen),
607                      SILC_STR_UI_SHORT(strlen(pkcs)),
608                      SILC_STR_UI32_STRING(pkcs),
609                      SILC_STR_UI_SHORT(strlen(identifier)),
610                      SILC_STR_UI32_STRING(identifier),
611                      SILC_STR_UI_XNSTRING(pk, pk_len),
612                      SILC_STR_END);
613   if (len)
614     *len = totlen;
615
616   ret = silc_calloc(buf->len, sizeof(*ret));
617   memcpy(ret, buf->data, buf->len);
618   silc_buffer_free(buf);
619
620   return ret;
621 }
622
623 /* Decodes SILC style public key. Returns TRUE if the decoding was
624    successful. Allocates new public key as well. */
625
626 int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
627                                 SilcPublicKey *public_key)
628 {
629   SilcBuffer buf;
630   SilcPKCS alg;
631   uint16 pkcs_len, identifier_len;
632   uint32 totlen, key_len;
633   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
634   int ret;
635
636   buf = silc_buffer_alloc(data_len);
637   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
638   silc_buffer_put(buf, data, data_len);
639
640   /* Get length */
641   ret = silc_buffer_unformat(buf,
642                              SILC_STR_UI_INT(&totlen),
643                              SILC_STR_END);
644   if (ret == -1) {
645     silc_buffer_free(buf);
646     return FALSE;
647   }
648
649   if (totlen != data_len) {
650     silc_buffer_free(buf);
651     return FALSE;
652   }
653
654   /* Get algorithm name and identifier */
655   silc_buffer_pull(buf, 4);
656   ret =
657     silc_buffer_unformat(buf,
658                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
659                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
660                          SILC_STR_END);
661   if (ret == -1)
662     goto err;
663
664   if (pkcs_len < 1 || identifier_len < 3 || 
665       pkcs_len + identifier_len > totlen)
666     goto err;
667
668   /* See if we support this algorithm (check only if PKCS are registered) */
669   if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
670     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
671     goto err;
672   }
673
674   /* Protocol says that at least UN and HN must be provided as identifier,
675      check for these. */
676   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
677     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
678                     "identifiers"));
679     goto err;
680   }
681
682   /* Get key data. We assume that rest of the buffer is key data. */
683   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
684   key_len = buf->len;
685   ret = silc_buffer_unformat(buf,
686                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
687                              SILC_STR_END);
688   if (ret == -1)
689     goto err;
690
691   /* Try to set the key. If this fails the key must be malformed. This
692      code assumes that the PKCS routine checks the format of the key. 
693      (check only if PKCS are registered) */
694   if (silc_pkcs_list) {
695     silc_pkcs_alloc(pkcs_name, &alg);
696     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
697       goto err;
698     silc_pkcs_free(alg);
699   }
700   
701   if (public_key) {
702     *public_key = silc_calloc(1, sizeof(**public_key));
703     (*public_key)->len = totlen;
704     (*public_key)->name = pkcs_name;
705     (*public_key)->identifier = ident;
706     (*public_key)->pk = key_data;
707     (*public_key)->pk_len = key_len;
708   }
709
710   silc_buffer_free(buf);
711   return TRUE;
712
713  err:
714   if (pkcs_name)
715     silc_free(pkcs_name);
716   if (ident)
717     silc_free(ident);
718   if (key_data)
719     silc_free(key_data);
720   silc_buffer_free(buf);
721   return FALSE;
722 }
723
724 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
725
726 unsigned char *
727 silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
728 {
729   SilcBuffer buf;
730   unsigned char *ret;
731   uint32 totlen;
732
733   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
734   buf = silc_buffer_alloc(totlen);
735   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
736
737   silc_buffer_format(buf,
738                      SILC_STR_UI_SHORT(strlen(private_key->name)),
739                      SILC_STR_UI32_STRING(private_key->name),
740                      SILC_STR_UI_XNSTRING(private_key->prv, 
741                                           private_key->prv_len),
742                      SILC_STR_END);
743   if (len)
744     *len = totlen;
745
746   ret = silc_calloc(buf->len, sizeof(*ret));
747   memcpy(ret, buf->data, buf->len);
748   silc_buffer_free(buf);
749
750   return ret;
751 }
752
753 /* Encodes SILC private key. Returns the encoded data. */
754
755 unsigned char *
756 silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
757                                   char *pkcs, uint32 *len)
758 {
759   SilcBuffer buf;
760   unsigned char *ret;
761   uint32 totlen;
762
763   totlen = 2 + strlen(pkcs) + prv_len;
764   buf = silc_buffer_alloc(totlen);
765   silc_buffer_pull_tail(buf, totlen);
766
767   silc_buffer_format(buf,
768                      SILC_STR_UI_SHORT(strlen(pkcs)),
769                      SILC_STR_UI32_STRING(pkcs),
770                      SILC_STR_UI_XNSTRING(prv, prv_len),
771                      SILC_STR_END);
772   if (len)
773     *len = totlen;
774
775   ret = silc_calloc(buf->len, sizeof(*ret));
776   memcpy(ret, buf->data, buf->len);
777   silc_buffer_free(buf);
778
779   return ret;
780 }
781
782 /* Decodes SILC style public key. Returns TRUE if the decoding was
783    successful. Allocates new private key as well. */
784
785 int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
786                                  SilcPrivateKey *private_key)
787 {
788   SilcBuffer buf;
789   SilcPKCS alg;
790   uint16 pkcs_len;
791   uint32 key_len;
792   unsigned char *pkcs_name = NULL, *key_data = NULL;
793   int ret;
794
795   buf = silc_buffer_alloc(data_len);
796   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
797   silc_buffer_put(buf, data, data_len);
798
799   /* Get algorithm name and identifier */
800   ret = 
801     silc_buffer_unformat(buf,
802                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
803                          SILC_STR_END);
804   if (ret == -1)
805     goto err;
806
807   if (pkcs_len < 1 || pkcs_len > buf->truelen)
808     goto err;
809
810   /* See if we support this algorithm (check only if PKCS are registered). */
811   if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
812     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
813     goto err;
814   }
815
816   /* Get key data. We assume that rest of the buffer is key data. */
817   silc_buffer_pull(buf, 2 + pkcs_len);
818   key_len = buf->len;
819   ret = silc_buffer_unformat(buf,
820                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
821                              SILC_STR_END);
822   if (ret == -1)
823     goto err;
824
825   /* Try to set the key. If this fails the key must be malformed. This
826      code assumes that the PKCS routine checks the format of the key. 
827      (check only if PKCS are registered) */
828   if (silc_pkcs_list) {
829     silc_pkcs_alloc(pkcs_name, &alg);
830     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
831       goto err;
832     silc_pkcs_free(alg);
833   }
834   
835   if (private_key) {
836     *private_key = silc_calloc(1, sizeof(**private_key));
837     (*private_key)->name = pkcs_name;
838     (*private_key)->prv = key_data;
839     (*private_key)->prv_len = key_len;
840   }
841
842   silc_buffer_free(buf);
843   return TRUE;
844
845  err:
846   if (pkcs_name)
847     silc_free(pkcs_name);
848   if (key_data)
849     silc_free(key_data);
850   silc_buffer_free(buf);
851   return FALSE;
852 }
853
854 /* Internal routine to save public key */
855
856 static int silc_pkcs_save_public_key_internal(char *filename,
857                                               unsigned char *data,
858                                               uint32 data_len,
859                                               uint32 encoding)
860 {
861   SilcBuffer buf;
862   uint32 len;
863
864   switch(encoding) {
865   case SILC_PKCS_FILE_BIN:
866     break;
867   case SILC_PKCS_FILE_PEM:
868     data = silc_encode_pem_file(data, data_len);
869     data_len = strlen(data);
870     break;
871   }
872
873   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
874                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
875   buf = silc_buffer_alloc(len);
876   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
877
878   silc_buffer_format(buf,
879                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
880                      SILC_STR_UI_XNSTRING(data, data_len),
881                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
882                      SILC_STR_END);
883
884   /* Save into file */
885   if (silc_file_write(filename, buf->data, buf->len)) {
886     silc_buffer_free(buf);
887     return FALSE;
888   }
889
890   silc_buffer_free(buf);
891   return TRUE;
892 }
893
894 /* Saves public key into file */
895
896 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
897                               uint32 encoding)
898 {
899   unsigned char *data;
900   uint32 data_len;
901
902   data = silc_pkcs_public_key_encode(public_key, &data_len);
903   return silc_pkcs_save_public_key_internal(filename, data, data_len,
904                                             encoding);
905 }
906
907 /* Saves public key into file */
908
909 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
910                                    uint32 data_len,
911                                    uint32 encoding)
912 {
913   return silc_pkcs_save_public_key_internal(filename, data, data_len,
914                                             encoding);
915 }
916
917 /* Internal routine to save private key. */
918
919 static int silc_pkcs_save_private_key_internal(char *filename,
920                                                unsigned char *data,
921                                                uint32 data_len,
922                                                uint32 encoding)
923 {
924   SilcBuffer buf;
925   uint32 len;
926
927   switch(encoding) {
928   case SILC_PKCS_FILE_BIN:
929     break;
930   case SILC_PKCS_FILE_PEM:
931     data = silc_encode_pem_file(data, data_len);
932     data_len = strlen(data);
933     break;
934   }
935
936   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
937                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
938   buf = silc_buffer_alloc(len);
939   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
940
941   silc_buffer_format(buf,
942                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
943                      SILC_STR_UI_XNSTRING(data, data_len),
944                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
945                      SILC_STR_END);
946
947   /* Save into a file */
948   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
949     silc_buffer_free(buf);
950     return FALSE;
951   }
952
953   silc_buffer_free(buf);
954   return TRUE;
955 }
956
957 /* Saves private key into file. */
958 /* XXX The buffer should be encrypted if passphrase is provided. */
959
960 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
961                                unsigned char *passphrase,
962                                uint32 encoding)
963 {
964   unsigned char *data;
965   uint32 data_len;
966
967   data = silc_pkcs_private_key_encode(private_key, &data_len);
968   return silc_pkcs_save_private_key_internal(filename, data, data_len,
969                                              encoding);
970 }
971
972 /* Saves private key into file. */
973 /* XXX The buffer should be encrypted if passphrase is provided. */
974
975 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
976                                     uint32 data_len,
977                                     unsigned char *passphrase,
978                                     uint32 encoding)
979 {
980   return silc_pkcs_save_private_key_internal(filename, data, data_len,
981                                              encoding);
982 }
983
984 /* Loads public key from file and allocates new public key. Returns TRUE
985    is loading was successful. */
986
987 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
988                               uint32 encoding)
989 {
990   unsigned char *cp, *old, *data, byte;
991   uint32 i, data_len, len;
992
993   old = data = silc_file_read(filename, &data_len);
994   if (!data)
995     return FALSE;
996
997   /* Check start of file and remove header from the data. */
998   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
999   cp = data;
1000   for (i = 0; i < len; i++) {
1001     byte = cp[0];
1002     cp++;
1003     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1004       memset(old, 0, data_len);
1005       silc_free(old);
1006       return FALSE;
1007     }
1008   }
1009   data = cp;
1010
1011   /* Decode public key */
1012   if (public_key) {
1013     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1014                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1015
1016     switch(encoding) {
1017     case SILC_PKCS_FILE_BIN:
1018       break;
1019     case SILC_PKCS_FILE_PEM:
1020       data = silc_decode_pem(data, len, &len);
1021       break;
1022     }
1023
1024     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1025       memset(old, 0, data_len);
1026       silc_free(old);
1027       return FALSE;
1028     }
1029   }
1030
1031   memset(old, 0, data_len);
1032   silc_free(old);
1033   return TRUE;
1034 }
1035
1036 /* Load private key from file and allocates new private key. Returns TRUE
1037    if loading was successful. */
1038 /* XXX Should support encrypted private key files */
1039
1040 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1041                                uint32 encoding)
1042 {
1043   unsigned char *cp, *old, *data, byte;
1044   uint32 i, data_len, len;
1045
1046   old = data = silc_file_read(filename, &data_len);
1047   if (!data)
1048     return FALSE;
1049
1050   /* Check start of file and remove header from the data. */
1051   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1052   cp = data;
1053   for (i = 0; i < len; i++) {
1054     byte = cp[0];
1055     cp++;
1056     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1057       memset(old, 0, data_len);
1058       silc_free(old);
1059       return FALSE;
1060     }
1061   }
1062   data = cp;
1063
1064   /* Decode private key */
1065   if (private_key) {
1066     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1067                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1068
1069     switch(encoding) {
1070     case SILC_PKCS_FILE_BIN:
1071       break;
1072     case SILC_PKCS_FILE_PEM:
1073       data = silc_decode_pem(data, len, &len);
1074       break;
1075     }
1076
1077     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1078       memset(old, 0, data_len);
1079       silc_free(old);
1080       return FALSE;
1081     }
1082   }
1083
1084   memset(old, 0, data_len);
1085   silc_free(old);
1086   return TRUE;
1087 }