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 /* Check if exists already */
76 SilcPKCSObject *entry;
77 silc_dlist_start(silc_pkcs_list);
78 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
79 if (!strcmp(entry->name, pkcs->name))
84 new = silc_calloc(1, sizeof(*new));
85 new->name = strdup(pkcs->name);
86 new->init = pkcs->init;
87 new->clear_keys = pkcs->clear_keys;
88 new->get_public_key = pkcs->get_public_key;
89 new->get_private_key = pkcs->get_private_key;
90 new->set_public_key = pkcs->set_public_key;
91 new->set_private_key = pkcs->set_private_key;
92 new->context_len = pkcs->context_len;
93 new->encrypt = pkcs->encrypt;
94 new->decrypt = pkcs->decrypt;
95 new->sign = pkcs->sign;
96 new->verify = pkcs->verify;
99 if (silc_pkcs_list == NULL)
100 silc_pkcs_list = silc_dlist_init();
101 silc_dlist_add(silc_pkcs_list, new);
103 #endif /* SILC_EPOC */
107 /* Unregister a PKCS from the SILC. */
109 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
112 SilcPKCSObject *entry;
114 SILC_LOG_DEBUG(("Unregistering PKCS"));
119 silc_dlist_start(silc_pkcs_list);
120 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
121 if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
122 silc_dlist_del(silc_pkcs_list, entry);
123 silc_free(entry->name);
126 if (silc_dlist_count(silc_pkcs_list) == 0) {
127 silc_dlist_uninit(silc_pkcs_list);
128 silc_pkcs_list = NULL;
135 #endif /* SILC_EPOC */
139 /* Function that registers all the default PKCS (all builtin PKCS).
140 The application may use this to register the default PKCS if specific
141 PKCS in any specific order is not wanted. */
143 bool silc_pkcs_register_default(void)
148 for (i = 0; silc_default_pkcs[i].name; i++)
149 silc_pkcs_register(&(silc_default_pkcs[i]));
151 #endif /* SILC_EPOC */
155 bool silc_pkcs_unregister_all(void)
158 SilcPKCSObject *entry;
163 silc_dlist_start(silc_pkcs_list);
164 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
165 silc_pkcs_unregister(entry);
169 #endif /* SILC_EPOC */
173 /* Allocates a new SilcPKCS object. The new allocated object is returned
174 to the 'new_pkcs' argument. */
176 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
178 SilcPKCSObject *entry = NULL;
180 SILC_LOG_DEBUG(("Allocating new PKCS object"));
183 if (silc_pkcs_list) {
184 silc_dlist_start(silc_pkcs_list);
185 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
186 if (!strcmp(entry->name, name))
192 /* On EPOC which don't have globals we check our constant hash list. */
194 for (i = 0; silc_default_pkcs[i].name; i++) {
195 if (!strcmp(silc_default_pkcs[i].name, name)) {
196 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
201 #endif /* SILC_EPOC */
204 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
205 (*new_pkcs)->pkcs = entry;
206 (*new_pkcs)->context = silc_calloc(1, entry->context_len());
213 /* Free's the PKCS object */
215 void silc_pkcs_free(SilcPKCS pkcs)
218 pkcs->pkcs->clear_keys(pkcs->context);
219 silc_free(pkcs->context);
224 /* Return TRUE if PKCS algorithm `name' is supported. */
226 int silc_pkcs_is_supported(const unsigned char *name)
229 SilcPKCSObject *entry;
231 if (silc_pkcs_list) {
232 silc_dlist_start(silc_pkcs_list);
233 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
234 if (!strcmp(entry->name, name))
241 for (i = 0; silc_default_pkcs[i].name; i++)
242 if (!strcmp(silc_default_pkcs[i].name, name))
245 #endif /* SILC_EPOC */
249 /* Returns comma separated list of supported PKCS algorithms */
251 char *silc_pkcs_get_supported(void)
253 SilcPKCSObject *entry;
258 if (silc_pkcs_list) {
259 silc_dlist_start(silc_pkcs_list);
260 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
261 len += strlen(entry->name);
262 list = silc_realloc(list, len + 1);
264 memcpy(list + (len - strlen(entry->name)),
265 entry->name, strlen(entry->name));
266 memcpy(list + len, ",", 1);
273 for (i = 0; silc_default_pkcs[i].name; i++) {
274 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
275 len += strlen(entry->name);
276 list = silc_realloc(list, len + 1);
278 memcpy(list + (len - strlen(entry->name)),
279 entry->name, strlen(entry->name));
280 memcpy(list + len, ",", 1);
284 #endif /* SILC_EPOC */
291 /* Generate new key pair into the `pkcs' context. */
293 int silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
296 return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
299 /* Returns the length of the key */
301 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
303 return pkcs->key_len;
306 const char *silc_pkcs_get_name(SilcPKCS pkcs)
308 return pkcs->pkcs->name;
311 /* Returns SILC style public key */
313 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
315 return pkcs->pkcs->get_public_key(pkcs->context, len);
318 /* Returns SILC style private key */
320 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
322 return pkcs->pkcs->get_private_key(pkcs->context, len);
325 /* Sets public key from SilcPublicKey. */
327 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
329 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
331 return pkcs->key_len;
334 /* Sets public key from data. */
336 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
339 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
340 return pkcs->key_len;
343 /* Sets private key from SilcPrivateKey. */
345 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
347 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
348 private_key->prv_len);
351 /* Sets private key from data. */
353 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
356 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
361 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
362 unsigned char *dst, SilcUInt32 *dst_len)
364 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
369 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
370 unsigned char *dst, SilcUInt32 *dst_len)
372 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
375 /* Generates signature */
377 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
378 unsigned char *dst, SilcUInt32 *dst_len)
380 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
383 /* Verifies signature */
385 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
386 SilcUInt32 signature_len, unsigned char *data,
389 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
393 /* Generates signature with hash. The hash is signed. */
395 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
396 unsigned char *src, SilcUInt32 src_len,
397 unsigned char *dst, SilcUInt32 *dst_len)
399 unsigned char hashr[32];
403 silc_hash_make(hash, src, src_len, hashr);
404 hash_len = silc_hash_len(hash);
406 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
408 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
409 memset(hashr, 0, sizeof(hashr));
414 /* Verifies signature with hash. The `data' is hashed and verified against
417 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
418 unsigned char *signature,
419 SilcUInt32 signature_len,
423 unsigned char hashr[32];
427 silc_hash_make(hash, data, data_len, hashr);
428 hash_len = silc_hash_len(hash);
430 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
432 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
434 memset(hashr, 0, sizeof(hashr));
439 /* Encodes and returns SILC public key identifier. If some of the
440 arguments is NULL those are not encoded into the identifier string.
441 Protocol says that at least username and host must be provided. */
443 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
444 char *email, char *org, char *country)
448 SilcUInt32 len, tlen = 0;
450 if (!username || !host)
453 len = (username ? strlen(username) : 0) +
454 (host ? strlen(host) : 0) +
455 (realname ? strlen(realname) : 0) +
456 (email ? strlen(email) : 0) +
457 (org ? strlen(org) : 0) +
458 (country ? strlen(country) : 0);
463 len += 3 + 5 + 5 + 4 + 4 + 4;
464 buf = silc_buffer_alloc(len);
465 silc_buffer_pull_tail(buf, len);
468 silc_buffer_format(buf,
469 SILC_STR_UI32_STRING("UN="),
470 SILC_STR_UI32_STRING(username),
472 silc_buffer_pull(buf, 3 + strlen(username));
473 tlen = 3 + strlen(username);
477 silc_buffer_format(buf,
478 SILC_STR_UI32_STRING(", "),
479 SILC_STR_UI32_STRING("HN="),
480 SILC_STR_UI32_STRING(host),
482 silc_buffer_pull(buf, 5 + strlen(host));
483 tlen += 5 + strlen(host);
487 silc_buffer_format(buf,
488 SILC_STR_UI32_STRING(", "),
489 SILC_STR_UI32_STRING("RN="),
490 SILC_STR_UI32_STRING(realname),
492 silc_buffer_pull(buf, 5 + strlen(realname));
493 tlen += 5 + strlen(realname);
497 silc_buffer_format(buf,
498 SILC_STR_UI32_STRING(", "),
499 SILC_STR_UI32_STRING("E="),
500 SILC_STR_UI32_STRING(email),
502 silc_buffer_pull(buf, 4 + strlen(email));
503 tlen += 4 + strlen(email);
507 silc_buffer_format(buf,
508 SILC_STR_UI32_STRING(", "),
509 SILC_STR_UI32_STRING("O="),
510 SILC_STR_UI32_STRING(org),
512 silc_buffer_pull(buf, 4 + strlen(org));
513 tlen += 4 + strlen(org);
517 silc_buffer_format(buf,
518 SILC_STR_UI32_STRING(", "),
519 SILC_STR_UI32_STRING("C="),
520 SILC_STR_UI32_STRING(country),
522 silc_buffer_pull(buf, 4 + strlen(country));
523 tlen += 4 + strlen(country);
526 silc_buffer_push(buf, buf->data - buf->head);
527 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
528 memcpy(identifier, buf->data, tlen);
529 silc_buffer_free(buf);
534 /* Decodes the provided `identifier' and returns allocated context for
537 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
539 SilcPublicKeyIdentifier ident;
543 ident = silc_calloc(1, sizeof(*ident));
547 len = strcspn(cp, ",");
548 if (len - 1 >= 0 && cp[len - 1] == '\\') {
551 len = strcspn(cp, ",") + len;
552 if (len - 1 >= 0 && cp[len - 1] != '\\')
557 item = silc_calloc(len + 1, sizeof(char));
558 memcpy(item, cp, len);
560 if (strstr(item, "UN="))
561 ident->username = strdup(item + strcspn(cp, "=") + 1);
562 else if (strstr(item, "HN="))
563 ident->host = strdup(item + strcspn(cp, "=") + 1);
564 else if (strstr(item, "RN="))
565 ident->realname = strdup(item + strcspn(cp, "=") + 1);
566 else if (strstr(item, "E="))
567 ident->email = strdup(item + strcspn(cp, "=") + 1);
568 else if (strstr(item, "O="))
569 ident->org = strdup(item + strcspn(cp, "=") + 1);
570 else if (strstr(item, "C="))
571 ident->country = strdup(item + strcspn(cp, "=") + 1);
586 /* Free's decoded public key identifier context. Call this to free the
587 context returned by the silc_pkcs_decode_identifier. */
589 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
591 silc_free(identifier->username);
592 silc_free(identifier->host);
593 silc_free(identifier->realname);
594 silc_free(identifier->email);
595 silc_free(identifier->org);
596 silc_free(identifier->country);
597 silc_free(identifier);
600 /* Allocates SILC style public key formed from sent arguments. All data
603 SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
604 const char *identifier,
605 const unsigned char *pk,
608 SilcPublicKey public_key;
611 public_key = silc_calloc(1, sizeof(*public_key));
612 public_key->name = strdup(name);
613 public_key->pk_len = pk_len;
614 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
615 memcpy(public_key->pk, pk, pk_len);
617 if (!silc_utf8_valid(identifier, strlen(identifier))) {
618 int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
619 tmp = silc_calloc(len + 1, sizeof(*tmp));
620 silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
624 public_key->identifier = strdup(identifier);
625 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
631 /* Free's public key */
633 void silc_pkcs_public_key_free(SilcPublicKey public_key)
636 silc_free(public_key->name);
637 silc_free(public_key->identifier);
638 silc_free(public_key->pk);
639 silc_free(public_key);
643 /* Allocates SILC private key formed from sent arguments. All data is
646 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
647 const unsigned char *prv,
650 SilcPrivateKey private_key;
652 private_key = silc_calloc(1, sizeof(*private_key));
653 private_key->name = strdup(name);
654 private_key->prv_len = prv_len;
655 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
656 memcpy(private_key->prv, prv, prv_len);
661 /* Free's private key */
663 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
666 silc_free(private_key->name);
667 silc_free(private_key->prv);
668 silc_free(private_key);
672 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
676 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
681 buf = silc_buffer_alloc(public_key->len);
682 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
684 silc_buffer_format(buf,
685 SILC_STR_UI_INT(public_key->len),
686 SILC_STR_UI_SHORT(strlen(public_key->name)),
687 SILC_STR_UI32_STRING(public_key->name),
688 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
689 SILC_STR_UI32_STRING(public_key->identifier),
690 SILC_STR_UI_XNSTRING(public_key->pk,
694 *len = public_key->len;
696 ret = silc_calloc(buf->len, sizeof(*ret));
697 memcpy(ret, buf->data, buf->len);
698 silc_buffer_free(buf);
703 /* Encodes SILC style public key. Returns the encoded data. */
706 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
707 char *pkcs, char *identifier,
714 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
715 buf = silc_buffer_alloc(totlen);
716 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
718 silc_buffer_format(buf,
719 SILC_STR_UI_INT(totlen),
720 SILC_STR_UI_SHORT(strlen(pkcs)),
721 SILC_STR_UI32_STRING(pkcs),
722 SILC_STR_UI_SHORT(strlen(identifier)),
723 SILC_STR_UI32_STRING(identifier),
724 SILC_STR_UI_XNSTRING(pk, pk_len),
729 ret = silc_calloc(buf->len, sizeof(*ret));
730 memcpy(ret, buf->data, buf->len);
731 silc_buffer_free(buf);
736 /* Decodes SILC style public key. Returns TRUE if the decoding was
737 successful. Allocates new public key as well. */
739 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
740 SilcPublicKey *public_key)
744 SilcUInt16 pkcs_len, identifier_len;
745 SilcUInt32 totlen, key_len;
746 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
749 buf = silc_buffer_alloc(data_len);
750 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
751 silc_buffer_put(buf, data, data_len);
754 ret = silc_buffer_unformat(buf,
755 SILC_STR_UI_INT(&totlen),
758 silc_buffer_free(buf);
762 if (totlen != data_len) {
763 silc_buffer_free(buf);
767 /* Get algorithm name and identifier */
768 silc_buffer_pull(buf, 4);
770 silc_buffer_unformat(buf,
771 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
772 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
777 if (pkcs_len < 1 || identifier_len < 3 ||
778 pkcs_len + identifier_len > totlen)
781 /* See if we support this algorithm (check only if PKCS are registered) */
782 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
783 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
787 /* Protocol says that at least UN and HN must be provided as identifier,
789 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
790 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
795 /* Get key data. We assume that rest of the buffer is key data. */
796 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
798 ret = silc_buffer_unformat(buf,
799 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
804 /* Try to set the key. If this fails the key must be malformed. This
805 code assumes that the PKCS routine checks the format of the key.
806 (check only if PKCS are registered) */
807 if (SILC_PKCS_LIST) {
808 silc_pkcs_alloc(pkcs_name, &alg);
809 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
815 *public_key = silc_calloc(1, sizeof(**public_key));
816 (*public_key)->len = totlen;
817 (*public_key)->name = pkcs_name;
818 (*public_key)->identifier = ident;
819 (*public_key)->pk = key_data;
820 (*public_key)->pk_len = key_len;
823 silc_buffer_free(buf);
828 silc_free(pkcs_name);
833 silc_buffer_free(buf);
837 /* Compares two public keys and returns TRUE if they are same key, and
838 FALSE if they are not same. */
840 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
845 if (key1->len == key2->len &&
846 key1->name && key2->name && key1->identifier && key2->identifier &&
847 !strcmp(key1->name, key2->name) &&
848 !strcmp(key1->identifier, key2->identifier) &&
849 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
850 key1->pk_len == key2->pk_len)
856 /* Copies the public key indicated by `public_key' and returns new allocated
857 public key which is indentical to the `public_key'. */
859 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
861 SilcPublicKey key = silc_calloc(1, sizeof(*key));
865 key->len = public_key->len;
866 key->name = silc_memdup(public_key->name, strlen(public_key->name));
867 key->identifier = silc_memdup(public_key->identifier,
868 strlen(public_key->identifier));
869 key->pk = silc_memdup(public_key->pk, public_key->pk_len);
870 key->pk_len = public_key->pk_len;
875 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
878 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
884 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
885 buf = silc_buffer_alloc(totlen);
886 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
888 silc_buffer_format(buf,
889 SILC_STR_UI_SHORT(strlen(private_key->name)),
890 SILC_STR_UI32_STRING(private_key->name),
891 SILC_STR_UI_XNSTRING(private_key->prv,
892 private_key->prv_len),
897 ret = silc_calloc(buf->len, sizeof(*ret));
898 memcpy(ret, buf->data, buf->len);
899 silc_buffer_free(buf);
904 /* Encodes SILC private key. Returns the encoded data. */
907 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
908 char *pkcs, SilcUInt32 *len)
914 totlen = 2 + strlen(pkcs) + prv_len;
915 buf = silc_buffer_alloc(totlen);
916 silc_buffer_pull_tail(buf, totlen);
918 silc_buffer_format(buf,
919 SILC_STR_UI_SHORT(strlen(pkcs)),
920 SILC_STR_UI32_STRING(pkcs),
921 SILC_STR_UI_XNSTRING(prv, prv_len),
926 ret = silc_calloc(buf->len, sizeof(*ret));
927 memcpy(ret, buf->data, buf->len);
928 silc_buffer_free(buf);
933 /* Decodes SILC style public key. Returns TRUE if the decoding was
934 successful. Allocates new private key as well. */
936 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
937 SilcPrivateKey *private_key)
943 unsigned char *pkcs_name = NULL, *key_data = NULL;
946 buf = silc_buffer_alloc(data_len);
947 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
948 silc_buffer_put(buf, data, data_len);
950 /* Get algorithm name and identifier */
952 silc_buffer_unformat(buf,
953 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
958 if (pkcs_len < 1 || pkcs_len > buf->truelen)
961 /* See if we support this algorithm (check only if PKCS are registered). */
962 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
963 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
967 /* Get key data. We assume that rest of the buffer is key data. */
968 silc_buffer_pull(buf, 2 + pkcs_len);
970 ret = silc_buffer_unformat(buf,
971 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
976 /* Try to set the key. If this fails the key must be malformed. This
977 code assumes that the PKCS routine checks the format of the key.
978 (check only if PKCS are registered) */
979 if (SILC_PKCS_LIST) {
980 silc_pkcs_alloc(pkcs_name, &alg);
981 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
987 *private_key = silc_calloc(1, sizeof(**private_key));
988 (*private_key)->name = pkcs_name;
989 (*private_key)->prv = key_data;
990 (*private_key)->prv_len = key_len;
993 silc_buffer_free(buf);
998 silc_free(pkcs_name);
1000 silc_free(key_data);
1001 silc_buffer_free(buf);
1005 /* Internal routine to save public key */
1007 static int silc_pkcs_save_public_key_internal(char *filename,
1008 unsigned char *data,
1009 SilcUInt32 data_len,
1010 SilcUInt32 encoding)
1016 case SILC_PKCS_FILE_BIN:
1018 case SILC_PKCS_FILE_PEM:
1019 data = silc_pem_encode_file(data, data_len);
1020 data_len = strlen(data);
1024 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1025 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1026 buf = silc_buffer_alloc(len);
1027 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1029 silc_buffer_format(buf,
1030 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1031 SILC_STR_UI_XNSTRING(data, data_len),
1032 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1035 /* Save into file */
1036 if (silc_file_writefile(filename, buf->data, buf->len)) {
1037 silc_buffer_free(buf);
1041 silc_buffer_free(buf);
1045 /* Saves public key into file */
1047 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1048 SilcUInt32 encoding)
1050 unsigned char *data;
1051 SilcUInt32 data_len;
1053 data = silc_pkcs_public_key_encode(public_key, &data_len);
1054 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1058 /* Saves public key into file */
1060 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1061 SilcUInt32 data_len,
1062 SilcUInt32 encoding)
1064 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1068 /* Internal routine to save private key. */
1070 static int silc_pkcs_save_private_key_internal(char *filename,
1071 unsigned char *data,
1072 SilcUInt32 data_len,
1073 SilcUInt32 encoding)
1079 case SILC_PKCS_FILE_BIN:
1081 case SILC_PKCS_FILE_PEM:
1082 data = silc_pem_encode_file(data, data_len);
1083 data_len = strlen(data);
1087 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1088 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1089 buf = silc_buffer_alloc(len);
1090 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1092 silc_buffer_format(buf,
1093 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1094 SILC_STR_UI_XNSTRING(data, data_len),
1095 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1098 /* Save into a file */
1099 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1100 silc_buffer_free(buf);
1104 silc_buffer_free(buf);
1108 /* Saves private key into file. */
1109 /* XXX The buffer should be encrypted if passphrase is provided. */
1111 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1112 unsigned char *passphrase,
1113 SilcUInt32 encoding)
1115 unsigned char *data;
1116 SilcUInt32 data_len;
1118 data = silc_pkcs_private_key_encode(private_key, &data_len);
1119 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1123 /* Saves private key into file. */
1124 /* XXX The buffer should be encrypted if passphrase is provided. */
1126 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1127 SilcUInt32 data_len,
1128 unsigned char *passphrase,
1129 SilcUInt32 encoding)
1131 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1135 /* Loads public key from file and allocates new public key. Returns TRUE
1136 is loading was successful. */
1138 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1139 SilcUInt32 encoding)
1141 unsigned char *cp, *old, *data, byte;
1142 SilcUInt32 i, data_len, len;
1144 old = data = silc_file_readfile(filename, &data_len);
1148 /* Check start of file and remove header from the data. */
1149 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1151 for (i = 0; i < len; i++) {
1154 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1155 memset(old, 0, data_len);
1162 /* Decode public key */
1164 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1165 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1168 case SILC_PKCS_FILE_BIN:
1170 case SILC_PKCS_FILE_PEM:
1171 data = silc_pem_decode(data, len, &len);
1172 memset(old, 0, data_len);
1179 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1180 memset(old, 0, data_len);
1186 memset(old, 0, data_len);
1191 /* Load private key from file and allocates new private key. Returns TRUE
1192 if loading was successful. */
1193 /* XXX Should support encrypted private key files */
1195 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1196 SilcUInt32 encoding)
1198 unsigned char *cp, *old, *data, byte;
1199 SilcUInt32 i, data_len, len;
1201 old = data = silc_file_readfile(filename, &data_len);
1205 /* Check start of file and remove header from the data. */
1206 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1208 for (i = 0; i < len; i++) {
1211 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1212 memset(old, 0, data_len);
1219 /* Decode private key */
1221 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1222 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1225 case SILC_PKCS_FILE_BIN:
1227 case SILC_PKCS_FILE_PEM:
1228 data = silc_pem_decode(data, len, &len);
1232 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1233 memset(old, 0, data_len);
1239 memset(old, 0, data_len);