5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
26 /* The main SILC PKCS structure. */
27 struct SilcPKCSStruct {
34 /* Dynamically registered list of PKCS. */
35 SilcDList silc_pkcs_list = NULL;
36 #define SILC_PKCS_LIST silc_pkcs_list
38 #define SILC_PKCS_LIST TRUE
39 #endif /* SILC_EPOC */
41 /* Static list of PKCS for silc_pkcs_register_default(). */
42 const SilcPKCSObject silc_default_pkcs[] =
44 /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
46 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
47 silc_rsa_get_private_key, silc_rsa_set_public_key,
48 silc_rsa_set_private_key, silc_rsa_context_len,
49 silc_pkcs1_encrypt, silc_pkcs1_decrypt,
50 silc_pkcs1_sign, silc_pkcs1_verify },
52 /* Raw RSA operations */
54 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
55 silc_rsa_get_private_key, silc_rsa_set_public_key,
56 silc_rsa_set_private_key, silc_rsa_context_len,
57 silc_rsa_encrypt, silc_rsa_decrypt,
58 silc_rsa_sign, silc_rsa_verify },
60 { NULL, NULL, NULL, NULL, NULL,
61 NULL, NULL, NULL, NULL, NULL, NULL }
64 /* Register a new PKCS into SILC. This is used at the initialization of
67 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
72 SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
74 new = silc_calloc(1, sizeof(*new));
75 new->name = strdup(pkcs->name);
76 new->init = pkcs->init;
77 new->clear_keys = pkcs->clear_keys;
78 new->get_public_key = pkcs->get_public_key;
79 new->get_private_key = pkcs->get_private_key;
80 new->set_public_key = pkcs->set_public_key;
81 new->set_private_key = pkcs->set_private_key;
82 new->context_len = pkcs->context_len;
83 new->encrypt = pkcs->encrypt;
84 new->decrypt = pkcs->decrypt;
85 new->sign = pkcs->sign;
86 new->verify = pkcs->verify;
89 if (silc_pkcs_list == NULL)
90 silc_pkcs_list = silc_dlist_init();
91 silc_dlist_add(silc_pkcs_list, new);
93 #endif /* SILC_EPOC */
97 /* Unregister a PKCS from the SILC. */
99 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
102 SilcPKCSObject *entry;
104 SILC_LOG_DEBUG(("Unregistering PKCS"));
109 silc_dlist_start(silc_pkcs_list);
110 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
111 if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
112 silc_dlist_del(silc_pkcs_list, entry);
113 silc_free(entry->name);
116 if (silc_dlist_count(silc_pkcs_list) == 0) {
117 silc_dlist_uninit(silc_pkcs_list);
118 silc_pkcs_list = NULL;
125 #endif /* SILC_EPOC */
129 /* Function that registers all the default PKCS (all builtin PKCS).
130 The application may use this to register the default PKCS if specific
131 PKCS in any specific order is not wanted. */
133 bool silc_pkcs_register_default(void)
138 for (i = 0; silc_default_pkcs[i].name; i++)
139 silc_pkcs_register(&(silc_default_pkcs[i]));
141 #endif /* SILC_EPOC */
145 bool silc_pkcs_unregister_all(void)
148 SilcPKCSObject *entry;
153 silc_dlist_start(silc_pkcs_list);
154 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
155 silc_pkcs_unregister(entry);
159 #endif /* SILC_EPOC */
163 /* Allocates a new SilcPKCS object. The new allocated object is returned
164 to the 'new_pkcs' argument. */
166 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
168 SilcPKCSObject *entry = NULL;
170 SILC_LOG_DEBUG(("Allocating new PKCS object"));
173 if (silc_pkcs_list) {
174 silc_dlist_start(silc_pkcs_list);
175 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
176 if (!strcmp(entry->name, name))
182 /* On EPOC which don't have globals we check our constant hash list. */
184 for (i = 0; silc_default_pkcs[i].name; i++) {
185 if (!strcmp(silc_default_pkcs[i].name, name)) {
186 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
191 #endif /* SILC_EPOC */
194 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
195 (*new_pkcs)->pkcs = entry;
196 (*new_pkcs)->context = silc_calloc(1, entry->context_len());
203 /* Free's the PKCS object */
205 void silc_pkcs_free(SilcPKCS pkcs)
208 pkcs->pkcs->clear_keys(pkcs->context);
209 silc_free(pkcs->context);
214 /* Return TRUE if PKCS algorithm `name' is supported. */
216 int silc_pkcs_is_supported(const unsigned char *name)
219 SilcPKCSObject *entry;
221 if (silc_pkcs_list) {
222 silc_dlist_start(silc_pkcs_list);
223 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
224 if (!strcmp(entry->name, name))
231 for (i = 0; silc_default_pkcs[i].name; i++)
232 if (!strcmp(silc_default_pkcs[i].name, name))
235 #endif /* SILC_EPOC */
239 /* Returns comma separated list of supported PKCS algorithms */
241 char *silc_pkcs_get_supported(void)
243 SilcPKCSObject *entry;
248 if (silc_pkcs_list) {
249 silc_dlist_start(silc_pkcs_list);
250 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
251 len += strlen(entry->name);
252 list = silc_realloc(list, len + 1);
254 memcpy(list + (len - strlen(entry->name)),
255 entry->name, strlen(entry->name));
256 memcpy(list + len, ",", 1);
263 for (i = 0; silc_default_pkcs[i].name; i++) {
264 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
265 len += strlen(entry->name);
266 list = silc_realloc(list, len + 1);
268 memcpy(list + (len - strlen(entry->name)),
269 entry->name, strlen(entry->name));
270 memcpy(list + len, ",", 1);
274 #endif /* SILC_EPOC */
281 /* Generate new key pair into the `pkcs' context. */
283 int silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
286 return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
289 /* Returns the length of the key */
291 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
293 return pkcs->key_len;
296 const char *silc_pkcs_get_name(SilcPKCS pkcs)
298 return pkcs->pkcs->name;
301 /* Returns SILC style public key */
303 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
305 return pkcs->pkcs->get_public_key(pkcs->context, len);
308 /* Returns SILC style private key */
310 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
312 return pkcs->pkcs->get_private_key(pkcs->context, len);
315 /* Sets public key from SilcPublicKey. */
317 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
319 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
321 return pkcs->key_len;
324 /* Sets public key from data. */
326 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
329 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
330 return pkcs->key_len;
333 /* Sets private key from SilcPrivateKey. */
335 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
337 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
338 private_key->prv_len);
341 /* Sets private key from data. */
343 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
346 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
351 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
352 unsigned char *dst, SilcUInt32 *dst_len)
354 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
359 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
360 unsigned char *dst, SilcUInt32 *dst_len)
362 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
365 /* Generates signature */
367 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
368 unsigned char *dst, SilcUInt32 *dst_len)
370 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
373 /* Verifies signature */
375 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
376 SilcUInt32 signature_len, unsigned char *data,
379 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
383 /* Generates signature with hash. The hash is signed. */
385 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
386 unsigned char *src, SilcUInt32 src_len,
387 unsigned char *dst, SilcUInt32 *dst_len)
389 unsigned char hashr[32];
393 silc_hash_make(hash, src, src_len, hashr);
394 hash_len = silc_hash_len(hash);
396 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
398 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
399 memset(hashr, 0, sizeof(hashr));
404 /* Verifies signature with hash. The `data' is hashed and verified against
407 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
408 unsigned char *signature,
409 SilcUInt32 signature_len,
413 unsigned char hashr[32];
417 silc_hash_make(hash, data, data_len, hashr);
418 hash_len = silc_hash_len(hash);
420 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
422 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
424 memset(hashr, 0, sizeof(hashr));
429 /* Encodes and returns SILC public key identifier. If some of the
430 arguments is NULL those are not encoded into the identifier string.
431 Protocol says that at least username and host must be provided. */
433 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
434 char *email, char *org, char *country)
438 SilcUInt32 len, tlen = 0;
440 if (!username || !host)
443 len = (username ? strlen(username) : 0) +
444 (host ? strlen(host) : 0) +
445 (realname ? strlen(realname) : 0) +
446 (email ? strlen(email) : 0) +
447 (org ? strlen(org) : 0) +
448 (country ? strlen(country) : 0);
453 len += 3 + 5 + 5 + 4 + 4 + 4;
454 buf = silc_buffer_alloc(len);
455 silc_buffer_pull_tail(buf, len);
458 silc_buffer_format(buf,
459 SILC_STR_UI32_STRING("UN="),
460 SILC_STR_UI32_STRING(username),
462 silc_buffer_pull(buf, 3 + strlen(username));
463 tlen = 3 + strlen(username);
467 silc_buffer_format(buf,
468 SILC_STR_UI32_STRING(", "),
469 SILC_STR_UI32_STRING("HN="),
470 SILC_STR_UI32_STRING(host),
472 silc_buffer_pull(buf, 5 + strlen(host));
473 tlen += 5 + strlen(host);
477 silc_buffer_format(buf,
478 SILC_STR_UI32_STRING(", "),
479 SILC_STR_UI32_STRING("RN="),
480 SILC_STR_UI32_STRING(realname),
482 silc_buffer_pull(buf, 5 + strlen(realname));
483 tlen += 5 + strlen(realname);
487 silc_buffer_format(buf,
488 SILC_STR_UI32_STRING(", "),
489 SILC_STR_UI32_STRING("E="),
490 SILC_STR_UI32_STRING(email),
492 silc_buffer_pull(buf, 4 + strlen(email));
493 tlen += 4 + strlen(email);
497 silc_buffer_format(buf,
498 SILC_STR_UI32_STRING(", "),
499 SILC_STR_UI32_STRING("O="),
500 SILC_STR_UI32_STRING(org),
502 silc_buffer_pull(buf, 4 + strlen(org));
503 tlen += 4 + strlen(org);
507 silc_buffer_format(buf,
508 SILC_STR_UI32_STRING(", "),
509 SILC_STR_UI32_STRING("C="),
510 SILC_STR_UI32_STRING(country),
512 silc_buffer_pull(buf, 4 + strlen(country));
513 tlen += 4 + strlen(country);
516 silc_buffer_push(buf, buf->data - buf->head);
517 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
518 memcpy(identifier, buf->data, tlen);
519 silc_buffer_free(buf);
524 /* Decodes the provided `identifier' and returns allocated context for
527 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
529 SilcPublicKeyIdentifier ident;
533 ident = silc_calloc(1, sizeof(*ident));
537 len = strcspn(cp, ",");
538 if (len - 1 >= 0 && cp[len - 1] == '\\') {
541 len = strcspn(cp, ",") + len;
542 if (len - 1 >= 0 && cp[len - 1] != '\\')
547 item = silc_calloc(len + 1, sizeof(char));
548 memcpy(item, cp, len);
550 if (strstr(item, "UN="))
551 ident->username = strdup(item + strcspn(cp, "=") + 1);
552 else if (strstr(item, "HN="))
553 ident->host = strdup(item + strcspn(cp, "=") + 1);
554 else if (strstr(item, "RN="))
555 ident->realname = strdup(item + strcspn(cp, "=") + 1);
556 else if (strstr(item, "E="))
557 ident->email = strdup(item + strcspn(cp, "=") + 1);
558 else if (strstr(item, "O="))
559 ident->org = strdup(item + strcspn(cp, "=") + 1);
560 else if (strstr(item, "C="))
561 ident->country = strdup(item + strcspn(cp, "=") + 1);
576 /* Free's decoded public key identifier context. Call this to free the
577 context returned by the silc_pkcs_decode_identifier. */
579 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
581 silc_free(identifier->username);
582 silc_free(identifier->host);
583 silc_free(identifier->realname);
584 silc_free(identifier->email);
585 silc_free(identifier->org);
586 silc_free(identifier->country);
587 silc_free(identifier);
590 /* Allocates SILC style public key formed from sent arguments. All data
593 SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
594 const char *identifier,
595 const unsigned char *pk,
598 SilcPublicKey public_key;
601 public_key = silc_calloc(1, sizeof(*public_key));
602 public_key->name = strdup(name);
603 public_key->pk_len = pk_len;
604 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
605 memcpy(public_key->pk, pk, pk_len);
607 if (!silc_utf8_valid(identifier, strlen(identifier))) {
608 int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
609 tmp = silc_calloc(len + 1, sizeof(*tmp));
610 silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
614 public_key->identifier = strdup(identifier);
615 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
621 /* Free's public key */
623 void silc_pkcs_public_key_free(SilcPublicKey public_key)
626 silc_free(public_key->name);
627 silc_free(public_key->identifier);
628 silc_free(public_key->pk);
629 silc_free(public_key);
633 /* Allocates SILC private key formed from sent arguments. All data is
636 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
637 const unsigned char *prv,
640 SilcPrivateKey private_key;
642 private_key = silc_calloc(1, sizeof(*private_key));
643 private_key->name = strdup(name);
644 private_key->prv_len = prv_len;
645 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
646 memcpy(private_key->prv, prv, prv_len);
651 /* Free's private key */
653 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
656 silc_free(private_key->name);
657 silc_free(private_key->prv);
658 silc_free(private_key);
662 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
666 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
671 buf = silc_buffer_alloc(public_key->len);
672 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
674 silc_buffer_format(buf,
675 SILC_STR_UI_INT(public_key->len),
676 SILC_STR_UI_SHORT(strlen(public_key->name)),
677 SILC_STR_UI32_STRING(public_key->name),
678 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
679 SILC_STR_UI32_STRING(public_key->identifier),
680 SILC_STR_UI_XNSTRING(public_key->pk,
684 *len = public_key->len;
686 ret = silc_calloc(buf->len, sizeof(*ret));
687 memcpy(ret, buf->data, buf->len);
688 silc_buffer_free(buf);
693 /* Encodes SILC style public key. Returns the encoded data. */
696 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
697 char *pkcs, char *identifier,
704 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
705 buf = silc_buffer_alloc(totlen);
706 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
708 silc_buffer_format(buf,
709 SILC_STR_UI_INT(totlen),
710 SILC_STR_UI_SHORT(strlen(pkcs)),
711 SILC_STR_UI32_STRING(pkcs),
712 SILC_STR_UI_SHORT(strlen(identifier)),
713 SILC_STR_UI32_STRING(identifier),
714 SILC_STR_UI_XNSTRING(pk, pk_len),
719 ret = silc_calloc(buf->len, sizeof(*ret));
720 memcpy(ret, buf->data, buf->len);
721 silc_buffer_free(buf);
726 /* Decodes SILC style public key. Returns TRUE if the decoding was
727 successful. Allocates new public key as well. */
729 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
730 SilcPublicKey *public_key)
734 SilcUInt16 pkcs_len, identifier_len;
735 SilcUInt32 totlen, key_len;
736 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
739 buf = silc_buffer_alloc(data_len);
740 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
741 silc_buffer_put(buf, data, data_len);
744 ret = silc_buffer_unformat(buf,
745 SILC_STR_UI_INT(&totlen),
748 silc_buffer_free(buf);
752 if (totlen != data_len) {
753 silc_buffer_free(buf);
757 /* Get algorithm name and identifier */
758 silc_buffer_pull(buf, 4);
760 silc_buffer_unformat(buf,
761 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
762 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
767 if (pkcs_len < 1 || identifier_len < 3 ||
768 pkcs_len + identifier_len > totlen)
771 /* See if we support this algorithm (check only if PKCS are registered) */
772 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
773 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
777 /* Protocol says that at least UN and HN must be provided as identifier,
779 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
780 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
785 /* Get key data. We assume that rest of the buffer is key data. */
786 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
788 ret = silc_buffer_unformat(buf,
789 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
794 /* Try to set the key. If this fails the key must be malformed. This
795 code assumes that the PKCS routine checks the format of the key.
796 (check only if PKCS are registered) */
797 if (SILC_PKCS_LIST) {
798 silc_pkcs_alloc(pkcs_name, &alg);
799 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
805 *public_key = silc_calloc(1, sizeof(**public_key));
806 (*public_key)->len = totlen;
807 (*public_key)->name = pkcs_name;
808 (*public_key)->identifier = ident;
809 (*public_key)->pk = key_data;
810 (*public_key)->pk_len = key_len;
813 silc_buffer_free(buf);
818 silc_free(pkcs_name);
823 silc_buffer_free(buf);
827 /* Compares two public keys and returns TRUE if they are same key, and
828 FALSE if they are not same. */
830 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
835 if (key1->len == key2->len &&
836 key1->name && key2->name && key1->identifier && key2->identifier &&
837 !strcmp(key1->name, key2->name) &&
838 !strcmp(key1->identifier, key2->identifier) &&
839 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
840 key1->pk_len == key2->pk_len)
846 /* Copies the public key indicated by `public_key' and returns new allocated
847 public key which is indentical to the `public_key'. */
849 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
851 SilcPublicKey key = silc_calloc(1, sizeof(*key));
855 key->len = public_key->len;
856 key->name = silc_memdup(public_key->name, strlen(public_key->name));
857 key->identifier = silc_memdup(public_key->identifier,
858 strlen(public_key->identifier));
859 key->pk = silc_memdup(public_key->pk, public_key->pk_len);
860 key->pk_len = public_key->pk_len;
865 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
868 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
874 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
875 buf = silc_buffer_alloc(totlen);
876 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
878 silc_buffer_format(buf,
879 SILC_STR_UI_SHORT(strlen(private_key->name)),
880 SILC_STR_UI32_STRING(private_key->name),
881 SILC_STR_UI_XNSTRING(private_key->prv,
882 private_key->prv_len),
887 ret = silc_calloc(buf->len, sizeof(*ret));
888 memcpy(ret, buf->data, buf->len);
889 silc_buffer_free(buf);
894 /* Encodes SILC private key. Returns the encoded data. */
897 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
898 char *pkcs, SilcUInt32 *len)
904 totlen = 2 + strlen(pkcs) + prv_len;
905 buf = silc_buffer_alloc(totlen);
906 silc_buffer_pull_tail(buf, totlen);
908 silc_buffer_format(buf,
909 SILC_STR_UI_SHORT(strlen(pkcs)),
910 SILC_STR_UI32_STRING(pkcs),
911 SILC_STR_UI_XNSTRING(prv, prv_len),
916 ret = silc_calloc(buf->len, sizeof(*ret));
917 memcpy(ret, buf->data, buf->len);
918 silc_buffer_free(buf);
923 /* Decodes SILC style public key. Returns TRUE if the decoding was
924 successful. Allocates new private key as well. */
926 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
927 SilcPrivateKey *private_key)
933 unsigned char *pkcs_name = NULL, *key_data = NULL;
936 buf = silc_buffer_alloc(data_len);
937 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
938 silc_buffer_put(buf, data, data_len);
940 /* Get algorithm name and identifier */
942 silc_buffer_unformat(buf,
943 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
948 if (pkcs_len < 1 || pkcs_len > buf->truelen)
951 /* See if we support this algorithm (check only if PKCS are registered). */
952 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
953 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
957 /* Get key data. We assume that rest of the buffer is key data. */
958 silc_buffer_pull(buf, 2 + pkcs_len);
960 ret = silc_buffer_unformat(buf,
961 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
966 /* Try to set the key. If this fails the key must be malformed. This
967 code assumes that the PKCS routine checks the format of the key.
968 (check only if PKCS are registered) */
969 if (SILC_PKCS_LIST) {
970 silc_pkcs_alloc(pkcs_name, &alg);
971 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
977 *private_key = silc_calloc(1, sizeof(**private_key));
978 (*private_key)->name = pkcs_name;
979 (*private_key)->prv = key_data;
980 (*private_key)->prv_len = key_len;
983 silc_buffer_free(buf);
988 silc_free(pkcs_name);
991 silc_buffer_free(buf);
995 /* Internal routine to save public key */
997 static int silc_pkcs_save_public_key_internal(char *filename,
1000 SilcUInt32 encoding)
1006 case SILC_PKCS_FILE_BIN:
1008 case SILC_PKCS_FILE_PEM:
1009 data = silc_pem_encode_file(data, data_len);
1010 data_len = strlen(data);
1014 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1015 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1016 buf = silc_buffer_alloc(len);
1017 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1019 silc_buffer_format(buf,
1020 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1021 SILC_STR_UI_XNSTRING(data, data_len),
1022 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1025 /* Save into file */
1026 if (silc_file_writefile(filename, buf->data, buf->len)) {
1027 silc_buffer_free(buf);
1031 silc_buffer_free(buf);
1035 /* Saves public key into file */
1037 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1038 SilcUInt32 encoding)
1040 unsigned char *data;
1041 SilcUInt32 data_len;
1043 data = silc_pkcs_public_key_encode(public_key, &data_len);
1044 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1048 /* Saves public key into file */
1050 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1051 SilcUInt32 data_len,
1052 SilcUInt32 encoding)
1054 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1058 /* Internal routine to save private key. */
1060 static int silc_pkcs_save_private_key_internal(char *filename,
1061 unsigned char *data,
1062 SilcUInt32 data_len,
1063 SilcUInt32 encoding)
1069 case SILC_PKCS_FILE_BIN:
1071 case SILC_PKCS_FILE_PEM:
1072 data = silc_pem_encode_file(data, data_len);
1073 data_len = strlen(data);
1077 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1078 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1079 buf = silc_buffer_alloc(len);
1080 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1082 silc_buffer_format(buf,
1083 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1084 SILC_STR_UI_XNSTRING(data, data_len),
1085 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1088 /* Save into a file */
1089 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1090 silc_buffer_free(buf);
1094 silc_buffer_free(buf);
1098 /* Saves private key into file. */
1099 /* XXX The buffer should be encrypted if passphrase is provided. */
1101 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1102 unsigned char *passphrase,
1103 SilcUInt32 encoding)
1105 unsigned char *data;
1106 SilcUInt32 data_len;
1108 data = silc_pkcs_private_key_encode(private_key, &data_len);
1109 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1113 /* Saves private key into file. */
1114 /* XXX The buffer should be encrypted if passphrase is provided. */
1116 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1117 SilcUInt32 data_len,
1118 unsigned char *passphrase,
1119 SilcUInt32 encoding)
1121 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1125 /* Loads public key from file and allocates new public key. Returns TRUE
1126 is loading was successful. */
1128 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1129 SilcUInt32 encoding)
1131 unsigned char *cp, *old, *data, byte;
1132 SilcUInt32 i, data_len, len;
1134 old = data = silc_file_readfile(filename, &data_len);
1138 /* Check start of file and remove header from the data. */
1139 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1141 for (i = 0; i < len; i++) {
1144 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1145 memset(old, 0, data_len);
1152 /* Decode public key */
1154 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1155 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1158 case SILC_PKCS_FILE_BIN:
1160 case SILC_PKCS_FILE_PEM:
1161 data = silc_pem_decode(data, len, &len);
1162 memset(old, 0, data_len);
1169 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1170 memset(old, 0, data_len);
1176 memset(old, 0, data_len);
1181 /* Load private key from file and allocates new private key. Returns TRUE
1182 if loading was successful. */
1183 /* XXX Should support encrypted private key files */
1185 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1186 SilcUInt32 encoding)
1188 unsigned char *cp, *old, *data, byte;
1189 SilcUInt32 i, data_len, len;
1191 old = data = silc_file_readfile(filename, &data_len);
1195 /* Check start of file and remove header from the data. */
1196 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1198 for (i = 0; i < len; i++) {
1201 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1202 memset(old, 0, data_len);
1209 /* Decode private key */
1211 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1212 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1215 case SILC_PKCS_FILE_BIN:
1217 case SILC_PKCS_FILE_PEM:
1218 data = silc_pem_decode(data, len, &len);
1222 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1223 memset(old, 0, data_len);
1229 memset(old, 0, data_len);