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