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 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
28    only static declarations are possible. XXX: I hope this to change
29    real soon. */
30 SilcPKCSObject silc_pkcs_list[] =
31 {
32   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
33   /*
34   { "rsa", &silc_rsa_data_context, 
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_rsa_data_context_len, silc_rsa_set_arg,
39     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
40     silc_pkcs1_sign, silc_pkcs1_verify },
41   */
42
43   /* Raw RSA operations */
44   { "rsa", &silc_rsa_data_context, 
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_rsa_data_context_len, silc_rsa_set_arg,
49     silc_rsa_encrypt, silc_rsa_decrypt,
50     silc_rsa_sign, silc_rsa_verify },
51
52   { NULL, NULL, NULL, NULL, NULL,
53     NULL, NULL, NULL, NULL, NULL, NULL }
54 };
55
56 /* Allocates a new SilcPKCS object. The new allocated object is returned
57    to the 'new_pkcs' argument. This function also initializes the data
58    context structure. Function returns 1 on success and 0 on error.
59
60 */
61 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
62 {
63   int i;
64
65   SILC_LOG_DEBUG(("Allocating new PKCS object"));
66
67   for (i = 0; silc_pkcs_list[i].name; i++) {
68     if (!strcmp(silc_pkcs_list[i].name, name))
69       break;
70   }
71
72   if (silc_pkcs_list[i].name == NULL)
73     return FALSE;
74
75   *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
76
77   /* Set the pointers */
78   (*new_pkcs)->pkcs = &silc_pkcs_list[i];
79   (*new_pkcs)->pkcs->data_context = 
80     silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
81   (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
82   (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
83
84   return TRUE;
85 }
86
87 /* Free's the PKCS object */
88
89 void silc_pkcs_free(SilcPKCS pkcs)
90 {
91   if (pkcs)
92     silc_free(pkcs->context);
93 }
94
95 /* Return TRUE if PKCS algorithm `name' is supported. */
96
97 int silc_pkcs_is_supported(const unsigned char *name)
98 {
99   int i;
100
101   for (i = 0; silc_pkcs_list[i].name; i++) {
102     if (!strcmp(silc_pkcs_list[i].name, name))
103       return TRUE;
104   }
105
106   return FALSE;
107 }
108
109 /* Returns comma separated list of supported PKCS algorithms */
110
111 char *silc_pkcs_get_supported()
112 {
113   char *list = NULL;
114   int i, len;
115
116   len = 0;
117   for (i = 0; silc_pkcs_list[i].name; i++) {
118     len += strlen(silc_pkcs_list[i].name);
119     list = silc_realloc(list, len + 1);
120
121     memcpy(list + (len - strlen(silc_pkcs_list[i].name)), 
122            silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
123     memcpy(list + len, ",", 1);
124     len++;
125   }
126
127   list[len - 1] = 0;
128
129   return list;
130 }
131
132 /* Returns the length of the key */
133
134 unsigned int silc_pkcs_get_key_len(SilcPKCS self)
135 {
136   return self->key_len;
137 }
138
139 /* Returns SILC style public key */
140
141 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
142 {
143   return pkcs->pkcs->get_public_key(pkcs->context, len);
144 }
145
146 /* Returns SILC style private key */
147
148 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
149 {
150   return pkcs->pkcs->get_private_key(pkcs->context, len);
151 }
152
153 /* Sets public key from SilcPublicKey. */
154
155 int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
156 {
157   return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
158                                     public_key->pk_len);
159 }
160
161 /* Sets public key from data. */
162
163 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
164                                   unsigned int pk_len)
165 {
166   return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
167 }
168
169 /* Sets private key from SilcPrivateKey. */
170
171 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
172 {
173   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
174                                      private_key->prv_len);
175 }
176
177 /* Sets private key from data. */
178
179 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
180                                    unsigned int prv_len)
181 {
182   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
183 }
184
185 /* Encrypts */
186
187 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, unsigned int src_len,
188                       unsigned char *dst, unsigned int *dst_len)
189 {
190   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
191 }
192
193 /* Decrypts */
194
195 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, unsigned int src_len,
196                       unsigned char *dst, unsigned int *dst_len)
197 {
198   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
199 }
200
201 /* Generates signature */
202
203 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, unsigned int src_len,
204                    unsigned char *dst, unsigned int *dst_len)
205 {
206   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
207 }
208
209 /* Verifies signature */
210
211 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
212                      unsigned int signature_len, unsigned char *data, 
213                      unsigned int data_len)
214 {
215   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
216                             data, data_len);
217 }
218
219 /* Generates signature with hash. The hash is signed. */
220
221 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
222                              unsigned char *src, unsigned int src_len,
223                              unsigned char *dst, unsigned int *dst_len)
224 {
225   unsigned char hashr[32];
226   unsigned int hash_len;
227   int ret;
228
229   silc_hash_make(hash, src, src_len, hashr);
230   hash_len = hash->hash->hash_len;
231
232   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
233   memset(hashr, 0, sizeof(hashr));
234
235   return ret;
236 }
237
238 /* Verifies signature with hash. The `data' is hashed and verified against
239    the `signature'. */
240
241 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
242                                unsigned char *signature, 
243                                unsigned int signature_len, 
244                                unsigned char *data, 
245                                unsigned int data_len)
246 {
247   unsigned char hashr[32];
248   unsigned int hash_len;
249   int ret;
250
251   silc_hash_make(hash, data, data_len, hashr);
252   hash_len = hash->hash->hash_len;
253
254   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
255                            hashr, hash_len);
256   memset(hashr, 0, sizeof(hashr));
257
258   return ret;
259 }
260
261 /* Encodes and returns SILC public key identifier. If some of the 
262    arguments is NULL those are not encoded into the identifier string.
263    Protocol says that at least username and host must be provided. */
264
265 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
266                                   char *email, char *org, char *country)
267 {
268   SilcBuffer buf;
269   char *identifier;
270   unsigned int len, tlen = 0;
271
272   if (!username || !host)
273     return NULL;
274
275   len = (username ? strlen(username) : 0) +
276         (host     ? strlen(host)     : 0) +
277         (realname ? strlen(realname) : 0) +
278         (email    ? strlen(email)    : 0) +
279         (org      ? strlen(org)      : 0) +
280         (country  ? strlen(country)  : 0);
281   
282   if (len < 3)
283     return NULL;
284
285   len += 3 + 5 + 5 + 4 + 4 + 4;
286   buf = silc_buffer_alloc(len);
287   silc_buffer_pull_tail(buf, len);
288
289   if (username) {
290     silc_buffer_format(buf,
291                        SILC_STR_UI32_STRING("UN="),
292                        SILC_STR_UI32_STRING(username),
293                        SILC_STR_END);
294     silc_buffer_pull(buf, 3 + strlen(username));
295     tlen = 3 + strlen(username); 
296   }
297     
298   if (host) {
299     silc_buffer_format(buf,
300                        SILC_STR_UI32_STRING(", "),
301                        SILC_STR_UI32_STRING("HN="),
302                        SILC_STR_UI32_STRING(host),
303                        SILC_STR_END);
304     silc_buffer_pull(buf, 5 + strlen(host));
305     tlen += 5 + strlen(host); 
306   }
307
308   if (realname) {
309     silc_buffer_format(buf,
310                        SILC_STR_UI32_STRING(", "),
311                        SILC_STR_UI32_STRING("RN="),
312                        SILC_STR_UI32_STRING(realname),
313                        SILC_STR_END);
314     silc_buffer_pull(buf, 5 + strlen(realname));
315     tlen += 5 + strlen(realname); 
316   }
317
318   if (email) {
319     silc_buffer_format(buf,
320                        SILC_STR_UI32_STRING(", "),
321                        SILC_STR_UI32_STRING("E="),
322                        SILC_STR_UI32_STRING(email),
323                        SILC_STR_END);
324     silc_buffer_pull(buf, 4 + strlen(email));
325     tlen += 4 + strlen(email); 
326   }
327
328   if (org) {
329     silc_buffer_format(buf,
330                        SILC_STR_UI32_STRING(", "),
331                        SILC_STR_UI32_STRING("O="),
332                        SILC_STR_UI32_STRING(org),
333                        SILC_STR_END);
334     silc_buffer_pull(buf, 4 + strlen(org));
335     tlen += 4 + strlen(org); 
336   }
337
338   if (country) {
339     silc_buffer_format(buf,
340                        SILC_STR_UI32_STRING(", "),
341                        SILC_STR_UI32_STRING("C="),
342                        SILC_STR_UI32_STRING(country),
343                        SILC_STR_END);
344     silc_buffer_pull(buf, 4 + strlen(country));
345     tlen += 4 + strlen(country); 
346   }
347
348   silc_buffer_push(buf, buf->data - buf->head);
349   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
350   memcpy(identifier, buf->data, tlen);
351   silc_buffer_free(buf);
352
353   return identifier;
354 }
355
356 /* Allocates SILC style public key formed from sent arguments. All data
357    is duplicated. */
358
359 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
360                                          unsigned char *pk, 
361                                          unsigned int pk_len)
362 {
363   SilcPublicKey public_key;
364
365   public_key = silc_calloc(1, sizeof(*public_key));
366   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
367   public_key->name = strdup(name);
368   public_key->identifier = strdup(identifier);
369   public_key->pk_len = pk_len;
370   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
371   memcpy(public_key->pk, pk, pk_len);
372
373   return public_key;
374 }
375
376 /* Free's public key */
377
378 void silc_pkcs_public_key_free(SilcPublicKey public_key)
379 {
380   if (public_key) {
381     silc_free(public_key->name);
382     silc_free(public_key->identifier);
383     silc_free(public_key->pk);
384     silc_free(public_key);
385   }
386 }
387
388 /* Allocates SILC private key formed from sent arguments. All data is
389    duplicated. */
390
391 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
392                                            unsigned int prv_len)
393 {
394   SilcPrivateKey private_key;
395
396   private_key = silc_calloc(1, sizeof(*private_key));
397   private_key->name = strdup(name);
398   private_key->prv_len = prv_len;
399   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
400   memcpy(private_key->prv, prv, prv_len);
401
402   return private_key;
403 }
404
405 /* Free's private key */
406
407 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
408 {
409   if (private_key) {
410     silc_free(private_key->name);
411     silc_free(private_key->prv);
412     silc_free(private_key);
413   }
414 }
415
416 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
417    data. */
418
419 unsigned char *
420 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
421 {
422   SilcBuffer buf;
423   unsigned char *ret;
424
425   buf = silc_buffer_alloc(public_key->len);
426   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
427
428   silc_buffer_format(buf,
429                      SILC_STR_UI_INT(public_key->len),
430                      SILC_STR_UI_SHORT(strlen(public_key->name)),
431                      SILC_STR_UI32_STRING(public_key->name),
432                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
433                      SILC_STR_UI32_STRING(public_key->identifier),
434                      SILC_STR_UI_XNSTRING(public_key->pk, 
435                                           public_key->pk_len),
436                      SILC_STR_END);
437   if (len)
438     *len = public_key->len;
439
440   ret = silc_calloc(buf->len, sizeof(*ret));
441   memcpy(ret, buf->data, buf->len);
442   silc_buffer_free(buf);
443
444   return ret;
445 }
446
447 /* Encodes SILC style public key. Returns the encoded data. */
448
449 unsigned char *
450 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
451                                  char *pkcs, char *identifier, 
452                                  unsigned int *len)
453 {
454   SilcBuffer buf;
455   unsigned char *ret;
456   unsigned int totlen;
457
458   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
459   buf = silc_buffer_alloc(totlen);
460   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
461
462   silc_buffer_format(buf,
463                      SILC_STR_UI_INT(totlen),
464                      SILC_STR_UI_SHORT(strlen(pkcs)),
465                      SILC_STR_UI32_STRING(pkcs),
466                      SILC_STR_UI_SHORT(strlen(identifier)),
467                      SILC_STR_UI32_STRING(identifier),
468                      SILC_STR_UI_XNSTRING(pk, pk_len),
469                      SILC_STR_END);
470   if (len)
471     *len = totlen;
472
473   ret = silc_calloc(buf->len, sizeof(*ret));
474   memcpy(ret, buf->data, buf->len);
475   silc_buffer_free(buf);
476
477   return ret;
478 }
479
480 /* Decodes SILC style public key. Returns TRUE if the decoding was
481    successful. Allocates new public key as well. */
482
483 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
484                                 SilcPublicKey *public_key)
485 {
486   SilcBuffer buf;
487   SilcPKCS alg;
488   unsigned short pkcs_len, identifier_len;
489   unsigned int totlen, key_len;
490   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
491   int ret;
492
493   buf = silc_buffer_alloc(data_len);
494   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
495   silc_buffer_put(buf, data, data_len);
496
497   /* Get length */
498   ret = silc_buffer_unformat(buf,
499                              SILC_STR_UI_INT(&totlen),
500                              SILC_STR_END);
501   if (ret == -1) {
502     silc_buffer_free(buf);
503     return FALSE;
504   }
505
506   if (totlen != data_len) {
507     silc_buffer_free(buf);
508     return FALSE;
509   }
510
511   /* Get algorithm name and identifier */
512   silc_buffer_pull(buf, 4);
513   ret =
514     silc_buffer_unformat(buf,
515                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
516                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
517                          SILC_STR_END);
518   if (ret == -1)
519     goto err;
520
521   if (pkcs_len < 1 || identifier_len < 3 || 
522       pkcs_len + identifier_len > totlen)
523     goto err;
524
525   /* See if we support this algorithm */
526   if (!silc_pkcs_is_supported(pkcs_name))
527     goto err;
528
529   /* Protocol says that at least UN and HN must be provided as identifier,
530      check for these. */
531   if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
532     goto err;
533
534   /* Get key data. We assume that rest of the buffer is key data. */
535   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
536   key_len = buf->len;
537   ret = silc_buffer_unformat(buf,
538                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
539                              SILC_STR_END);
540   if (ret == -1)
541     goto err;
542
543   /* Try to set the key. If this fails the key must be malformed. This
544      code assumes that the PKCS routine checks the format of the key. */
545   silc_pkcs_alloc(pkcs_name, &alg);
546   if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
547     goto err;
548   silc_pkcs_free(alg);
549   
550   if (public_key) {
551     *public_key = silc_calloc(1, sizeof(**public_key));
552     (*public_key)->len = totlen;
553     (*public_key)->name = pkcs_name;
554     (*public_key)->identifier = ident;
555     (*public_key)->pk = key_data;
556     (*public_key)->pk_len = key_len;
557   }
558
559   silc_buffer_free(buf);
560   return TRUE;
561
562  err:
563   if (pkcs_name)
564     silc_free(pkcs_name);
565   if (ident)
566     silc_free(ident);
567   if (key_data)
568     silc_free(key_data);
569   silc_buffer_free(buf);
570   return FALSE;
571 }
572
573 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
574
575 unsigned char *
576 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
577 {
578   SilcBuffer buf;
579   unsigned char *ret;
580   unsigned int totlen;
581
582   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
583   buf = silc_buffer_alloc(totlen);
584   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
585
586   silc_buffer_format(buf,
587                      SILC_STR_UI_SHORT(strlen(private_key->name)),
588                      SILC_STR_UI32_STRING(private_key->name),
589                      SILC_STR_UI_XNSTRING(private_key->prv, 
590                                           private_key->prv_len),
591                      SILC_STR_END);
592   if (len)
593     *len = totlen;
594
595   ret = silc_calloc(buf->len, sizeof(*ret));
596   memcpy(ret, buf->data, buf->len);
597   silc_buffer_free(buf);
598
599   return ret;
600 }
601
602 /* Encodes SILC private key. Returns the encoded data. */
603
604 unsigned char *
605 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
606                                   char *pkcs, unsigned int *len)
607 {
608   SilcBuffer buf;
609   unsigned char *ret;
610   unsigned int totlen;
611
612   totlen = 2 + strlen(pkcs) + prv_len;
613   buf = silc_buffer_alloc(totlen);
614   silc_buffer_pull_tail(buf, totlen);
615
616   silc_buffer_format(buf,
617                      SILC_STR_UI_SHORT(strlen(pkcs)),
618                      SILC_STR_UI32_STRING(pkcs),
619                      SILC_STR_UI_XNSTRING(prv, prv_len),
620                      SILC_STR_END);
621   if (len)
622     *len = totlen;
623
624   ret = silc_calloc(buf->len, sizeof(*ret));
625   memcpy(ret, buf->data, buf->len);
626   silc_buffer_free(buf);
627
628   return ret;
629 }
630
631 /* Decodes SILC style public key. Returns TRUE if the decoding was
632    successful. Allocates new private key as well. */
633
634 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
635                                  SilcPrivateKey *private_key)
636 {
637   SilcBuffer buf;
638   SilcPKCS alg;
639   unsigned short pkcs_len;
640   unsigned int key_len;
641   unsigned char *pkcs_name = NULL, *key_data = NULL;
642   int ret;
643
644   buf = silc_buffer_alloc(data_len);
645   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
646   silc_buffer_put(buf, data, data_len);
647
648   /* Get algorithm name and identifier */
649   ret = 
650     silc_buffer_unformat(buf,
651                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
652                          SILC_STR_END);
653   if (ret == -1)
654     goto err;
655
656   if (pkcs_len < 1 || pkcs_len > buf->truelen)
657     goto err;
658
659   /* See if we support this algorithm */
660   if (!silc_pkcs_is_supported(pkcs_name))
661     goto err;
662
663   /* Get key data. We assume that rest of the buffer is key data. */
664   silc_buffer_pull(buf, 2 + pkcs_len);
665   key_len = buf->len;
666   ret = silc_buffer_unformat(buf,
667                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
668                              SILC_STR_END);
669   if (ret == -1)
670     goto err;
671
672   /* Try to set the key. If this fails the key must be malformed. This
673      code assumes that the PKCS routine checks the format of the key. */
674   silc_pkcs_alloc(pkcs_name, &alg);
675   if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
676     goto err;
677   silc_pkcs_free(alg);
678   
679   if (private_key) {
680     *private_key = silc_calloc(1, sizeof(**private_key));
681     (*private_key)->name = pkcs_name;
682     (*private_key)->prv = key_data;
683     (*private_key)->prv_len = key_len;
684   }
685
686   silc_buffer_free(buf);
687   return TRUE;
688
689  err:
690   if (pkcs_name)
691     silc_free(pkcs_name);
692   if (key_data)
693     silc_free(key_data);
694   silc_buffer_free(buf);
695   return FALSE;
696 }
697
698 /* Internal routine to save public key */
699
700 static int silc_pkcs_save_public_key_internal(char *filename,
701                                               unsigned char *data,
702                                               unsigned int data_len,
703                                               unsigned int encoding)
704 {
705   SilcBuffer buf;
706   unsigned int len;
707
708   switch(encoding) {
709   case SILC_PKCS_FILE_BIN:
710     break;
711   case SILC_PKCS_FILE_PEM:
712     data = silc_encode_pem_file(data, data_len);
713     data_len = strlen(data);
714     break;
715   }
716
717   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
718                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
719   buf = silc_buffer_alloc(len);
720   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
721
722   silc_buffer_format(buf,
723                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
724                      SILC_STR_UI_XNSTRING(data, data_len),
725                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
726                      SILC_STR_END);
727
728   /* Save into file */
729   if (silc_file_write(filename, buf->data, buf->len)) {
730     silc_buffer_free(buf);
731     return FALSE;
732   }
733
734   silc_buffer_free(buf);
735   return TRUE;
736 }
737
738 /* Saves public key into file */
739
740 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
741                               unsigned int encoding)
742 {
743   unsigned char *data;
744   unsigned int data_len;
745
746   data = silc_pkcs_public_key_encode(public_key, &data_len);
747   return silc_pkcs_save_public_key_internal(filename, data, data_len,
748                                             encoding);
749 }
750
751 /* Saves public key into file */
752
753 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
754                                    unsigned int data_len,
755                                    unsigned int encoding)
756 {
757   return silc_pkcs_save_public_key_internal(filename, data, data_len,
758                                             encoding);
759 }
760
761 /* Internal routine to save private key. */
762
763 static int silc_pkcs_save_private_key_internal(char *filename,
764                                                unsigned char *data,
765                                                unsigned int data_len,
766                                                unsigned int encoding)
767 {
768   SilcBuffer buf;
769   unsigned int len;
770
771   switch(encoding) {
772   case SILC_PKCS_FILE_BIN:
773     break;
774   case SILC_PKCS_FILE_PEM:
775     data = silc_encode_pem_file(data, data_len);
776     data_len = strlen(data);
777     break;
778   }
779
780   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
781                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
782   buf = silc_buffer_alloc(len);
783   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
784
785   silc_buffer_format(buf,
786                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
787                      SILC_STR_UI_XNSTRING(data, data_len),
788                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
789                      SILC_STR_END);
790
791   /* Save into a file */
792   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
793     silc_buffer_free(buf);
794     return FALSE;
795   }
796
797   silc_buffer_free(buf);
798   return TRUE;
799 }
800
801 /* Saves private key into file. */
802 /* XXX The buffer should be encrypted if passphrase is provided. */
803
804 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
805                                unsigned char *passphrase,
806                                unsigned int encoding)
807 {
808   unsigned char *data;
809   unsigned int data_len;
810
811   data = silc_pkcs_private_key_encode(private_key, &data_len);
812   return silc_pkcs_save_private_key_internal(filename, data, data_len,
813                                              encoding);
814 }
815
816 /* Saves private key into file. */
817 /* XXX The buffer should be encrypted if passphrase is provided. */
818
819 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
820                                     unsigned int data_len,
821                                     unsigned char *passphrase,
822                                     unsigned int encoding)
823 {
824   return silc_pkcs_save_private_key_internal(filename, data, data_len,
825                                              encoding);
826 }
827
828 /* Loads public key from file and allocates new public key. Returns TRUE
829    is loading was successful. */
830
831 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
832                               unsigned int encoding)
833 {
834   unsigned char *cp, *old, *data, byte;
835   unsigned int i, data_len, len;
836
837   old = data = silc_file_read(filename, &data_len);
838   if (!data)
839     return FALSE;
840
841   /* Check start of file and remove header from the data. */
842   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
843   cp = data;
844   for (i = 0; i < len; i++) {
845     byte = cp[0];
846     cp++;
847     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
848       memset(old, 0, data_len);
849       silc_free(old);
850     }
851   }
852   data = cp;
853
854   /* Decode public key */
855   if (public_key) {
856     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
857                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
858
859     switch(encoding) {
860     case SILC_PKCS_FILE_BIN:
861       break;
862     case SILC_PKCS_FILE_PEM:
863       data = silc_decode_pem(data, len, &len);
864       break;
865     }
866
867     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
868       memset(old, 0, data_len);
869       silc_free(old);
870       return FALSE;
871     }
872   }
873
874   memset(old, 0, data_len);
875   silc_free(old);
876   return TRUE;
877 }
878
879 /* Load private key from file and allocates new private key. Returns TRUE
880    if loading was successful. */
881 /* XXX Should support encrypted private key files */
882
883 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
884                                unsigned int encoding)
885 {
886   unsigned char *cp, *old, *data, byte;
887   unsigned int i, data_len, len;
888
889   old = data = silc_file_read(filename, &data_len);
890   if (!data)
891     return FALSE;
892
893   /* Check start of file and remove header from the data. */
894   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
895   cp = data;
896   for (i = 0; i < len; i++) {
897     byte = cp[0];
898     cp++;
899     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
900       memset(old, 0, data_len);
901       silc_free(old);
902     }
903   }
904   data = cp;
905
906   /* Decode private key */
907   if (private_key) {
908     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
909                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
910
911     switch(encoding) {
912     case SILC_PKCS_FILE_BIN:
913       break;
914     case SILC_PKCS_FILE_PEM:
915       data = silc_decode_pem(data, len, &len);
916       break;
917     }
918
919     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
920       memset(old, 0, data_len);
921       silc_free(old);
922       return FALSE;
923     }
924   }
925
926   memset(old, 0, data_len);
927   silc_free(old);
928   return TRUE;
929 }