5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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.
23 /****************************** Key generation *******************************/
25 /* Generate new SILC key pair. */
27 SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
28 SilcUInt32 bits_key_len,
29 const char *identifier,
31 SilcPublicKey *ret_public_key,
32 SilcPrivateKey *ret_private_key)
34 SilcSILCPublicKey pubkey;
35 SilcSILCPrivateKey privkey;
36 const SilcPKCSAlgorithm *alg;
37 const SilcPKCSObject *pkcs;
40 SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
41 algorithm, bits_key_len));
46 pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
50 /* Allocate SILC public key */
51 pubkey = silc_calloc(1, sizeof(*pubkey));
55 /* Decode identifier */
56 if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
59 if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
64 /* Allocate algorithm */
65 alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
73 /* Allocate SILC private key */
74 privkey = silc_calloc(1, sizeof(*privkey));
81 /* Allocate public key */
82 *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
83 if (!(*ret_public_key)) {
88 (*ret_public_key)->pkcs = pkcs;
89 (*ret_public_key)->public_key = pubkey;
91 /* Allocate private key */
92 *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
93 if (!(*ret_private_key)) {
96 silc_free(*ret_public_key);
99 (*ret_private_key)->pkcs = pkcs;
100 (*ret_private_key)->private_key = privkey;
102 /* Generate the algorithm key pair */
103 if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
104 &privkey->private_key)) {
107 silc_free(*ret_public_key);
108 silc_free(*ret_private_key);
116 /**************************** Utility functions ******************************/
118 /* Decodes the provided `identifier' */
120 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
121 SilcPublicKeyIdentifier ident)
126 /* Protocol says that at least UN and HN must be provided as identifier */
127 if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
128 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
133 cp = (char *)identifier;
135 len = strcspn(cp, ",");
140 if (len - 1 >= 0 && cp[len - 1] == '\\') {
142 if (len + 1 > strlen(cp)) {
147 len = strcspn(cp, ",") + len;
152 if (len - 1 >= 0 && cp[len - 1] != '\\')
160 item = silc_calloc(len + 1, sizeof(char));
163 if (len > strlen(cp))
165 memcpy(item, cp, len);
167 if (strstr(item, "UN="))
168 ident->username = strdup(item + strcspn(cp, "=") + 1);
169 else if (strstr(item, "HN="))
170 ident->host = strdup(item + strcspn(cp, "=") + 1);
171 else if (strstr(item, "RN="))
172 ident->realname = strdup(item + strcspn(cp, "=") + 1);
173 else if (strstr(item, "E="))
174 ident->email = strdup(item + strcspn(cp, "=") + 1);
175 else if (strstr(item, "O="))
176 ident->org = strdup(item + strcspn(cp, "=") + 1);
177 else if (strstr(item, "C="))
178 ident->country = strdup(item + strcspn(cp, "=") + 1);
179 else if (strstr(item, "V="))
180 ident->version = strdup(item + strcspn(cp, "=") + 1);
195 /* Encodes and returns SILC public key identifier. If some of the
196 arguments is NULL those are not encoded into the identifier string.
197 Protocol says that at least username and host must be provided. */
199 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
200 char *realname, char *email,
201 char *org, char *country,
204 SilcBufferStruct buf;
207 if (!username || !host)
209 if (strlen(username) < 1 || strlen(host) < 1)
212 memset(&buf, 0, sizeof(buf));
215 silc_buffer_format(&buf,
217 SILC_STR_UI32_STRING("UN="),
218 SILC_STR_UI32_STRING(username),
222 silc_buffer_format(&buf,
224 SILC_STR_UI32_STRING(", "),
225 SILC_STR_UI32_STRING("HN="),
226 SILC_STR_UI32_STRING(host),
230 silc_buffer_format(&buf,
232 SILC_STR_UI32_STRING(", "),
233 SILC_STR_UI32_STRING("RN="),
234 SILC_STR_UI32_STRING(realname),
238 silc_buffer_format(&buf,
240 SILC_STR_UI32_STRING(", "),
241 SILC_STR_UI32_STRING("E="),
242 SILC_STR_UI32_STRING(email),
246 silc_buffer_format(&buf,
248 SILC_STR_UI32_STRING(", "),
249 SILC_STR_UI32_STRING("O="),
250 SILC_STR_UI32_STRING(org),
254 silc_buffer_format(&buf,
256 SILC_STR_UI32_STRING(", "),
257 SILC_STR_UI32_STRING("C="),
258 SILC_STR_UI32_STRING(country),
262 if (strlen(version) > 1 || !isdigit(version[0])) {
263 silc_buffer_purge(&buf);
266 silc_buffer_format(&buf,
268 SILC_STR_UI32_STRING(", "),
269 SILC_STR_UI32_STRING("V="),
270 SILC_STR_UI32_STRING(version),
274 silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
276 identifier = silc_buffer_steal(&buf, NULL);
280 /* Return SILC public key version */
282 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
284 SilcSILCPublicKey silc_pubkey;
286 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
289 silc_pubkey = public_key->public_key;
291 /* If version identifire is not present it is version 1. */
292 if (!silc_pubkey->identifier.version)
295 return atoi(silc_pubkey->identifier.version);
298 /*************************** Public key routines *****************************/
300 /* Returns PKCS algorithm context */
302 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
304 SilcSILCPublicKey silc_pubkey = public_key;
305 return silc_pubkey->pkcs;
308 /* Imports SILC protocol style public key from SILC public key file */
310 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
311 SilcUInt32 filedata_len,
312 SilcPKCSFileEncoding encoding,
313 void **ret_public_key)
316 unsigned char *data = NULL;
319 SILC_LOG_DEBUG(("Parsing SILC public key file"));
324 /* Check start of file and remove header from the data. */
325 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
326 if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) {
327 SILC_LOG_ERROR(("Malformed SILC public key header"));
330 for (i = 0; i < len; i++) {
331 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
332 SILC_LOG_ERROR(("Malformed SILC public key header"));
337 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
338 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
341 case SILC_PKCS_FILE_BIN:
344 case SILC_PKCS_FILE_BASE64:
345 data = silc_base64_decode(filedata, filedata_len, &filedata_len);
352 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
356 return ret ? TRUE : FALSE;
359 /* Imports SILC protocol style public key */
361 int silc_pkcs_silc_import_public_key(unsigned char *key,
363 void **ret_public_key)
365 const SilcPKCSAlgorithm *pkcs;
366 SilcBufferStruct buf, alg_key;
367 SilcSILCPublicKey silc_pubkey = NULL;
368 SilcAsn1 asn1 = NULL;
369 SilcUInt32 totlen, keydata_len;
370 SilcUInt16 pkcs_len, identifier_len;
371 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
374 SILC_LOG_DEBUG(("Parsing SILC public key"));
379 silc_buffer_set(&buf, key, key_len);
382 ret = silc_buffer_unformat(&buf,
384 SILC_STR_UI_INT(&totlen),
389 /* Backwards compatibility */
390 if (totlen == key_len)
393 if (totlen + 4 != key_len)
396 /* Get algorithm name and identifier */
398 silc_buffer_unformat(&buf,
400 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
401 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
406 if (pkcs_len < 1 || identifier_len < 3 ||
407 pkcs_len + identifier_len > totlen)
411 keydata_len = silc_buffer_len(&buf);
412 ret = silc_buffer_unformat(&buf,
413 SILC_STR_DATA(&key_data, keydata_len),
418 /* Allocate SILC public key context */
419 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
423 /* Decode SILC identifier */
424 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
427 asn1 = silc_asn1_alloc();
431 SILC_LOG_DEBUG(("Public key version %s",
432 (!silc_pubkey->identifier.version ? "1" :
433 silc_pubkey->identifier.version)));
435 if (!strcmp(pkcs_name, "rsa")) {
436 /* Parse the SILC RSA public key */
437 SilcUInt32 e_len, n_len;
440 /* Get PKCS object. Different PKCS #1 scheme is used with different
442 if (!silc_pubkey->identifier.version ||
443 atoi(silc_pubkey->identifier.version) <= 1) {
445 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
447 /* Version 2 and newer */
448 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
451 SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
454 silc_pubkey->pkcs = pkcs;
458 SILC_GET32_MSB(e_len, key_data);
459 if (!e_len || e_len + 4 > keydata_len)
462 silc_mp_bin2mp(key_data + 4, e_len, &e);
463 if (keydata_len < 4 + e_len + 4) {
467 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
468 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
473 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
475 /* Encode to PKCS #1 format */
476 memset(&alg_key, 0, sizeof(alg_key));
477 if (!silc_asn1_encode(asn1, &alg_key,
481 SILC_ASN1_END, SILC_ASN1_END)) {
490 } else if (!strcmp(pkcs_name, "dsa")) {
491 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
495 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
499 /* Import PKCS algorithm public key */
500 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
501 &silc_pubkey->public_key))
504 silc_free(pkcs_name);
506 silc_asn1_free(asn1);
508 *ret_public_key = silc_pubkey;
513 silc_free(pkcs_name);
515 silc_free(silc_pubkey);
517 silc_asn1_free(asn1);
521 /* Exports public key as SILC protocol style public key file */
524 silc_pkcs_silc_export_public_key_file(void *public_key,
525 SilcPKCSFileEncoding encoding,
529 unsigned char *key, *data;
532 SILC_LOG_DEBUG(("Encoding SILC public key file"));
535 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
540 case SILC_PKCS_FILE_BIN:
543 case SILC_PKCS_FILE_BASE64:
544 data = silc_base64_encode_file(key, key_len);
549 key_len = strlen(data);
553 /* Encode SILC public key file */
554 buf = silc_buffer_alloc_size(key_len +
555 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
556 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
562 if (silc_buffer_format(buf,
563 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
564 SILC_STR_UI_XNSTRING(key, key_len),
565 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
567 silc_buffer_free(buf);
573 key = silc_buffer_steal(buf, ret_len);
574 silc_buffer_free(buf);
579 /* Exports public key as SILC protocol style public key */
581 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
584 SilcSILCPublicKey silc_pubkey = public_key;
585 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
586 SilcBufferStruct alg_key;
587 SilcBuffer buf = NULL;
588 SilcAsn1 asn1 = NULL;
589 unsigned char *pk = NULL, *key = NULL, *ret;
590 SilcUInt32 pk_len, key_len, totlen;
593 SILC_LOG_DEBUG(("Encoding SILC public key"));
595 /* Export PKCS algorithm public key */
596 if (pkcs->export_public_key)
597 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
599 SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
602 silc_buffer_set(&alg_key, pk, pk_len);
604 /* Encode identifier */
606 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
607 silc_pubkey->identifier.host,
608 silc_pubkey->identifier.realname,
609 silc_pubkey->identifier.email,
610 silc_pubkey->identifier.org,
611 silc_pubkey->identifier.country,
612 silc_pubkey->identifier.version);
614 SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
618 asn1 = silc_asn1_alloc();
622 if (!strcmp(pkcs->name, "rsa")) {
623 /* Parse the PKCS #1 public key */
625 SilcUInt32 n_len, e_len;
626 unsigned char *nb, *eb;
628 memset(&n, 0, sizeof(n));
629 memset(&e, 0, sizeof(e));
630 if (!silc_asn1_decode(asn1, &alg_key,
634 SILC_ASN1_END, SILC_ASN1_END))
637 /* Encode to SILC RSA public key */
638 eb = silc_mp_mp2bin(&e, 0, &e_len);
641 nb = silc_mp_mp2bin(&n, 0, &n_len);
644 key_len = e_len + 4 + n_len + 4;
645 key = silc_calloc(key_len, sizeof(*key));
649 /* Put e length and e */
650 SILC_PUT32_MSB(e_len, key);
651 memcpy(key + 4, eb, e_len);
653 /* Put n length and n. */
654 SILC_PUT32_MSB(n_len, key + 4 + e_len);
655 memcpy(key + 4 + e_len + 4, nb, n_len);
660 } else if (!strcmp(pkcs->name, "dsa")) {
661 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
665 SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", pkcs->name));
669 /* Encode SILC Public Key */
670 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
671 buf = silc_buffer_alloc_size(totlen + 4);
674 if (silc_buffer_format(buf,
675 SILC_STR_UI_INT(totlen),
676 SILC_STR_UI_SHORT(strlen(pkcs->name)),
677 SILC_STR_UI32_STRING(pkcs->name),
678 SILC_STR_UI_SHORT(strlen(identifier)),
679 SILC_STR_UI32_STRING(identifier),
680 SILC_STR_UI_XNSTRING(key, key_len),
684 ret = silc_buffer_steal(buf, ret_len);
685 silc_buffer_free(buf);
687 silc_free(identifier);
688 silc_buffer_purge(&alg_key);
689 silc_asn1_free(asn1);
694 silc_free(identifier);
698 silc_buffer_free(buf);
700 silc_asn1_free(asn1);
704 /* Return key length */
706 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
708 SilcSILCPublicKey silc_pubkey = public_key;
709 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
712 /* Copy public key */
714 void *silc_pkcs_silc_public_key_copy(void *public_key)
716 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
717 SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
719 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
722 new_pubkey->pkcs = silc_pubkey->pkcs;
724 new_pubkey->public_key =
725 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
726 if (!new_pubkey->public_key) {
727 silc_free(new_pubkey);
732 new_pubkey->identifier.username =
733 silc_memdup(ident->username, strlen(ident->username));
735 new_pubkey->identifier.host =
736 silc_memdup(ident->host, strlen(ident->host));
738 new_pubkey->identifier.realname =
739 silc_memdup(ident->realname, strlen(ident->realname));
741 new_pubkey->identifier.email =
742 silc_memdup(ident->email, strlen(ident->email));
744 new_pubkey->identifier.org =
745 silc_memdup(ident->org, strlen(ident->org));
747 new_pubkey->identifier.country =
748 silc_memdup(ident->country, strlen(ident->country));
750 new_pubkey->identifier.version =
751 silc_memdup(ident->version, strlen(ident->version));
756 /* Compares public keys */
758 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
760 SilcSILCPublicKey k1 = key1, k2 = key2;
762 if (strcmp(k1->pkcs->name, k2->pkcs->name))
765 if ((k1->identifier.username && !k2->identifier.username) ||
766 (!k1->identifier.username && k2->identifier.username) ||
767 (k1->identifier.username && k2->identifier.username &&
768 strcmp(k1->identifier.username, k2->identifier.username)))
771 if ((k1->identifier.host && !k2->identifier.host) ||
772 (!k1->identifier.host && k2->identifier.host) ||
773 (k1->identifier.host && k2->identifier.host &&
774 strcmp(k1->identifier.host, k2->identifier.host)))
777 if ((k1->identifier.realname && !k2->identifier.realname) ||
778 (!k1->identifier.realname && k2->identifier.realname) ||
779 (k1->identifier.realname && k2->identifier.realname &&
780 strcmp(k1->identifier.realname, k2->identifier.realname)))
783 if ((k1->identifier.email && !k2->identifier.email) ||
784 (!k1->identifier.email && k2->identifier.email) ||
785 (k1->identifier.email && k2->identifier.email &&
786 strcmp(k1->identifier.email, k2->identifier.email)))
789 if ((k1->identifier.org && !k2->identifier.org) ||
790 (!k1->identifier.org && k2->identifier.org) ||
791 (k1->identifier.org && k2->identifier.org &&
792 strcmp(k1->identifier.org, k2->identifier.org)))
795 if ((k1->identifier.country && !k2->identifier.country) ||
796 (!k1->identifier.country && k2->identifier.country) ||
797 (k1->identifier.country && k2->identifier.country &&
798 strcmp(k1->identifier.country, k2->identifier.country)))
801 if ((k1->identifier.version && !k2->identifier.version) ||
802 (!k1->identifier.version && k2->identifier.version) ||
803 (k1->identifier.version && k2->identifier.version &&
804 strcmp(k1->identifier.version, k2->identifier.version)))
807 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
810 /* Frees public key */
812 void silc_pkcs_silc_public_key_free(void *public_key)
814 SilcSILCPublicKey silc_pubkey = public_key;
816 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
818 silc_free(silc_pubkey->identifier.username);
819 silc_free(silc_pubkey->identifier.host);
820 silc_free(silc_pubkey->identifier.realname);
821 silc_free(silc_pubkey->identifier.email);
822 silc_free(silc_pubkey->identifier.org);
823 silc_free(silc_pubkey->identifier.country);
824 silc_free(silc_pubkey->identifier.version);
825 silc_free(silc_pubkey);
829 /*************************** Private key routines ****************************/
831 /* Private key file magic */
832 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
834 /* Imports SILC implementation style private key file */
836 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
837 SilcUInt32 filedata_len,
838 const char *passphrase,
839 SilcUInt32 passphrase_len,
840 SilcPKCSFileEncoding encoding,
841 void **ret_private_key)
847 unsigned char tmp[32], keymat[64], *data = NULL;
848 SilcUInt32 i, len, magic, mac_len;
851 SILC_LOG_DEBUG(("Parsing SILC private key file"));
853 /* Check start of file and remove header from the data. */
854 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
855 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
856 SILC_LOG_ERROR(("Malformed SILC private key header"));
859 for (i = 0; i < len; i++) {
860 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
861 SILC_LOG_ERROR(("Malformed SILC private key header"));
867 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
868 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
871 case SILC_PKCS_FILE_BIN:
874 case SILC_PKCS_FILE_BASE64:
875 data = silc_base64_decode(filedata, filedata_len, &len);
882 memset(tmp, 0, sizeof(tmp));
883 memset(keymat, 0, sizeof(keymat));
885 /* Check file magic */
886 SILC_GET32_MSB(magic, filedata);
887 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
888 SILC_LOG_DEBUG(("Private key does not have correct magic"));
892 /* Allocate the AES cipher */
893 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
894 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
897 blocklen = silc_cipher_get_block_len(aes);
898 if (blocklen * 2 > sizeof(tmp)) {
899 silc_cipher_free(aes);
903 /* Allocate SHA1 hash */
904 if (!silc_hash_alloc("sha1", &sha1)) {
905 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
906 silc_cipher_free(aes);
911 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
912 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
913 silc_hash_free(sha1);
914 silc_cipher_free(aes);
918 /* Derive the decryption key from the provided key material. The key
919 is 256 bits length, and derived by taking hash of the data, then
920 re-hashing the data and the previous digest, and using the first and
921 second digest as the key. */
922 silc_hash_init(sha1);
923 silc_hash_update(sha1, passphrase, passphrase_len);
924 silc_hash_final(sha1, keymat);
925 silc_hash_init(sha1);
926 silc_hash_update(sha1, passphrase, passphrase_len);
927 silc_hash_update(sha1, keymat, 16);
928 silc_hash_final(sha1, keymat + 16);
930 /* Set the key to the cipher */
931 silc_cipher_set_key(aes, keymat, 256, FALSE);
933 /* First, verify the MAC of the private key data */
934 mac_len = silc_hmac_len(sha1hmac);
935 silc_hmac_init_with_key(sha1hmac, keymat, 16);
936 silc_hmac_update(sha1hmac, filedata, len - mac_len);
937 silc_hmac_final(sha1hmac, tmp, NULL);
938 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
939 SILC_LOG_DEBUG(("Integrity check for private key failed"));
940 memset(keymat, 0, sizeof(keymat));
941 memset(tmp, 0, sizeof(tmp));
942 silc_hmac_free(sha1hmac);
943 silc_hash_free(sha1);
944 silc_cipher_free(aes);
950 /* Decrypt the private key buffer */
951 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
952 SILC_GET32_MSB(i, filedata);
954 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
955 memset(keymat, 0, sizeof(keymat));
956 memset(tmp, 0, sizeof(tmp));
957 silc_hmac_free(sha1hmac);
958 silc_hash_free(sha1);
959 silc_cipher_free(aes);
966 memset(keymat, 0, sizeof(keymat));
967 memset(tmp, 0, sizeof(tmp));
968 silc_hmac_free(sha1hmac);
969 silc_hash_free(sha1);
970 silc_cipher_free(aes);
972 /* Import the private key */
973 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
977 return ret ? TRUE : FALSE;
980 /* Private key version */
981 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
982 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
984 /* Imports SILC implementation style private key */
986 int silc_pkcs_silc_import_private_key(unsigned char *key,
988 void **ret_private_key)
990 SilcBufferStruct buf;
991 const SilcPKCSAlgorithm *pkcs;
992 SilcBufferStruct alg_key;
993 SilcSILCPrivateKey silc_privkey = NULL;
994 SilcAsn1 asn1 = NULL;
996 SilcUInt32 keydata_len;
997 unsigned char *pkcs_name = NULL, *key_data;
1000 SILC_LOG_DEBUG(("Parsing SILC private key"));
1002 if (!ret_private_key)
1005 silc_buffer_set(&buf, key, key_len);
1007 /* Get algorithm name and identifier */
1009 silc_buffer_unformat(&buf,
1010 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1013 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1017 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1018 SILC_LOG_DEBUG(("Malformed private key buffer"));
1022 /* Get key data. We assume that rest of the buffer is key data. */
1023 silc_buffer_pull(&buf, 2 + pkcs_len);
1024 keydata_len = silc_buffer_len(&buf);
1025 ret = silc_buffer_unformat(&buf,
1026 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1031 /* Allocate SILC private key context */
1032 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1036 asn1 = silc_asn1_alloc();
1040 if (!strcmp(pkcs_name, "rsa")) {
1041 /* Parse the RSA SILC private key */
1043 SilcMPInt n, e, d, dp, dq, qp, p, q;
1045 SilcUInt32 len, ver;
1047 if (keydata_len < 4)
1049 silc_buffer_set(&k, key_data, keydata_len);
1051 /* Get version. Key without the version is old style private key
1052 and we need to do some computation to get it to correct format. */
1053 if (silc_buffer_unformat(&k,
1054 SILC_STR_UI_INT(&ver),
1057 silc_buffer_pull(&k, 4);
1059 if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1060 ver != SILC_PRIVATE_KEY_VERSION_2) {
1064 if (silc_buffer_unformat(&k,
1065 SILC_STR_UI_INT(&len),
1068 silc_buffer_pull(&k, 4);
1071 /* Get PKCS object. Different PKCS #1 scheme is used with different
1073 if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1074 /* Version 0 and 1 */
1075 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1077 /* Version 2 and newer */
1078 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1081 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1084 silc_privkey->pkcs = pkcs;
1086 SILC_LOG_DEBUG(("Private key version %s",
1087 (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1088 ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1091 if (silc_buffer_unformat(&k,
1092 SILC_STR_DATA(&tmp, len),
1096 silc_mp_bin2mp(tmp, len, &e);
1097 silc_buffer_pull(&k, len);
1100 if (silc_buffer_unformat(&k,
1101 SILC_STR_UI_INT(&len),
1104 silc_buffer_pull(&k, 4);
1105 if (silc_buffer_unformat(&k,
1106 SILC_STR_DATA(&tmp, len),
1110 silc_mp_bin2mp(tmp, len, &n);
1111 silc_buffer_pull(&k, len);
1114 if (silc_buffer_unformat(&k,
1115 SILC_STR_UI_INT(&len),
1118 silc_buffer_pull(&k, 4);
1119 if (silc_buffer_unformat(&k,
1120 SILC_STR_DATA(&tmp, len),
1124 silc_mp_bin2mp(tmp, len, &d);
1125 silc_buffer_pull(&k, len);
1128 if (silc_buffer_unformat(&k,
1129 SILC_STR_UI_INT(&len),
1132 silc_buffer_pull(&k, 4);
1133 if (silc_buffer_unformat(&k,
1134 SILC_STR_DATA(&tmp, len),
1138 silc_mp_bin2mp(tmp, len, &dp);
1139 silc_buffer_pull(&k, len);
1142 if (silc_buffer_unformat(&k,
1143 SILC_STR_UI_INT(&len),
1146 silc_buffer_pull(&k, 4);
1147 if (silc_buffer_unformat(&k,
1148 SILC_STR_DATA(&tmp, len),
1152 silc_mp_bin2mp(tmp, len, &dq);
1153 silc_buffer_pull(&k, len);
1159 if (silc_buffer_unformat(&k,
1160 SILC_STR_UI_INT(&len),
1163 silc_buffer_pull(&k, 4);
1164 if (silc_buffer_len(&k) < len)
1166 silc_buffer_pull(&k, len);
1169 if (silc_buffer_unformat(&k,
1170 SILC_STR_UI_INT(&len),
1173 silc_buffer_pull(&k, 4);
1174 if (silc_buffer_len(&k) < len)
1176 silc_buffer_pull(&k, len);
1181 if (silc_buffer_unformat(&k,
1182 SILC_STR_UI_INT(&len),
1185 silc_buffer_pull(&k, 4);
1186 if (silc_buffer_unformat(&k,
1187 SILC_STR_DATA(&tmp, len),
1191 silc_mp_bin2mp(tmp, len, &qp);
1192 silc_buffer_pull(&k, len);
1196 if (silc_buffer_unformat(&k,
1197 SILC_STR_UI_INT(&len),
1200 silc_buffer_pull(&k, 4);
1201 if (silc_buffer_unformat(&k,
1202 SILC_STR_DATA(&tmp, len),
1206 silc_mp_bin2mp(tmp, len, &p);
1207 silc_buffer_pull(&k, len);
1210 if (silc_buffer_unformat(&k,
1211 SILC_STR_UI_INT(&len),
1214 silc_buffer_pull(&k, 4);
1215 if (silc_buffer_unformat(&k,
1216 SILC_STR_DATA(&tmp, len),
1220 silc_mp_bin2mp(tmp, len, &q);
1221 silc_buffer_pull(&k, len);
1224 /* Old version. Compute to new version */
1225 SILC_LOG_DEBUG(("Old version private key"));
1227 silc_mp_modinv(&qp, &q, &p);
1230 /* Encode to PKCS #1 format */
1231 memset(&alg_key, 0, sizeof(alg_key));
1232 if (!silc_asn1_encode(asn1, &alg_key,
1234 SILC_ASN1_SHORT_INT(0),
1243 SILC_ASN1_END, SILC_ASN1_END))
1252 silc_mp_uninit(&dp);
1253 silc_mp_uninit(&dq);
1254 silc_mp_uninit(&qp);
1256 } else if (!strcmp(pkcs_name, "dsa")) {
1257 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1261 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1265 /* Import PKCS algorithm private key */
1266 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1267 &silc_privkey->private_key))
1270 silc_free(pkcs_name);
1271 silc_asn1_free(asn1);
1273 *ret_private_key = silc_privkey;
1278 silc_free(pkcs_name);
1279 silc_free(silc_privkey);
1281 silc_asn1_free(asn1);
1282 SILC_LOG_ERROR(("Malformed SILC private key "));
1286 /* Exports private key as SILC implementation style private key file */
1289 silc_pkcs_silc_export_private_key_file(void *private_key,
1290 const char *passphrase,
1291 SilcUInt32 passphrase_len,
1292 SilcPKCSFileEncoding encoding,
1294 SilcUInt32 *ret_len)
1299 SilcBuffer buf, enc;
1300 SilcUInt32 len, blocklen, padlen, key_len;
1301 unsigned char *key, *data;
1302 unsigned char tmp[32], keymat[64];
1305 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1307 /* Export the private key */
1308 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1312 memset(tmp, 0, sizeof(tmp));
1313 memset(keymat, 0, sizeof(keymat));
1315 /* Allocate the AES cipher */
1316 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1317 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1321 blocklen = silc_cipher_get_block_len(aes);
1322 if (blocklen * 2 > sizeof(tmp)) {
1323 silc_cipher_free(aes);
1328 /* Allocate SHA1 hash */
1329 if (!silc_hash_alloc("sha1", &sha1)) {
1330 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1331 silc_cipher_free(aes);
1336 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1337 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1338 silc_hash_free(sha1);
1339 silc_cipher_free(aes);
1343 /* Derive the encryption key from the provided key material. The key
1344 is 256 bits length, and derived by taking hash of the data, then
1345 re-hashing the data and the previous digest, and using the first and
1346 second digest as the key. */
1347 silc_hash_init(sha1);
1348 silc_hash_update(sha1, passphrase, passphrase_len);
1349 silc_hash_final(sha1, keymat);
1350 silc_hash_init(sha1);
1351 silc_hash_update(sha1, passphrase, passphrase_len);
1352 silc_hash_update(sha1, keymat, 16);
1353 silc_hash_final(sha1, keymat + 16);
1355 /* Set the key to the cipher */
1356 silc_cipher_set_key(aes, keymat, 256, TRUE);
1358 /* Encode the buffer to be encrypted. Add padding to it too, at least
1359 block size of the cipher. */
1361 /* Allocate buffer for encryption */
1362 len = silc_hmac_len(sha1hmac);
1363 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1364 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1366 silc_hmac_free(sha1hmac);
1367 silc_hash_free(sha1);
1368 silc_cipher_free(aes);
1372 /* Generate padding */
1373 for (i = 0; i < padlen; i++)
1374 tmp[i] = silc_rng_get_byte_fast(rng);
1376 /* Put magic number */
1377 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1378 silc_buffer_pull(enc, 4);
1380 /* Encode the buffer */
1381 silc_buffer_format(enc,
1382 SILC_STR_UI_INT(key_len),
1383 SILC_STR_UI_XNSTRING(key, key_len),
1384 SILC_STR_UI_XNSTRING(tmp, padlen),
1389 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1390 silc_cipher_get_iv(aes));
1392 silc_buffer_push(enc, 4);
1394 /* Compute HMAC over the encrypted data and append the MAC to data.
1395 The key is the first digest of the original key material. */
1396 key_len = silc_buffer_len(enc) - len;
1397 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1398 silc_hmac_update(sha1hmac, enc->data, key_len);
1399 silc_buffer_pull(enc, key_len);
1400 silc_hmac_final(sha1hmac, enc->data, NULL);
1401 silc_buffer_push(enc, key_len);
1404 memset(keymat, 0, sizeof(keymat));
1405 memset(tmp, 0, sizeof(tmp));
1406 silc_hmac_free(sha1hmac);
1407 silc_hash_free(sha1);
1408 silc_cipher_free(aes);
1411 case SILC_PKCS_FILE_BIN:
1414 case SILC_PKCS_FILE_BASE64:
1415 data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1417 silc_buffer_clear(enc);
1418 silc_buffer_free(enc);
1421 silc_free(silc_buffer_steal(enc, NULL));
1422 silc_buffer_set(enc, data, strlen(data));
1427 key_len = silc_buffer_len(enc);
1429 /* Encode the data and save to file */
1430 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1431 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1432 buf = silc_buffer_alloc_size(len);
1434 silc_buffer_free(enc);
1437 silc_buffer_format(buf,
1438 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1439 SILC_STR_UI_XNSTRING(key, key_len),
1440 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1443 silc_buffer_free(enc);
1444 data = silc_buffer_steal(buf, ret_len);
1445 silc_buffer_free(buf);
1450 /* Exports private key as SILC implementation style private key */
1452 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1453 SilcUInt32 *ret_len)
1455 SilcSILCPrivateKey silc_privkey = private_key;
1456 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1457 SilcBufferStruct alg_key;
1458 SilcBuffer buf = NULL;
1459 SilcAsn1 asn1 = NULL;
1460 unsigned char *prv = NULL, *key = NULL, *ret;
1461 SilcUInt32 prv_len, key_len, totlen;
1463 SILC_LOG_DEBUG(("Encoding SILC private key"));
1465 /* Export PKCS algorithm private key */
1466 if (pkcs->export_private_key)
1467 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1470 silc_buffer_set(&alg_key, prv, prv_len);
1472 asn1 = silc_asn1_alloc();
1476 if (!strcmp(pkcs->name, "rsa")) {
1477 /* Parse the PKCS #1 private key */
1478 SilcMPInt n, e, d, dp, dq, qp, p, q;
1479 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1480 qp_len, p_len, q_len, len = 0;
1481 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1483 if (!silc_asn1_decode(asn1, &alg_key,
1485 SILC_ASN1_INT(NULL),
1494 SILC_ASN1_END, SILC_ASN1_END))
1497 /* Encode to SILC RSA private key */
1498 eb = silc_mp_mp2bin(&e, 0, &e_len);
1499 nb = silc_mp_mp2bin(&n, 0, &n_len);
1500 db = silc_mp_mp2bin(&d, 0, &d_len);
1501 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1502 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1503 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1504 pb = silc_mp_mp2bin(&p, 0, &p_len);
1505 qb = silc_mp_mp2bin(&q, 0, &q_len);
1506 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1507 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1509 buf = silc_buffer_alloc_size(len);
1512 if (silc_buffer_format(buf,
1513 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1514 SILC_STR_UI_INT(e_len),
1515 SILC_STR_UI_XNSTRING(eb, e_len),
1516 SILC_STR_UI_INT(n_len),
1517 SILC_STR_UI_XNSTRING(nb, n_len),
1518 SILC_STR_UI_INT(d_len),
1519 SILC_STR_UI_XNSTRING(db, d_len),
1520 SILC_STR_UI_INT(dp_len),
1521 SILC_STR_UI_XNSTRING(dpb, dp_len),
1522 SILC_STR_UI_INT(dq_len),
1523 SILC_STR_UI_XNSTRING(dqb, dq_len),
1524 SILC_STR_UI_INT(qp_len),
1525 SILC_STR_UI_XNSTRING(qpb, qp_len),
1526 SILC_STR_UI_INT(p_len),
1527 SILC_STR_UI_XNSTRING(pb, p_len),
1528 SILC_STR_UI_INT(q_len),
1529 SILC_STR_UI_XNSTRING(qb, q_len),
1533 key = silc_buffer_steal(buf, &key_len);
1534 silc_buffer_free(buf);
1544 } else if (!strcmp(pkcs->name, "dsa")) {
1545 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1549 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1553 /* Encode SILC private key */
1554 totlen = 2 + strlen(pkcs->name) + key_len;
1555 buf = silc_buffer_alloc_size(totlen);
1558 if (silc_buffer_format(buf,
1559 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1560 SILC_STR_UI32_STRING(pkcs->name),
1561 SILC_STR_UI_XNSTRING(key, key_len),
1565 ret = silc_buffer_steal(buf, ret_len);
1566 silc_buffer_free(buf);
1569 silc_asn1_free(asn1);
1577 silc_buffer_free(buf);
1581 /* Return key length */
1583 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1585 SilcSILCPrivateKey silc_privkey = private_key;
1586 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1589 /* Frees private key */
1591 void silc_pkcs_silc_private_key_free(void *private_key)
1593 SilcSILCPrivateKey silc_privkey = private_key;
1595 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1597 silc_free(silc_privkey);
1601 /***************************** PKCS operations ******************************/
1603 /* Encrypts as specified in SILC protocol specification */
1605 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1609 SilcUInt32 dst_size,
1610 SilcUInt32 *ret_dst_len,
1613 SilcSILCPublicKey silc_pubkey = public_key;
1615 if (!silc_pubkey->pkcs->encrypt)
1618 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1620 dst, dst_size, ret_dst_len, rng);
1623 /* Decrypts as specified in SILC protocol specification */
1625 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1629 SilcUInt32 dst_size,
1630 SilcUInt32 *ret_dst_len)
1632 SilcSILCPrivateKey silc_privkey = private_key;
1634 if (!silc_privkey->pkcs->decrypt)
1637 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1639 dst, dst_size, ret_dst_len);
1642 /* Signs as specified in SILC protocol specification */
1644 SilcBool silc_pkcs_silc_sign(void *private_key,
1647 unsigned char *signature,
1648 SilcUInt32 signature_size,
1649 SilcUInt32 *ret_signature_len,
1650 SilcBool compute_hash,
1653 SilcSILCPrivateKey silc_privkey = private_key;
1655 if (!silc_privkey->pkcs->sign)
1658 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1660 signature, signature_size,
1661 ret_signature_len, compute_hash, hash);
1664 /* Verifies as specified in SILC protocol specification */
1666 SilcBool silc_pkcs_silc_verify(void *public_key,
1667 unsigned char *signature,
1668 SilcUInt32 signature_len,
1669 unsigned char *data,
1670 SilcUInt32 data_len,
1673 SilcSILCPublicKey silc_pubkey = public_key;
1675 if (!silc_pubkey->pkcs->verify)
1678 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1679 signature, signature_len,
1680 data, data_len, hash);