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   }
198
199   list[len - 1] = 0;
200
201   return list;
202 }
203
204 /* Returns the length of the key */
205
206 uint32 silc_pkcs_get_key_len(SilcPKCS self)
207 {
208   return self->key_len;
209 }
210
211 /* Returns SILC style public key */
212
213 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, uint32 *len)
214 {
215   return pkcs->pkcs->get_public_key(pkcs->context, len);
216 }
217
218 /* Returns SILC style private key */
219
220 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, uint32 *len)
221 {
222   return pkcs->pkcs->get_private_key(pkcs->context, len);
223 }
224
225 /* Sets public key from SilcPublicKey. */
226
227 uint32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
228 {
229   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
230                                              public_key->pk_len);
231   return pkcs->key_len;
232 }
233
234 /* Sets public key from data. */
235
236 uint32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
237                                      uint32 pk_len)
238 {
239   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
240   return pkcs->key_len;
241 }
242
243 /* Sets private key from SilcPrivateKey. */
244
245 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
246 {
247   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
248                                      private_key->prv_len);
249 }
250
251 /* Sets private key from data. */
252
253 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
254                                    uint32 prv_len)
255 {
256   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
257 }
258
259 /* Encrypts */
260
261 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
262                       unsigned char *dst, uint32 *dst_len)
263 {
264   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
265 }
266
267 /* Decrypts */
268
269 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
270                       unsigned char *dst, uint32 *dst_len)
271 {
272   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
273 }
274
275 /* Generates signature */
276
277 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
278                    unsigned char *dst, uint32 *dst_len)
279 {
280   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
281 }
282
283 /* Verifies signature */
284
285 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
286                      uint32 signature_len, unsigned char *data, 
287                      uint32 data_len)
288 {
289   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
290                             data, data_len);
291 }
292
293 /* Generates signature with hash. The hash is signed. */
294
295 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
296                              unsigned char *src, uint32 src_len,
297                              unsigned char *dst, uint32 *dst_len)
298 {
299   unsigned char hashr[32];
300   uint32 hash_len;
301   int ret;
302
303   silc_hash_make(hash, src, src_len, hashr);
304   hash_len = hash->hash->hash_len;
305
306   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
307
308   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
309   memset(hashr, 0, sizeof(hashr));
310
311   return ret;
312 }
313
314 /* Verifies signature with hash. The `data' is hashed and verified against
315    the `signature'. */
316
317 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
318                                unsigned char *signature, 
319                                uint32 signature_len, 
320                                unsigned char *data, 
321                                uint32 data_len)
322 {
323   unsigned char hashr[32];
324   uint32 hash_len;
325   int ret;
326
327   silc_hash_make(hash, data, data_len, hashr);
328   hash_len = hash->hash->hash_len;
329
330   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
331
332   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
333                            hashr, hash_len);
334   memset(hashr, 0, sizeof(hashr));
335
336   return ret;
337 }
338
339 /* Encodes and returns SILC public key identifier. If some of the 
340    arguments is NULL those are not encoded into the identifier string.
341    Protocol says that at least username and host must be provided. */
342
343 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
344                                   char *email, char *org, char *country)
345 {
346   SilcBuffer buf;
347   char *identifier;
348   uint32 len, tlen = 0;
349
350   if (!username || !host)
351     return NULL;
352
353   len = (username ? strlen(username) : 0) +
354         (host     ? strlen(host)     : 0) +
355         (realname ? strlen(realname) : 0) +
356         (email    ? strlen(email)    : 0) +
357         (org      ? strlen(org)      : 0) +
358         (country  ? strlen(country)  : 0);
359   
360   if (len < 3)
361     return NULL;
362
363   len += 3 + 5 + 5 + 4 + 4 + 4;
364   buf = silc_buffer_alloc(len);
365   silc_buffer_pull_tail(buf, len);
366
367   if (username) {
368     silc_buffer_format(buf,
369                        SILC_STR_UI32_STRING("UN="),
370                        SILC_STR_UI32_STRING(username),
371                        SILC_STR_END);
372     silc_buffer_pull(buf, 3 + strlen(username));
373     tlen = 3 + strlen(username); 
374   }
375     
376   if (host) {
377     silc_buffer_format(buf,
378                        SILC_STR_UI32_STRING(", "),
379                        SILC_STR_UI32_STRING("HN="),
380                        SILC_STR_UI32_STRING(host),
381                        SILC_STR_END);
382     silc_buffer_pull(buf, 5 + strlen(host));
383     tlen += 5 + strlen(host); 
384   }
385
386   if (realname) {
387     silc_buffer_format(buf,
388                        SILC_STR_UI32_STRING(", "),
389                        SILC_STR_UI32_STRING("RN="),
390                        SILC_STR_UI32_STRING(realname),
391                        SILC_STR_END);
392     silc_buffer_pull(buf, 5 + strlen(realname));
393     tlen += 5 + strlen(realname); 
394   }
395
396   if (email) {
397     silc_buffer_format(buf,
398                        SILC_STR_UI32_STRING(", "),
399                        SILC_STR_UI32_STRING("E="),
400                        SILC_STR_UI32_STRING(email),
401                        SILC_STR_END);
402     silc_buffer_pull(buf, 4 + strlen(email));
403     tlen += 4 + strlen(email); 
404   }
405
406   if (org) {
407     silc_buffer_format(buf,
408                        SILC_STR_UI32_STRING(", "),
409                        SILC_STR_UI32_STRING("O="),
410                        SILC_STR_UI32_STRING(org),
411                        SILC_STR_END);
412     silc_buffer_pull(buf, 4 + strlen(org));
413     tlen += 4 + strlen(org); 
414   }
415
416   if (country) {
417     silc_buffer_format(buf,
418                        SILC_STR_UI32_STRING(", "),
419                        SILC_STR_UI32_STRING("C="),
420                        SILC_STR_UI32_STRING(country),
421                        SILC_STR_END);
422     silc_buffer_pull(buf, 4 + strlen(country));
423     tlen += 4 + strlen(country); 
424   }
425
426   silc_buffer_push(buf, buf->data - buf->head);
427   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
428   memcpy(identifier, buf->data, tlen);
429   silc_buffer_free(buf);
430
431   return identifier;
432 }
433
434 /* Decodes the provided `identifier' and returns allocated context for
435    the identifier. */
436
437 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
438 {
439   SilcPublicKeyIdentifier ident;
440   char *cp, *item;
441   int len;
442
443   ident = silc_calloc(1, sizeof(*ident));
444
445   cp = identifier;
446   while (cp) {
447     len = strcspn(cp, ",");
448     if (len - 1 >= 0 && cp[len - 1] == '\\') {
449       cp += len + 1;
450       continue;
451     }
452
453     item = silc_calloc(len + 1, sizeof(char));
454     memcpy(item, cp, len);
455
456     if (strstr(item, "UN="))
457       ident->username = strdup(item + strcspn(cp, "=") + 1);
458     else if (strstr(item, "HN="))
459       ident->host = strdup(item + strcspn(cp, "=") + 1);
460     else if (strstr(item, "RN="))
461       ident->realname = strdup(item + strcspn(cp, "=") + 1);
462     else if (strstr(item, "E="))
463       ident->email = strdup(item + strcspn(cp, "=") + 1);
464     else if (strstr(item, "O="))
465       ident->org = strdup(item + strcspn(cp, "=") + 1);
466     else if (strstr(item, "C="))
467       ident->country = strdup(item + strcspn(cp, "=") + 1);
468     
469     cp += len;
470     if (strlen(cp) == 0)
471       cp = NULL;
472     else
473       cp += 1;
474     
475     if (item)
476       silc_free(item);
477   }
478
479   return ident;
480 }
481
482 /* Free's decoded public key identifier context. Call this to free the
483    context returned by the silc_pkcs_decode_identifier. */
484
485 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
486 {
487   silc_free(identifier->username);
488   silc_free(identifier->host);
489   silc_free(identifier->realname);
490   silc_free(identifier->email);
491   silc_free(identifier->org);
492   silc_free(identifier->country);
493   silc_free(identifier);
494 }
495
496 /* Allocates SILC style public key formed from sent arguments. All data
497    is duplicated. */
498
499 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
500                                          unsigned char *pk, 
501                                          uint32 pk_len)
502 {
503   SilcPublicKey public_key;
504
505   public_key = silc_calloc(1, sizeof(*public_key));
506   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
507   public_key->name = strdup(name);
508   public_key->identifier = strdup(identifier);
509   public_key->pk_len = pk_len;
510   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
511   memcpy(public_key->pk, pk, pk_len);
512
513   return public_key;
514 }
515
516 /* Free's public key */
517
518 void silc_pkcs_public_key_free(SilcPublicKey public_key)
519 {
520   if (public_key) {
521     silc_free(public_key->name);
522     silc_free(public_key->identifier);
523     silc_free(public_key->pk);
524     silc_free(public_key);
525   }
526 }
527
528 /* Allocates SILC private key formed from sent arguments. All data is
529    duplicated. */
530
531 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
532                                            uint32 prv_len)
533 {
534   SilcPrivateKey private_key;
535
536   private_key = silc_calloc(1, sizeof(*private_key));
537   private_key->name = strdup(name);
538   private_key->prv_len = prv_len;
539   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
540   memcpy(private_key->prv, prv, prv_len);
541
542   return private_key;
543 }
544
545 /* Free's private key */
546
547 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
548 {
549   if (private_key) {
550     silc_free(private_key->name);
551     silc_free(private_key->prv);
552     silc_free(private_key);
553   }
554 }
555
556 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
557    data. */
558
559 unsigned char *
560 silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
561 {
562   SilcBuffer buf;
563   unsigned char *ret;
564
565   buf = silc_buffer_alloc(public_key->len);
566   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
567
568   silc_buffer_format(buf,
569                      SILC_STR_UI_INT(public_key->len),
570                      SILC_STR_UI_SHORT(strlen(public_key->name)),
571                      SILC_STR_UI32_STRING(public_key->name),
572                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
573                      SILC_STR_UI32_STRING(public_key->identifier),
574                      SILC_STR_UI_XNSTRING(public_key->pk, 
575                                           public_key->pk_len),
576                      SILC_STR_END);
577   if (len)
578     *len = public_key->len;
579
580   ret = silc_calloc(buf->len, sizeof(*ret));
581   memcpy(ret, buf->data, buf->len);
582   silc_buffer_free(buf);
583
584   return ret;
585 }
586
587 /* Encodes SILC style public key. Returns the encoded data. */
588
589 unsigned char *
590 silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
591                                  char *pkcs, char *identifier, 
592                                  uint32 *len)
593 {
594   SilcBuffer buf;
595   unsigned char *ret;
596   uint32 totlen;
597
598   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
599   buf = silc_buffer_alloc(totlen);
600   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
601
602   silc_buffer_format(buf,
603                      SILC_STR_UI_INT(totlen),
604                      SILC_STR_UI_SHORT(strlen(pkcs)),
605                      SILC_STR_UI32_STRING(pkcs),
606                      SILC_STR_UI_SHORT(strlen(identifier)),
607                      SILC_STR_UI32_STRING(identifier),
608                      SILC_STR_UI_XNSTRING(pk, pk_len),
609                      SILC_STR_END);
610   if (len)
611     *len = totlen;
612
613   ret = silc_calloc(buf->len, sizeof(*ret));
614   memcpy(ret, buf->data, buf->len);
615   silc_buffer_free(buf);
616
617   return ret;
618 }
619
620 /* Decodes SILC style public key. Returns TRUE if the decoding was
621    successful. Allocates new public key as well. */
622
623 int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
624                                 SilcPublicKey *public_key)
625 {
626   SilcBuffer buf;
627   SilcPKCS alg;
628   uint16 pkcs_len, identifier_len;
629   uint32 totlen, key_len;
630   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
631   int ret;
632
633   buf = silc_buffer_alloc(data_len);
634   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
635   silc_buffer_put(buf, data, data_len);
636
637   /* Get length */
638   ret = silc_buffer_unformat(buf,
639                              SILC_STR_UI_INT(&totlen),
640                              SILC_STR_END);
641   if (ret == -1) {
642     silc_buffer_free(buf);
643     return FALSE;
644   }
645
646   if (totlen != data_len) {
647     silc_buffer_free(buf);
648     return FALSE;
649   }
650
651   /* Get algorithm name and identifier */
652   silc_buffer_pull(buf, 4);
653   ret =
654     silc_buffer_unformat(buf,
655                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
656                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
657                          SILC_STR_END);
658   if (ret == -1)
659     goto err;
660
661   if (pkcs_len < 1 || identifier_len < 3 || 
662       pkcs_len + identifier_len > totlen)
663     goto err;
664
665   /* See if we support this algorithm (check only if PKCS are registered) */
666   if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
667     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
668     goto err;
669   }
670
671   /* Protocol says that at least UN and HN must be provided as identifier,
672      check for these. */
673   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
674     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
675                     "identifiers"));
676     goto err;
677   }
678
679   /* Get key data. We assume that rest of the buffer is key data. */
680   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
681   key_len = buf->len;
682   ret = silc_buffer_unformat(buf,
683                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
684                              SILC_STR_END);
685   if (ret == -1)
686     goto err;
687
688   /* Try to set the key. If this fails the key must be malformed. This
689      code assumes that the PKCS routine checks the format of the key. 
690      (check only if PKCS are registered) */
691   if (silc_pkcs_list) {
692     silc_pkcs_alloc(pkcs_name, &alg);
693     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
694       goto err;
695     silc_pkcs_free(alg);
696   }
697   
698   if (public_key) {
699     *public_key = silc_calloc(1, sizeof(**public_key));
700     (*public_key)->len = totlen;
701     (*public_key)->name = pkcs_name;
702     (*public_key)->identifier = ident;
703     (*public_key)->pk = key_data;
704     (*public_key)->pk_len = key_len;
705   }
706
707   silc_buffer_free(buf);
708   return TRUE;
709
710  err:
711   if (pkcs_name)
712     silc_free(pkcs_name);
713   if (ident)
714     silc_free(ident);
715   if (key_data)
716     silc_free(key_data);
717   silc_buffer_free(buf);
718   return FALSE;
719 }
720
721 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
722
723 unsigned char *
724 silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
725 {
726   SilcBuffer buf;
727   unsigned char *ret;
728   uint32 totlen;
729
730   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
731   buf = silc_buffer_alloc(totlen);
732   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
733
734   silc_buffer_format(buf,
735                      SILC_STR_UI_SHORT(strlen(private_key->name)),
736                      SILC_STR_UI32_STRING(private_key->name),
737                      SILC_STR_UI_XNSTRING(private_key->prv, 
738                                           private_key->prv_len),
739                      SILC_STR_END);
740   if (len)
741     *len = totlen;
742
743   ret = silc_calloc(buf->len, sizeof(*ret));
744   memcpy(ret, buf->data, buf->len);
745   silc_buffer_free(buf);
746
747   return ret;
748 }
749
750 /* Encodes SILC private key. Returns the encoded data. */
751
752 unsigned char *
753 silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
754                                   char *pkcs, uint32 *len)
755 {
756   SilcBuffer buf;
757   unsigned char *ret;
758   uint32 totlen;
759
760   totlen = 2 + strlen(pkcs) + prv_len;
761   buf = silc_buffer_alloc(totlen);
762   silc_buffer_pull_tail(buf, totlen);
763
764   silc_buffer_format(buf,
765                      SILC_STR_UI_SHORT(strlen(pkcs)),
766                      SILC_STR_UI32_STRING(pkcs),
767                      SILC_STR_UI_XNSTRING(prv, prv_len),
768                      SILC_STR_END);
769   if (len)
770     *len = totlen;
771
772   ret = silc_calloc(buf->len, sizeof(*ret));
773   memcpy(ret, buf->data, buf->len);
774   silc_buffer_free(buf);
775
776   return ret;
777 }
778
779 /* Decodes SILC style public key. Returns TRUE if the decoding was
780    successful. Allocates new private key as well. */
781
782 int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
783                                  SilcPrivateKey *private_key)
784 {
785   SilcBuffer buf;
786   SilcPKCS alg;
787   uint16 pkcs_len;
788   uint32 key_len;
789   unsigned char *pkcs_name = NULL, *key_data = NULL;
790   int ret;
791
792   buf = silc_buffer_alloc(data_len);
793   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
794   silc_buffer_put(buf, data, data_len);
795
796   /* Get algorithm name and identifier */
797   ret = 
798     silc_buffer_unformat(buf,
799                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
800                          SILC_STR_END);
801   if (ret == -1)
802     goto err;
803
804   if (pkcs_len < 1 || pkcs_len > buf->truelen)
805     goto err;
806
807   /* See if we support this algorithm (check only if PKCS are registered). */
808   if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
809     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
810     goto err;
811   }
812
813   /* Get key data. We assume that rest of the buffer is key data. */
814   silc_buffer_pull(buf, 2 + pkcs_len);
815   key_len = buf->len;
816   ret = silc_buffer_unformat(buf,
817                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
818                              SILC_STR_END);
819   if (ret == -1)
820     goto err;
821
822   /* Try to set the key. If this fails the key must be malformed. This
823      code assumes that the PKCS routine checks the format of the key. 
824      (check only if PKCS are registered) */
825   if (silc_pkcs_list) {
826     silc_pkcs_alloc(pkcs_name, &alg);
827     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
828       goto err;
829     silc_pkcs_free(alg);
830   }
831   
832   if (private_key) {
833     *private_key = silc_calloc(1, sizeof(**private_key));
834     (*private_key)->name = pkcs_name;
835     (*private_key)->prv = key_data;
836     (*private_key)->prv_len = key_len;
837   }
838
839   silc_buffer_free(buf);
840   return TRUE;
841
842  err:
843   if (pkcs_name)
844     silc_free(pkcs_name);
845   if (key_data)
846     silc_free(key_data);
847   silc_buffer_free(buf);
848   return FALSE;
849 }
850
851 /* Internal routine to save public key */
852
853 static int silc_pkcs_save_public_key_internal(char *filename,
854                                               unsigned char *data,
855                                               uint32 data_len,
856                                               uint32 encoding)
857 {
858   SilcBuffer buf;
859   uint32 len;
860
861   switch(encoding) {
862   case SILC_PKCS_FILE_BIN:
863     break;
864   case SILC_PKCS_FILE_PEM:
865     data = silc_encode_pem_file(data, data_len);
866     data_len = strlen(data);
867     break;
868   }
869
870   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
871                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
872   buf = silc_buffer_alloc(len);
873   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
874
875   silc_buffer_format(buf,
876                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
877                      SILC_STR_UI_XNSTRING(data, data_len),
878                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
879                      SILC_STR_END);
880
881   /* Save into file */
882   if (silc_file_write(filename, buf->data, buf->len)) {
883     silc_buffer_free(buf);
884     return FALSE;
885   }
886
887   silc_buffer_free(buf);
888   return TRUE;
889 }
890
891 /* Saves public key into file */
892
893 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
894                               uint32 encoding)
895 {
896   unsigned char *data;
897   uint32 data_len;
898
899   data = silc_pkcs_public_key_encode(public_key, &data_len);
900   return silc_pkcs_save_public_key_internal(filename, data, data_len,
901                                             encoding);
902 }
903
904 /* Saves public key into file */
905
906 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
907                                    uint32 data_len,
908                                    uint32 encoding)
909 {
910   return silc_pkcs_save_public_key_internal(filename, data, data_len,
911                                             encoding);
912 }
913
914 /* Internal routine to save private key. */
915
916 static int silc_pkcs_save_private_key_internal(char *filename,
917                                                unsigned char *data,
918                                                uint32 data_len,
919                                                uint32 encoding)
920 {
921   SilcBuffer buf;
922   uint32 len;
923
924   switch(encoding) {
925   case SILC_PKCS_FILE_BIN:
926     break;
927   case SILC_PKCS_FILE_PEM:
928     data = silc_encode_pem_file(data, data_len);
929     data_len = strlen(data);
930     break;
931   }
932
933   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
934                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
935   buf = silc_buffer_alloc(len);
936   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
937
938   silc_buffer_format(buf,
939                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
940                      SILC_STR_UI_XNSTRING(data, data_len),
941                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
942                      SILC_STR_END);
943
944   /* Save into a file */
945   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
946     silc_buffer_free(buf);
947     return FALSE;
948   }
949
950   silc_buffer_free(buf);
951   return TRUE;
952 }
953
954 /* Saves private key into file. */
955 /* XXX The buffer should be encrypted if passphrase is provided. */
956
957 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
958                                unsigned char *passphrase,
959                                uint32 encoding)
960 {
961   unsigned char *data;
962   uint32 data_len;
963
964   data = silc_pkcs_private_key_encode(private_key, &data_len);
965   return silc_pkcs_save_private_key_internal(filename, data, data_len,
966                                              encoding);
967 }
968
969 /* Saves private key into file. */
970 /* XXX The buffer should be encrypted if passphrase is provided. */
971
972 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
973                                     uint32 data_len,
974                                     unsigned char *passphrase,
975                                     uint32 encoding)
976 {
977   return silc_pkcs_save_private_key_internal(filename, data, data_len,
978                                              encoding);
979 }
980
981 /* Loads public key from file and allocates new public key. Returns TRUE
982    is loading was successful. */
983
984 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
985                               uint32 encoding)
986 {
987   unsigned char *cp, *old, *data, byte;
988   uint32 i, data_len, len;
989
990   old = data = silc_file_read(filename, &data_len);
991   if (!data)
992     return FALSE;
993
994   /* Check start of file and remove header from the data. */
995   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
996   cp = data;
997   for (i = 0; i < len; i++) {
998     byte = cp[0];
999     cp++;
1000     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1001       memset(old, 0, data_len);
1002       silc_free(old);
1003       return FALSE;
1004     }
1005   }
1006   data = cp;
1007
1008   /* Decode public key */
1009   if (public_key) {
1010     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1011                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1012
1013     switch(encoding) {
1014     case SILC_PKCS_FILE_BIN:
1015       break;
1016     case SILC_PKCS_FILE_PEM:
1017       data = silc_decode_pem(data, len, &len);
1018       break;
1019     }
1020
1021     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1022       memset(old, 0, data_len);
1023       silc_free(old);
1024       return FALSE;
1025     }
1026   }
1027
1028   memset(old, 0, data_len);
1029   silc_free(old);
1030   return TRUE;
1031 }
1032
1033 /* Load private key from file and allocates new private key. Returns TRUE
1034    if loading was successful. */
1035 /* XXX Should support encrypted private key files */
1036
1037 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1038                                uint32 encoding)
1039 {
1040   unsigned char *cp, *old, *data, byte;
1041   uint32 i, data_len, len;
1042
1043   old = data = silc_file_read(filename, &data_len);
1044   if (!data)
1045     return FALSE;
1046
1047   /* Check start of file and remove header from the data. */
1048   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1049   cp = data;
1050   for (i = 0; i < len; i++) {
1051     byte = cp[0];
1052     cp++;
1053     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1054       memset(old, 0, data_len);
1055       silc_free(old);
1056       return FALSE;
1057     }
1058   }
1059   data = cp;
1060
1061   /* Decode private key */
1062   if (private_key) {
1063     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1064                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1065
1066     switch(encoding) {
1067     case SILC_PKCS_FILE_BIN:
1068       break;
1069     case SILC_PKCS_FILE_PEM:
1070       data = silc_decode_pem(data, len, &len);
1071       break;
1072     }
1073
1074     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1075       memset(old, 0, data_len);
1076       silc_free(old);
1077       return FALSE;
1078     }
1079   }
1080
1081   memset(old, 0, data_len);
1082   silc_free(old);
1083   return TRUE;
1084 }