5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
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.
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.
22 #include "silcincludes.h"
28 /* Dynamically registered list of PKCS. */
29 SilcDList silc_pkcs_list = NULL;
30 #define SILC_PKCS_LIST silc_pkcs_list
32 #define SILC_PKCS_LIST TRUE
33 #endif /* SILC_EPOC */
35 /* Static list of PKCS for silc_pkcs_register_default(). */
36 const SilcPKCSObject silc_default_pkcs[] =
38 /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
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 },
46 /* Raw RSA operations */
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 },
54 { NULL, NULL, NULL, NULL, NULL,
55 NULL, NULL, NULL, NULL, NULL, NULL }
58 /* Register a new PKCS into SILC. This is used at the initialization of
61 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
66 SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
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;
83 if (silc_pkcs_list == NULL)
84 silc_pkcs_list = silc_dlist_init();
85 silc_dlist_add(silc_pkcs_list, new);
87 #endif /* SILC_EPOC */
91 /* Unregister a PKCS from the SILC. */
93 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
96 SilcPKCSObject *entry;
98 SILC_LOG_DEBUG(("Unregistering PKCS"));
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);
108 if (silc_dlist_count(silc_pkcs_list) == 0) {
109 silc_dlist_uninit(silc_pkcs_list);
110 silc_pkcs_list = NULL;
117 #endif /* SILC_EPOC */
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. */
125 bool silc_pkcs_register_default(void)
130 for (i = 0; silc_default_pkcs[i].name; i++)
131 silc_pkcs_register(&(silc_default_pkcs[i]));
133 #endif /* SILC_EPOC */
137 /* Allocates a new SilcPKCS object. The new allocated object is returned
138 to the 'new_pkcs' argument. */
140 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
142 SilcPKCSObject *entry = NULL;
144 SILC_LOG_DEBUG(("Allocating new PKCS object"));
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))
156 /* On EPOC which don't have globals we check our constant hash list. */
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]);
165 #endif /* SILC_EPOC */
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;
178 /* Free's the PKCS object */
180 void silc_pkcs_free(SilcPKCS pkcs)
183 pkcs->pkcs->clear_keys(pkcs->context);
184 silc_free(pkcs->context);
189 /* Return TRUE if PKCS algorithm `name' is supported. */
191 int silc_pkcs_is_supported(const unsigned char *name)
194 SilcPKCSObject *entry;
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))
206 for (i = 0; silc_default_pkcs[i].name; i++)
207 if (!strcmp(silc_default_pkcs[i].name, name))
210 #endif /* SILC_EPOC */
214 /* Returns comma separated list of supported PKCS algorithms */
216 char *silc_pkcs_get_supported(void)
218 SilcPKCSObject *entry;
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);
229 memcpy(list + (len - strlen(entry->name)),
230 entry->name, strlen(entry->name));
231 memcpy(list + len, ",", 1);
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);
243 memcpy(list + (len - strlen(entry->name)),
244 entry->name, strlen(entry->name));
245 memcpy(list + len, ",", 1);
249 #endif /* SILC_EPOC */
256 /* Generate new key pair into the `pkcs' context. */
258 int silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
261 return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
264 /* Returns the length of the key */
266 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
268 return pkcs->key_len;
271 /* Returns SILC style public key */
273 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
275 return pkcs->pkcs->get_public_key(pkcs->context, len);
278 /* Returns SILC style private key */
280 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
282 return pkcs->pkcs->get_private_key(pkcs->context, len);
285 /* Sets public key from SilcPublicKey. */
287 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
289 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
291 return pkcs->key_len;
294 /* Sets public key from data. */
296 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
299 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
300 return pkcs->key_len;
303 /* Sets private key from SilcPrivateKey. */
305 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
307 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
308 private_key->prv_len);
311 /* Sets private key from data. */
313 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
316 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
321 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
322 unsigned char *dst, SilcUInt32 *dst_len)
324 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
329 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
330 unsigned char *dst, SilcUInt32 *dst_len)
332 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
335 /* Generates signature */
337 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
338 unsigned char *dst, SilcUInt32 *dst_len)
340 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
343 /* Verifies signature */
345 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
346 SilcUInt32 signature_len, unsigned char *data,
349 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
353 /* Generates signature with hash. The hash is signed. */
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)
359 unsigned char hashr[32];
363 silc_hash_make(hash, src, src_len, hashr);
364 hash_len = hash->hash->hash_len;
366 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
368 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
369 memset(hashr, 0, sizeof(hashr));
374 /* Verifies signature with hash. The `data' is hashed and verified against
377 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
378 unsigned char *signature,
379 SilcUInt32 signature_len,
383 unsigned char hashr[32];
387 silc_hash_make(hash, data, data_len, hashr);
388 hash_len = hash->hash->hash_len;
390 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
392 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
394 memset(hashr, 0, sizeof(hashr));
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. */
403 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
404 char *email, char *org, char *country)
408 SilcUInt32 len, tlen = 0;
410 if (!username || !host)
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);
423 len += 3 + 5 + 5 + 4 + 4 + 4;
424 buf = silc_buffer_alloc(len);
425 silc_buffer_pull_tail(buf, len);
428 silc_buffer_format(buf,
429 SILC_STR_UI32_STRING("UN="),
430 SILC_STR_UI32_STRING(username),
432 silc_buffer_pull(buf, 3 + strlen(username));
433 tlen = 3 + strlen(username);
437 silc_buffer_format(buf,
438 SILC_STR_UI32_STRING(", "),
439 SILC_STR_UI32_STRING("HN="),
440 SILC_STR_UI32_STRING(host),
442 silc_buffer_pull(buf, 5 + strlen(host));
443 tlen += 5 + strlen(host);
447 silc_buffer_format(buf,
448 SILC_STR_UI32_STRING(", "),
449 SILC_STR_UI32_STRING("RN="),
450 SILC_STR_UI32_STRING(realname),
452 silc_buffer_pull(buf, 5 + strlen(realname));
453 tlen += 5 + strlen(realname);
457 silc_buffer_format(buf,
458 SILC_STR_UI32_STRING(", "),
459 SILC_STR_UI32_STRING("E="),
460 SILC_STR_UI32_STRING(email),
462 silc_buffer_pull(buf, 4 + strlen(email));
463 tlen += 4 + strlen(email);
467 silc_buffer_format(buf,
468 SILC_STR_UI32_STRING(", "),
469 SILC_STR_UI32_STRING("O="),
470 SILC_STR_UI32_STRING(org),
472 silc_buffer_pull(buf, 4 + strlen(org));
473 tlen += 4 + strlen(org);
477 silc_buffer_format(buf,
478 SILC_STR_UI32_STRING(", "),
479 SILC_STR_UI32_STRING("C="),
480 SILC_STR_UI32_STRING(country),
482 silc_buffer_pull(buf, 4 + strlen(country));
483 tlen += 4 + strlen(country);
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);
494 /* Decodes the provided `identifier' and returns allocated context for
497 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
499 SilcPublicKeyIdentifier ident;
503 ident = silc_calloc(1, sizeof(*ident));
507 len = strcspn(cp, ",");
508 if (len - 1 >= 0 && cp[len - 1] == '\\') {
511 len = strcspn(cp, ",") + len;
512 if (len - 1 >= 0 && cp[len - 1] != '\\')
517 item = silc_calloc(len + 1, sizeof(char));
518 memcpy(item, cp, len);
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);
546 /* Free's decoded public key identifier context. Call this to free the
547 context returned by the silc_pkcs_decode_identifier. */
549 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
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);
560 /* Allocates SILC style public key formed from sent arguments. All data
563 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
567 SilcPublicKey public_key;
569 public_key = silc_calloc(1, sizeof(*public_key));
570 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
571 public_key->name = strdup(name);
572 public_key->identifier = strdup(identifier);
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);
580 /* Free's public key */
582 void silc_pkcs_public_key_free(SilcPublicKey public_key)
585 silc_free(public_key->name);
586 silc_free(public_key->identifier);
587 silc_free(public_key->pk);
588 silc_free(public_key);
592 /* Allocates SILC private key formed from sent arguments. All data is
595 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
598 SilcPrivateKey private_key;
600 private_key = silc_calloc(1, sizeof(*private_key));
601 private_key->name = strdup(name);
602 private_key->prv_len = prv_len;
603 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
604 memcpy(private_key->prv, prv, prv_len);
609 /* Free's private key */
611 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
614 silc_free(private_key->name);
615 silc_free(private_key->prv);
616 silc_free(private_key);
620 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
624 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
629 buf = silc_buffer_alloc(public_key->len);
630 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
632 silc_buffer_format(buf,
633 SILC_STR_UI_INT(public_key->len),
634 SILC_STR_UI_SHORT(strlen(public_key->name)),
635 SILC_STR_UI32_STRING(public_key->name),
636 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
637 SILC_STR_UI32_STRING(public_key->identifier),
638 SILC_STR_UI_XNSTRING(public_key->pk,
642 *len = public_key->len;
644 ret = silc_calloc(buf->len, sizeof(*ret));
645 memcpy(ret, buf->data, buf->len);
646 silc_buffer_free(buf);
651 /* Encodes SILC style public key. Returns the encoded data. */
654 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
655 char *pkcs, char *identifier,
662 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
663 buf = silc_buffer_alloc(totlen);
664 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
666 silc_buffer_format(buf,
667 SILC_STR_UI_INT(totlen),
668 SILC_STR_UI_SHORT(strlen(pkcs)),
669 SILC_STR_UI32_STRING(pkcs),
670 SILC_STR_UI_SHORT(strlen(identifier)),
671 SILC_STR_UI32_STRING(identifier),
672 SILC_STR_UI_XNSTRING(pk, pk_len),
677 ret = silc_calloc(buf->len, sizeof(*ret));
678 memcpy(ret, buf->data, buf->len);
679 silc_buffer_free(buf);
684 /* Decodes SILC style public key. Returns TRUE if the decoding was
685 successful. Allocates new public key as well. */
687 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
688 SilcPublicKey *public_key)
692 SilcUInt16 pkcs_len, identifier_len;
693 SilcUInt32 totlen, key_len;
694 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
697 buf = silc_buffer_alloc(data_len);
698 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
699 silc_buffer_put(buf, data, data_len);
702 ret = silc_buffer_unformat(buf,
703 SILC_STR_UI_INT(&totlen),
706 silc_buffer_free(buf);
710 if (totlen != data_len) {
711 silc_buffer_free(buf);
715 /* Get algorithm name and identifier */
716 silc_buffer_pull(buf, 4);
718 silc_buffer_unformat(buf,
719 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
720 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
725 if (pkcs_len < 1 || identifier_len < 3 ||
726 pkcs_len + identifier_len > totlen)
729 /* See if we support this algorithm (check only if PKCS are registered) */
730 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
731 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
735 /* Protocol says that at least UN and HN must be provided as identifier,
737 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
738 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
743 /* Get key data. We assume that rest of the buffer is key data. */
744 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
746 ret = silc_buffer_unformat(buf,
747 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
752 /* Try to set the key. If this fails the key must be malformed. This
753 code assumes that the PKCS routine checks the format of the key.
754 (check only if PKCS are registered) */
755 if (SILC_PKCS_LIST) {
756 silc_pkcs_alloc(pkcs_name, &alg);
757 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
763 *public_key = silc_calloc(1, sizeof(**public_key));
764 (*public_key)->len = totlen;
765 (*public_key)->name = pkcs_name;
766 (*public_key)->identifier = ident;
767 (*public_key)->pk = key_data;
768 (*public_key)->pk_len = key_len;
771 silc_buffer_free(buf);
776 silc_free(pkcs_name);
781 silc_buffer_free(buf);
785 /* Compares two public keys and returns TRUE if they are same key, and
786 FALSE if they are not same. */
788 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
793 if (key1->len == key2->len &&
794 key1->name && key2->name && key1->identifier && key2->identifier &&
795 !strcmp(key1->name, key2->name) &&
796 !strcmp(key1->identifier, key2->identifier) &&
797 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
798 key1->pk_len == key2->pk_len)
804 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
807 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
813 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
814 buf = silc_buffer_alloc(totlen);
815 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
817 silc_buffer_format(buf,
818 SILC_STR_UI_SHORT(strlen(private_key->name)),
819 SILC_STR_UI32_STRING(private_key->name),
820 SILC_STR_UI_XNSTRING(private_key->prv,
821 private_key->prv_len),
826 ret = silc_calloc(buf->len, sizeof(*ret));
827 memcpy(ret, buf->data, buf->len);
828 silc_buffer_free(buf);
833 /* Encodes SILC private key. Returns the encoded data. */
836 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
837 char *pkcs, SilcUInt32 *len)
843 totlen = 2 + strlen(pkcs) + prv_len;
844 buf = silc_buffer_alloc(totlen);
845 silc_buffer_pull_tail(buf, totlen);
847 silc_buffer_format(buf,
848 SILC_STR_UI_SHORT(strlen(pkcs)),
849 SILC_STR_UI32_STRING(pkcs),
850 SILC_STR_UI_XNSTRING(prv, prv_len),
855 ret = silc_calloc(buf->len, sizeof(*ret));
856 memcpy(ret, buf->data, buf->len);
857 silc_buffer_free(buf);
862 /* Decodes SILC style public key. Returns TRUE if the decoding was
863 successful. Allocates new private key as well. */
865 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
866 SilcPrivateKey *private_key)
872 unsigned char *pkcs_name = NULL, *key_data = NULL;
875 buf = silc_buffer_alloc(data_len);
876 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
877 silc_buffer_put(buf, data, data_len);
879 /* Get algorithm name and identifier */
881 silc_buffer_unformat(buf,
882 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
887 if (pkcs_len < 1 || pkcs_len > buf->truelen)
890 /* See if we support this algorithm (check only if PKCS are registered). */
891 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
892 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
896 /* Get key data. We assume that rest of the buffer is key data. */
897 silc_buffer_pull(buf, 2 + pkcs_len);
899 ret = silc_buffer_unformat(buf,
900 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
905 /* Try to set the key. If this fails the key must be malformed. This
906 code assumes that the PKCS routine checks the format of the key.
907 (check only if PKCS are registered) */
908 if (SILC_PKCS_LIST) {
909 silc_pkcs_alloc(pkcs_name, &alg);
910 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
916 *private_key = silc_calloc(1, sizeof(**private_key));
917 (*private_key)->name = pkcs_name;
918 (*private_key)->prv = key_data;
919 (*private_key)->prv_len = key_len;
922 silc_buffer_free(buf);
927 silc_free(pkcs_name);
930 silc_buffer_free(buf);
934 /* Internal routine to save public key */
936 static int silc_pkcs_save_public_key_internal(char *filename,
945 case SILC_PKCS_FILE_BIN:
947 case SILC_PKCS_FILE_PEM:
948 data = silc_encode_pem_file(data, data_len);
949 data_len = strlen(data);
953 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
954 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
955 buf = silc_buffer_alloc(len);
956 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
958 silc_buffer_format(buf,
959 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
960 SILC_STR_UI_XNSTRING(data, data_len),
961 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
965 if (silc_file_writefile(filename, buf->data, buf->len)) {
966 silc_buffer_free(buf);
970 silc_buffer_free(buf);
974 /* Saves public key into file */
976 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
982 data = silc_pkcs_public_key_encode(public_key, &data_len);
983 return silc_pkcs_save_public_key_internal(filename, data, data_len,
987 /* Saves public key into file */
989 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
993 return silc_pkcs_save_public_key_internal(filename, data, data_len,
997 /* Internal routine to save private key. */
999 static int silc_pkcs_save_private_key_internal(char *filename,
1000 unsigned char *data,
1001 SilcUInt32 data_len,
1002 SilcUInt32 encoding)
1008 case SILC_PKCS_FILE_BIN:
1010 case SILC_PKCS_FILE_PEM:
1011 data = silc_encode_pem_file(data, data_len);
1012 data_len = strlen(data);
1016 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1017 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1018 buf = silc_buffer_alloc(len);
1019 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1021 silc_buffer_format(buf,
1022 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1023 SILC_STR_UI_XNSTRING(data, data_len),
1024 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1027 /* Save into a file */
1028 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1029 silc_buffer_free(buf);
1033 silc_buffer_free(buf);
1037 /* Saves private key into file. */
1038 /* XXX The buffer should be encrypted if passphrase is provided. */
1040 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1041 unsigned char *passphrase,
1042 SilcUInt32 encoding)
1044 unsigned char *data;
1045 SilcUInt32 data_len;
1047 data = silc_pkcs_private_key_encode(private_key, &data_len);
1048 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1052 /* Saves private key into file. */
1053 /* XXX The buffer should be encrypted if passphrase is provided. */
1055 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1056 SilcUInt32 data_len,
1057 unsigned char *passphrase,
1058 SilcUInt32 encoding)
1060 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1064 /* Loads public key from file and allocates new public key. Returns TRUE
1065 is loading was successful. */
1067 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1068 SilcUInt32 encoding)
1070 unsigned char *cp, *old, *data, byte;
1071 SilcUInt32 i, data_len, len;
1073 old = data = silc_file_readfile(filename, &data_len);
1077 /* Check start of file and remove header from the data. */
1078 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1080 for (i = 0; i < len; i++) {
1083 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1084 memset(old, 0, data_len);
1091 /* Decode public key */
1093 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1094 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1097 case SILC_PKCS_FILE_BIN:
1099 case SILC_PKCS_FILE_PEM:
1100 data = silc_decode_pem(data, len, &len);
1101 memset(old, 0, data_len);
1108 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1109 memset(old, 0, data_len);
1115 memset(old, 0, data_len);
1120 /* Load private key from file and allocates new private key. Returns TRUE
1121 if loading was successful. */
1122 /* XXX Should support encrypted private key files */
1124 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1125 SilcUInt32 encoding)
1127 unsigned char *cp, *old, *data, byte;
1128 SilcUInt32 i, data_len, len;
1130 old = data = silc_file_readfile(filename, &data_len);
1134 /* Check start of file and remove header from the data. */
1135 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1137 for (i = 0; i < len; i++) {
1140 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1141 memset(old, 0, data_len);
1148 /* Decode private key */
1150 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1151 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1154 case SILC_PKCS_FILE_BIN:
1156 case SILC_PKCS_FILE_PEM:
1157 data = silc_decode_pem(data, len, &len);
1161 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1162 memset(old, 0, data_len);
1168 memset(old, 0, data_len);