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