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;
411 if (!username || !host)
414 len = (username ? silc_utf8_encoded_len(username, strlen(username), 0) : 0) +
415 (host ? silc_utf8_encoded_len(host, strlen(host), 0) : 0) +
416 (realname ? silc_utf8_encoded_len(realname, strlen(realname), 0) : 0) +
417 (email ? silc_utf8_encoded_len(email, strlen(email), 0) : 0) +
418 (org ? silc_utf8_encoded_len(org, strlen(org), 0) : 0) +
419 (country ? silc_utf8_encoded_len(country, strlen(country), 0) : 0);
424 len += 3 + 5 + 5 + 4 + 4 + 4;
425 buf = silc_buffer_alloc(len);
426 silc_buffer_pull_tail(buf, len);
429 memset(utf8, 0, sizeof(utf8));
430 len = silc_utf8_encode(username, strlen(username), 0, utf8,
432 silc_buffer_format(buf,
433 SILC_STR_UI32_STRING("UN="),
434 SILC_STR_UI32_STRING(utf8),
436 silc_buffer_pull(buf, 3 + len);
441 memset(utf8, 0, sizeof(utf8));
442 len = silc_utf8_encode(host, strlen(host), 0, utf8, sizeof(utf8) - 1);
443 silc_buffer_format(buf,
444 SILC_STR_UI32_STRING(", "),
445 SILC_STR_UI32_STRING("HN="),
446 SILC_STR_UI32_STRING(utf8),
448 silc_buffer_pull(buf, 5 + len);
453 memset(utf8, 0, sizeof(utf8));
454 len = silc_utf8_encode(realname, strlen(realname), 0, utf8,
456 silc_buffer_format(buf,
457 SILC_STR_UI32_STRING(", "),
458 SILC_STR_UI32_STRING("RN="),
459 SILC_STR_UI32_STRING(utf8),
461 silc_buffer_pull(buf, 5 + len);
466 memset(utf8, 0, sizeof(utf8));
467 len = silc_utf8_encode(email, strlen(email), 0, utf8, sizeof(utf8) - 1);
468 silc_buffer_format(buf,
469 SILC_STR_UI32_STRING(", "),
470 SILC_STR_UI32_STRING("E="),
471 SILC_STR_UI32_STRING(utf8),
473 silc_buffer_pull(buf, 4 + len);
478 memset(utf8, 0, sizeof(utf8));
479 len = silc_utf8_encode(org, strlen(org), 0, utf8, sizeof(utf8) - 1);
480 silc_buffer_format(buf,
481 SILC_STR_UI32_STRING(", "),
482 SILC_STR_UI32_STRING("O="),
483 SILC_STR_UI32_STRING(utf8),
485 silc_buffer_pull(buf, 4 + len);
490 memset(utf8, 0, sizeof(utf8));
491 len = silc_utf8_encode(country, strlen(country), 0, utf8,
493 silc_buffer_format(buf,
494 SILC_STR_UI32_STRING(", "),
495 SILC_STR_UI32_STRING("C="),
496 SILC_STR_UI32_STRING(utf8),
498 silc_buffer_pull(buf, 4 + len);
502 silc_buffer_push(buf, buf->data - buf->head);
503 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
504 memcpy(identifier, buf->data, tlen);
505 silc_buffer_free(buf);
510 /* Decodes the provided `identifier' and returns allocated context for
513 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
515 SilcPublicKeyIdentifier ident;
519 ident = silc_calloc(1, sizeof(*ident));
523 len = strcspn(cp, ",");
524 if (len - 1 >= 0 && cp[len - 1] == '\\') {
527 len = strcspn(cp, ",") + len;
528 if (len - 1 >= 0 && cp[len - 1] != '\\')
533 item = silc_calloc(len + 1, sizeof(char));
534 memcpy(item, cp, len);
536 if (strstr(item, "UN="))
537 ident->username = strdup(item + strcspn(cp, "=") + 1);
538 else if (strstr(item, "HN="))
539 ident->host = strdup(item + strcspn(cp, "=") + 1);
540 else if (strstr(item, "RN="))
541 ident->realname = strdup(item + strcspn(cp, "=") + 1);
542 else if (strstr(item, "E="))
543 ident->email = strdup(item + strcspn(cp, "=") + 1);
544 else if (strstr(item, "O="))
545 ident->org = strdup(item + strcspn(cp, "=") + 1);
546 else if (strstr(item, "C="))
547 ident->country = strdup(item + strcspn(cp, "=") + 1);
562 /* Free's decoded public key identifier context. Call this to free the
563 context returned by the silc_pkcs_decode_identifier. */
565 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
567 silc_free(identifier->username);
568 silc_free(identifier->host);
569 silc_free(identifier->realname);
570 silc_free(identifier->email);
571 silc_free(identifier->org);
572 silc_free(identifier->country);
573 silc_free(identifier);
576 /* Allocates SILC style public key formed from sent arguments. All data
579 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
583 SilcPublicKey public_key;
585 public_key = silc_calloc(1, sizeof(*public_key));
586 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
587 public_key->name = strdup(name);
588 public_key->identifier = strdup(identifier);
589 public_key->pk_len = pk_len;
590 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
591 memcpy(public_key->pk, pk, pk_len);
596 /* Free's public key */
598 void silc_pkcs_public_key_free(SilcPublicKey public_key)
601 silc_free(public_key->name);
602 silc_free(public_key->identifier);
603 silc_free(public_key->pk);
604 silc_free(public_key);
608 /* Allocates SILC private key formed from sent arguments. All data is
611 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
614 SilcPrivateKey private_key;
616 private_key = silc_calloc(1, sizeof(*private_key));
617 private_key->name = strdup(name);
618 private_key->prv_len = prv_len;
619 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
620 memcpy(private_key->prv, prv, prv_len);
625 /* Free's private key */
627 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
630 silc_free(private_key->name);
631 silc_free(private_key->prv);
632 silc_free(private_key);
636 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
640 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
645 buf = silc_buffer_alloc(public_key->len);
646 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
648 silc_buffer_format(buf,
649 SILC_STR_UI_INT(public_key->len),
650 SILC_STR_UI_SHORT(strlen(public_key->name)),
651 SILC_STR_UI32_STRING(public_key->name),
652 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
653 SILC_STR_UI32_STRING(public_key->identifier),
654 SILC_STR_UI_XNSTRING(public_key->pk,
658 *len = public_key->len;
660 ret = silc_calloc(buf->len, sizeof(*ret));
661 memcpy(ret, buf->data, buf->len);
662 silc_buffer_free(buf);
667 /* Encodes SILC style public key. Returns the encoded data. */
670 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
671 char *pkcs, char *identifier,
678 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
679 buf = silc_buffer_alloc(totlen);
680 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
682 silc_buffer_format(buf,
683 SILC_STR_UI_INT(totlen),
684 SILC_STR_UI_SHORT(strlen(pkcs)),
685 SILC_STR_UI32_STRING(pkcs),
686 SILC_STR_UI_SHORT(strlen(identifier)),
687 SILC_STR_UI32_STRING(identifier),
688 SILC_STR_UI_XNSTRING(pk, pk_len),
693 ret = silc_calloc(buf->len, sizeof(*ret));
694 memcpy(ret, buf->data, buf->len);
695 silc_buffer_free(buf);
700 /* Decodes SILC style public key. Returns TRUE if the decoding was
701 successful. Allocates new public key as well. */
703 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
704 SilcPublicKey *public_key)
708 SilcUInt16 pkcs_len, identifier_len;
709 SilcUInt32 totlen, key_len;
710 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
713 buf = silc_buffer_alloc(data_len);
714 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
715 silc_buffer_put(buf, data, data_len);
718 ret = silc_buffer_unformat(buf,
719 SILC_STR_UI_INT(&totlen),
722 silc_buffer_free(buf);
726 if (totlen != data_len) {
727 silc_buffer_free(buf);
731 /* Get algorithm name and identifier */
732 silc_buffer_pull(buf, 4);
734 silc_buffer_unformat(buf,
735 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
736 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
741 if (pkcs_len < 1 || identifier_len < 3 ||
742 pkcs_len + identifier_len > totlen)
745 /* See if we support this algorithm (check only if PKCS are registered) */
746 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
747 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
751 /* Protocol says that at least UN and HN must be provided as identifier,
753 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
754 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
759 /* Get key data. We assume that rest of the buffer is key data. */
760 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
762 ret = silc_buffer_unformat(buf,
763 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
768 /* Try to set the key. If this fails the key must be malformed. This
769 code assumes that the PKCS routine checks the format of the key.
770 (check only if PKCS are registered) */
771 if (SILC_PKCS_LIST) {
772 silc_pkcs_alloc(pkcs_name, &alg);
773 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
779 *public_key = silc_calloc(1, sizeof(**public_key));
780 (*public_key)->len = totlen;
781 (*public_key)->name = pkcs_name;
782 (*public_key)->identifier = ident;
783 (*public_key)->pk = key_data;
784 (*public_key)->pk_len = key_len;
787 silc_buffer_free(buf);
792 silc_free(pkcs_name);
797 silc_buffer_free(buf);
801 /* Compares two public keys and returns TRUE if they are same key, and
802 FALSE if they are not same. */
804 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
809 if (key1->len == key2->len &&
810 key1->name && key2->name && key1->identifier && key2->identifier &&
811 !strcmp(key1->name, key2->name) &&
812 !strcmp(key1->identifier, key2->identifier) &&
813 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
814 key1->pk_len == key2->pk_len)
820 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
823 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
829 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
830 buf = silc_buffer_alloc(totlen);
831 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
833 silc_buffer_format(buf,
834 SILC_STR_UI_SHORT(strlen(private_key->name)),
835 SILC_STR_UI32_STRING(private_key->name),
836 SILC_STR_UI_XNSTRING(private_key->prv,
837 private_key->prv_len),
842 ret = silc_calloc(buf->len, sizeof(*ret));
843 memcpy(ret, buf->data, buf->len);
844 silc_buffer_free(buf);
849 /* Encodes SILC private key. Returns the encoded data. */
852 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
853 char *pkcs, SilcUInt32 *len)
859 totlen = 2 + strlen(pkcs) + prv_len;
860 buf = silc_buffer_alloc(totlen);
861 silc_buffer_pull_tail(buf, totlen);
863 silc_buffer_format(buf,
864 SILC_STR_UI_SHORT(strlen(pkcs)),
865 SILC_STR_UI32_STRING(pkcs),
866 SILC_STR_UI_XNSTRING(prv, prv_len),
871 ret = silc_calloc(buf->len, sizeof(*ret));
872 memcpy(ret, buf->data, buf->len);
873 silc_buffer_free(buf);
878 /* Decodes SILC style public key. Returns TRUE if the decoding was
879 successful. Allocates new private key as well. */
881 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
882 SilcPrivateKey *private_key)
888 unsigned char *pkcs_name = NULL, *key_data = NULL;
891 buf = silc_buffer_alloc(data_len);
892 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
893 silc_buffer_put(buf, data, data_len);
895 /* Get algorithm name and identifier */
897 silc_buffer_unformat(buf,
898 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
903 if (pkcs_len < 1 || pkcs_len > buf->truelen)
906 /* See if we support this algorithm (check only if PKCS are registered). */
907 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
908 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
912 /* Get key data. We assume that rest of the buffer is key data. */
913 silc_buffer_pull(buf, 2 + pkcs_len);
915 ret = silc_buffer_unformat(buf,
916 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
921 /* Try to set the key. If this fails the key must be malformed. This
922 code assumes that the PKCS routine checks the format of the key.
923 (check only if PKCS are registered) */
924 if (SILC_PKCS_LIST) {
925 silc_pkcs_alloc(pkcs_name, &alg);
926 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
932 *private_key = silc_calloc(1, sizeof(**private_key));
933 (*private_key)->name = pkcs_name;
934 (*private_key)->prv = key_data;
935 (*private_key)->prv_len = key_len;
938 silc_buffer_free(buf);
943 silc_free(pkcs_name);
946 silc_buffer_free(buf);
950 /* Internal routine to save public key */
952 static int silc_pkcs_save_public_key_internal(char *filename,
961 case SILC_PKCS_FILE_BIN:
963 case SILC_PKCS_FILE_PEM:
964 data = silc_pem_encode_file(data, data_len);
965 data_len = strlen(data);
969 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
970 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
971 buf = silc_buffer_alloc(len);
972 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
974 silc_buffer_format(buf,
975 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
976 SILC_STR_UI_XNSTRING(data, data_len),
977 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
981 if (silc_file_writefile(filename, buf->data, buf->len)) {
982 silc_buffer_free(buf);
986 silc_buffer_free(buf);
990 /* Saves public key into file */
992 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
998 data = silc_pkcs_public_key_encode(public_key, &data_len);
999 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1003 /* Saves public key into file */
1005 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1006 SilcUInt32 data_len,
1007 SilcUInt32 encoding)
1009 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1013 /* Internal routine to save private key. */
1015 static int silc_pkcs_save_private_key_internal(char *filename,
1016 unsigned char *data,
1017 SilcUInt32 data_len,
1018 SilcUInt32 encoding)
1024 case SILC_PKCS_FILE_BIN:
1026 case SILC_PKCS_FILE_PEM:
1027 data = silc_pem_encode_file(data, data_len);
1028 data_len = strlen(data);
1032 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1033 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1034 buf = silc_buffer_alloc(len);
1035 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1037 silc_buffer_format(buf,
1038 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1039 SILC_STR_UI_XNSTRING(data, data_len),
1040 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1043 /* Save into a file */
1044 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1045 silc_buffer_free(buf);
1049 silc_buffer_free(buf);
1053 /* Saves private key into file. */
1054 /* XXX The buffer should be encrypted if passphrase is provided. */
1056 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1057 unsigned char *passphrase,
1058 SilcUInt32 encoding)
1060 unsigned char *data;
1061 SilcUInt32 data_len;
1063 data = silc_pkcs_private_key_encode(private_key, &data_len);
1064 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1068 /* Saves private key into file. */
1069 /* XXX The buffer should be encrypted if passphrase is provided. */
1071 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1072 SilcUInt32 data_len,
1073 unsigned char *passphrase,
1074 SilcUInt32 encoding)
1076 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1080 /* Loads public key from file and allocates new public key. Returns TRUE
1081 is loading was successful. */
1083 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1084 SilcUInt32 encoding)
1086 unsigned char *cp, *old, *data, byte;
1087 SilcUInt32 i, data_len, len;
1089 old = data = silc_file_readfile(filename, &data_len);
1093 /* Check start of file and remove header from the data. */
1094 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1096 for (i = 0; i < len; i++) {
1099 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1100 memset(old, 0, data_len);
1107 /* Decode public key */
1109 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1110 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1113 case SILC_PKCS_FILE_BIN:
1115 case SILC_PKCS_FILE_PEM:
1116 data = silc_pem_decode(data, len, &len);
1117 memset(old, 0, data_len);
1124 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1125 memset(old, 0, data_len);
1131 memset(old, 0, data_len);
1136 /* Load private key from file and allocates new private key. Returns TRUE
1137 if loading was successful. */
1138 /* XXX Should support encrypted private key files */
1140 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1141 SilcUInt32 encoding)
1143 unsigned char *cp, *old, *data, byte;
1144 SilcUInt32 i, data_len, len;
1146 old = data = silc_file_readfile(filename, &data_len);
1150 /* Check start of file and remove header from the data. */
1151 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1153 for (i = 0; i < len; i++) {
1156 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1157 memset(old, 0, data_len);
1164 /* Decode private key */
1166 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1167 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1170 case SILC_PKCS_FILE_BIN:
1172 case SILC_PKCS_FILE_PEM:
1173 data = silc_pem_decode(data, len, &len);
1177 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1178 memset(old, 0, data_len);
1184 memset(old, 0, data_len);