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;
570 public_key = silc_calloc(1, sizeof(*public_key));
571 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
572 public_key->name = strdup(name);
573 public_key->pk_len = pk_len;
574 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
575 memcpy(public_key->pk, pk, pk_len);
577 if (!silc_utf8_valid(identifier, strlen(identifier))) {
578 int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
579 tmp = silc_calloc(len + 1, sizeof(*tmp));
580 silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
584 public_key->identifier = strdup(identifier);
589 /* Free's public key */
591 void silc_pkcs_public_key_free(SilcPublicKey public_key)
594 silc_free(public_key->name);
595 silc_free(public_key->identifier);
596 silc_free(public_key->pk);
597 silc_free(public_key);
601 /* Allocates SILC private key formed from sent arguments. All data is
604 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
607 SilcPrivateKey private_key;
609 private_key = silc_calloc(1, sizeof(*private_key));
610 private_key->name = strdup(name);
611 private_key->prv_len = prv_len;
612 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
613 memcpy(private_key->prv, prv, prv_len);
618 /* Free's private key */
620 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
623 silc_free(private_key->name);
624 silc_free(private_key->prv);
625 silc_free(private_key);
629 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
633 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
638 buf = silc_buffer_alloc(public_key->len);
639 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
641 silc_buffer_format(buf,
642 SILC_STR_UI_INT(public_key->len),
643 SILC_STR_UI_SHORT(strlen(public_key->name)),
644 SILC_STR_UI32_STRING(public_key->name),
645 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
646 SILC_STR_UI32_STRING(public_key->identifier),
647 SILC_STR_UI_XNSTRING(public_key->pk,
651 *len = public_key->len;
653 ret = silc_calloc(buf->len, sizeof(*ret));
654 memcpy(ret, buf->data, buf->len);
655 silc_buffer_free(buf);
660 /* Encodes SILC style public key. Returns the encoded data. */
663 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
664 char *pkcs, char *identifier,
671 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
672 buf = silc_buffer_alloc(totlen);
673 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
675 silc_buffer_format(buf,
676 SILC_STR_UI_INT(totlen),
677 SILC_STR_UI_SHORT(strlen(pkcs)),
678 SILC_STR_UI32_STRING(pkcs),
679 SILC_STR_UI_SHORT(strlen(identifier)),
680 SILC_STR_UI32_STRING(identifier),
681 SILC_STR_UI_XNSTRING(pk, pk_len),
686 ret = silc_calloc(buf->len, sizeof(*ret));
687 memcpy(ret, buf->data, buf->len);
688 silc_buffer_free(buf);
693 /* Decodes SILC style public key. Returns TRUE if the decoding was
694 successful. Allocates new public key as well. */
696 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
697 SilcPublicKey *public_key)
701 SilcUInt16 pkcs_len, identifier_len;
702 SilcUInt32 totlen, key_len;
703 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
706 buf = silc_buffer_alloc(data_len);
707 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
708 silc_buffer_put(buf, data, data_len);
711 ret = silc_buffer_unformat(buf,
712 SILC_STR_UI_INT(&totlen),
715 silc_buffer_free(buf);
719 if (totlen != data_len) {
720 silc_buffer_free(buf);
724 /* Get algorithm name and identifier */
725 silc_buffer_pull(buf, 4);
727 silc_buffer_unformat(buf,
728 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
729 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
734 if (pkcs_len < 1 || identifier_len < 3 ||
735 pkcs_len + identifier_len > totlen)
738 /* See if we support this algorithm (check only if PKCS are registered) */
739 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
740 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
744 /* Protocol says that at least UN and HN must be provided as identifier,
746 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
747 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
752 /* Get key data. We assume that rest of the buffer is key data. */
753 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
755 ret = silc_buffer_unformat(buf,
756 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
761 /* Try to set the key. If this fails the key must be malformed. This
762 code assumes that the PKCS routine checks the format of the key.
763 (check only if PKCS are registered) */
764 if (SILC_PKCS_LIST) {
765 silc_pkcs_alloc(pkcs_name, &alg);
766 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
772 *public_key = silc_calloc(1, sizeof(**public_key));
773 (*public_key)->len = totlen;
774 (*public_key)->name = pkcs_name;
775 (*public_key)->identifier = ident;
776 (*public_key)->pk = key_data;
777 (*public_key)->pk_len = key_len;
780 silc_buffer_free(buf);
785 silc_free(pkcs_name);
790 silc_buffer_free(buf);
794 /* Compares two public keys and returns TRUE if they are same key, and
795 FALSE if they are not same. */
797 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
802 if (key1->len == key2->len &&
803 key1->name && key2->name && key1->identifier && key2->identifier &&
804 !strcmp(key1->name, key2->name) &&
805 !strcmp(key1->identifier, key2->identifier) &&
806 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
807 key1->pk_len == key2->pk_len)
813 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
816 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
822 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
823 buf = silc_buffer_alloc(totlen);
824 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
826 silc_buffer_format(buf,
827 SILC_STR_UI_SHORT(strlen(private_key->name)),
828 SILC_STR_UI32_STRING(private_key->name),
829 SILC_STR_UI_XNSTRING(private_key->prv,
830 private_key->prv_len),
835 ret = silc_calloc(buf->len, sizeof(*ret));
836 memcpy(ret, buf->data, buf->len);
837 silc_buffer_free(buf);
842 /* Encodes SILC private key. Returns the encoded data. */
845 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
846 char *pkcs, SilcUInt32 *len)
852 totlen = 2 + strlen(pkcs) + prv_len;
853 buf = silc_buffer_alloc(totlen);
854 silc_buffer_pull_tail(buf, totlen);
856 silc_buffer_format(buf,
857 SILC_STR_UI_SHORT(strlen(pkcs)),
858 SILC_STR_UI32_STRING(pkcs),
859 SILC_STR_UI_XNSTRING(prv, prv_len),
864 ret = silc_calloc(buf->len, sizeof(*ret));
865 memcpy(ret, buf->data, buf->len);
866 silc_buffer_free(buf);
871 /* Decodes SILC style public key. Returns TRUE if the decoding was
872 successful. Allocates new private key as well. */
874 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
875 SilcPrivateKey *private_key)
881 unsigned char *pkcs_name = NULL, *key_data = NULL;
884 buf = silc_buffer_alloc(data_len);
885 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
886 silc_buffer_put(buf, data, data_len);
888 /* Get algorithm name and identifier */
890 silc_buffer_unformat(buf,
891 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
896 if (pkcs_len < 1 || pkcs_len > buf->truelen)
899 /* See if we support this algorithm (check only if PKCS are registered). */
900 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
901 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
905 /* Get key data. We assume that rest of the buffer is key data. */
906 silc_buffer_pull(buf, 2 + pkcs_len);
908 ret = silc_buffer_unformat(buf,
909 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
914 /* Try to set the key. If this fails the key must be malformed. This
915 code assumes that the PKCS routine checks the format of the key.
916 (check only if PKCS are registered) */
917 if (SILC_PKCS_LIST) {
918 silc_pkcs_alloc(pkcs_name, &alg);
919 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
925 *private_key = silc_calloc(1, sizeof(**private_key));
926 (*private_key)->name = pkcs_name;
927 (*private_key)->prv = key_data;
928 (*private_key)->prv_len = key_len;
931 silc_buffer_free(buf);
936 silc_free(pkcs_name);
939 silc_buffer_free(buf);
943 /* Internal routine to save public key */
945 static int silc_pkcs_save_public_key_internal(char *filename,
954 case SILC_PKCS_FILE_BIN:
956 case SILC_PKCS_FILE_PEM:
957 data = silc_pem_encode_file(data, data_len);
958 data_len = strlen(data);
962 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
963 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
964 buf = silc_buffer_alloc(len);
965 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
967 silc_buffer_format(buf,
968 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
969 SILC_STR_UI_XNSTRING(data, data_len),
970 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
974 if (silc_file_writefile(filename, buf->data, buf->len)) {
975 silc_buffer_free(buf);
979 silc_buffer_free(buf);
983 /* Saves public key into file */
985 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
991 data = silc_pkcs_public_key_encode(public_key, &data_len);
992 return silc_pkcs_save_public_key_internal(filename, data, data_len,
996 /* Saves public key into file */
998 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1000 SilcUInt32 encoding)
1002 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1006 /* Internal routine to save private key. */
1008 static int silc_pkcs_save_private_key_internal(char *filename,
1009 unsigned char *data,
1010 SilcUInt32 data_len,
1011 SilcUInt32 encoding)
1017 case SILC_PKCS_FILE_BIN:
1019 case SILC_PKCS_FILE_PEM:
1020 data = silc_pem_encode_file(data, data_len);
1021 data_len = strlen(data);
1025 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1026 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1027 buf = silc_buffer_alloc(len);
1028 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1030 silc_buffer_format(buf,
1031 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1032 SILC_STR_UI_XNSTRING(data, data_len),
1033 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1036 /* Save into a file */
1037 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1038 silc_buffer_free(buf);
1042 silc_buffer_free(buf);
1046 /* Saves private key into file. */
1047 /* XXX The buffer should be encrypted if passphrase is provided. */
1049 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1050 unsigned char *passphrase,
1051 SilcUInt32 encoding)
1053 unsigned char *data;
1054 SilcUInt32 data_len;
1056 data = silc_pkcs_private_key_encode(private_key, &data_len);
1057 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1061 /* Saves private key into file. */
1062 /* XXX The buffer should be encrypted if passphrase is provided. */
1064 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1065 SilcUInt32 data_len,
1066 unsigned char *passphrase,
1067 SilcUInt32 encoding)
1069 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1073 /* Loads public key from file and allocates new public key. Returns TRUE
1074 is loading was successful. */
1076 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1077 SilcUInt32 encoding)
1079 unsigned char *cp, *old, *data, byte;
1080 SilcUInt32 i, data_len, len;
1082 old = data = silc_file_readfile(filename, &data_len);
1086 /* Check start of file and remove header from the data. */
1087 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1089 for (i = 0; i < len; i++) {
1092 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1093 memset(old, 0, data_len);
1100 /* Decode public key */
1102 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1103 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1106 case SILC_PKCS_FILE_BIN:
1108 case SILC_PKCS_FILE_PEM:
1109 data = silc_pem_decode(data, len, &len);
1110 memset(old, 0, data_len);
1117 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1118 memset(old, 0, data_len);
1124 memset(old, 0, data_len);
1129 /* Load private key from file and allocates new private key. Returns TRUE
1130 if loading was successful. */
1131 /* XXX Should support encrypted private key files */
1133 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1134 SilcUInt32 encoding)
1136 unsigned char *cp, *old, *data, byte;
1137 SilcUInt32 i, data_len, len;
1139 old = data = silc_file_readfile(filename, &data_len);
1143 /* Check start of file and remove header from the data. */
1144 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1146 for (i = 0; i < len; i++) {
1149 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1150 memset(old, 0, data_len);
1157 /* Decode private key */
1159 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1160 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1163 case SILC_PKCS_FILE_BIN:
1165 case SILC_PKCS_FILE_PEM:
1166 data = silc_pem_decode(data, len, &len);
1170 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1171 memset(old, 0, data_len);
1177 memset(old, 0, data_len);