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) < 3 || strlen(host) < 3)
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))
328 for (i = 0; i < len; i++) {
329 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
333 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
334 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
337 case SILC_PKCS_FILE_BIN:
340 case SILC_PKCS_FILE_BASE64:
341 data = silc_base64_decode(filedata, filedata_len, &filedata_len);
348 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
352 return ret ? TRUE : FALSE;
355 /* Imports SILC protocol style public key */
357 int silc_pkcs_silc_import_public_key(unsigned char *key,
359 void **ret_public_key)
361 const SilcPKCSAlgorithm *pkcs;
362 SilcBufferStruct buf, alg_key;
363 SilcSILCPublicKey silc_pubkey = NULL;
364 SilcAsn1 asn1 = NULL;
365 SilcUInt32 totlen, keydata_len;
366 SilcUInt16 pkcs_len, identifier_len;
367 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
370 SILC_LOG_DEBUG(("Parsing SILC public key"));
375 silc_buffer_set(&buf, key, key_len);
378 ret = silc_buffer_unformat(&buf,
380 SILC_STR_UI_INT(&totlen),
385 /* Backwards compatibility */
386 if (totlen == key_len)
389 if (totlen + 4 != key_len)
392 /* Get algorithm name and identifier */
394 silc_buffer_unformat(&buf,
396 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
397 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
402 if (pkcs_len < 1 || identifier_len < 3 ||
403 pkcs_len + identifier_len > totlen)
407 keydata_len = silc_buffer_len(&buf);
408 ret = silc_buffer_unformat(&buf,
409 SILC_STR_DATA(&key_data, keydata_len),
414 /* Allocate SILC public key context */
415 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
419 /* Decode SILC identifier */
420 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
423 asn1 = silc_asn1_alloc();
427 SILC_LOG_DEBUG(("Public key version %s",
428 (!silc_pubkey->identifier.version ? " 1" :
429 silc_pubkey->identifier.version)));
431 if (!strcmp(pkcs_name, "rsa")) {
432 /* Parse the SILC RSA public key */
433 SilcUInt32 e_len, n_len;
436 /* Get PKCS object. Different PKCS #1 scheme is used with different
438 if (!silc_pubkey->identifier.version ||
439 atoi(silc_pubkey->identifier.version) <= 1) {
441 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
443 /* Version 2 and newer */
444 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
447 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
450 silc_pubkey->pkcs = pkcs;
454 SILC_GET32_MSB(e_len, key_data);
455 if (!e_len || e_len + 4 > keydata_len)
458 silc_mp_bin2mp(key_data + 4, e_len, &e);
459 if (keydata_len < 4 + e_len + 4) {
463 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
464 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
469 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
471 /* Encode to PKCS #1 format */
472 memset(&alg_key, 0, sizeof(alg_key));
473 if (!silc_asn1_encode(asn1, &alg_key,
477 SILC_ASN1_END, SILC_ASN1_END)) {
486 } else if (!strcmp(pkcs_name, "dsa")) {
487 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
491 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
495 /* Import PKCS algorithm public key */
496 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
497 &silc_pubkey->public_key))
500 silc_free(pkcs_name);
502 silc_asn1_free(asn1);
504 *ret_public_key = silc_pubkey;
509 silc_free(pkcs_name);
511 silc_free(silc_pubkey);
513 silc_asn1_free(asn1);
517 /* Exports public key as SILC protocol style public key file */
520 silc_pkcs_silc_export_public_key_file(void *public_key,
521 SilcPKCSFileEncoding encoding,
525 unsigned char *key, *data;
528 SILC_LOG_DEBUG(("Encoding SILC public key file"));
531 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
536 case SILC_PKCS_FILE_BIN:
539 case SILC_PKCS_FILE_BASE64:
540 data = silc_base64_encode_file(key, key_len);
545 key_len = strlen(data);
549 /* Encode SILC public key file */
550 buf = silc_buffer_alloc_size(key_len +
551 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
552 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
558 if (silc_buffer_format(buf,
559 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
560 SILC_STR_UI_XNSTRING(key, key_len),
561 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
563 silc_buffer_free(buf);
569 key = silc_buffer_steal(buf, ret_len);
570 silc_buffer_free(buf);
575 /* Exports public key as SILC protocol style public key */
577 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
580 SilcSILCPublicKey silc_pubkey = public_key;
581 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
582 SilcBufferStruct alg_key;
583 SilcBuffer buf = NULL;
584 SilcAsn1 asn1 = NULL;
585 unsigned char *pk = NULL, *key = NULL, *ret;
586 SilcUInt32 pk_len, key_len, totlen;
589 SILC_LOG_DEBUG(("Encoding SILC public key"));
591 /* Export PKCS algorithm public key */
592 if (pkcs->export_public_key)
593 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
596 silc_buffer_set(&alg_key, pk, pk_len);
598 /* Encode identifier */
600 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
601 silc_pubkey->identifier.host,
602 silc_pubkey->identifier.realname,
603 silc_pubkey->identifier.email,
604 silc_pubkey->identifier.org,
605 silc_pubkey->identifier.country,
606 silc_pubkey->identifier.version);
610 asn1 = silc_asn1_alloc();
614 if (!strcmp(pkcs->name, "rsa")) {
615 /* Parse the PKCS #1 public key */
617 SilcUInt32 n_len, e_len;
618 unsigned char *nb, *eb;
620 memset(&n, 0, sizeof(n));
621 memset(&e, 0, sizeof(e));
622 if (!silc_asn1_decode(asn1, &alg_key,
626 SILC_ASN1_END, SILC_ASN1_END))
629 /* Encode to SILC RSA public key */
630 eb = silc_mp_mp2bin(&e, 0, &e_len);
633 nb = silc_mp_mp2bin(&n, 0, &n_len);
636 key_len = e_len + 4 + n_len + 4;
637 key = silc_calloc(key_len, sizeof(*key));
641 /* Put e length and e */
642 SILC_PUT32_MSB(e_len, key);
643 memcpy(key + 4, eb, e_len);
645 /* Put n length and n. */
646 SILC_PUT32_MSB(n_len, key + 4 + e_len);
647 memcpy(key + 4 + e_len + 4, nb, n_len);
652 } else if (!strcmp(pkcs->name, "dsa")) {
653 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
657 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
661 /* Encode SILC Public Key */
662 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
663 buf = silc_buffer_alloc_size(totlen + 4);
666 if (silc_buffer_format(buf,
667 SILC_STR_UI_INT(totlen),
668 SILC_STR_UI_SHORT(strlen(pkcs->name)),
669 SILC_STR_UI32_STRING(pkcs->name),
670 SILC_STR_UI_SHORT(strlen(identifier)),
671 SILC_STR_UI32_STRING(identifier),
672 SILC_STR_UI_XNSTRING(key, key_len),
676 ret = silc_buffer_steal(buf, ret_len);
677 silc_buffer_free(buf);
679 silc_free(identifier);
680 silc_asn1_free(asn1);
685 silc_free(identifier);
689 silc_buffer_free(buf);
691 silc_asn1_free(asn1);
695 /* Return key length */
697 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
699 SilcSILCPublicKey silc_pubkey = public_key;
700 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
703 /* Copy public key */
705 void *silc_pkcs_silc_public_key_copy(void *public_key)
707 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
709 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
712 new_pubkey->pkcs = silc_pubkey->pkcs;
714 new_pubkey->public_key =
715 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
716 if (!new_pubkey->public_key) {
717 silc_free(new_pubkey);
724 /* Compares public keys */
726 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
728 SilcSILCPublicKey k1 = key1, k2 = key2;
730 if (strcmp(k1->pkcs->name, k2->pkcs->name))
733 if ((k1->identifier.username && !k2->identifier.username) ||
734 (!k1->identifier.username && k2->identifier.username) ||
735 (k1->identifier.username && k2->identifier.username &&
736 strcmp(k1->identifier.username, k2->identifier.username)))
739 if ((k1->identifier.host && !k2->identifier.host) ||
740 (!k1->identifier.host && k2->identifier.host) ||
741 (k1->identifier.host && k2->identifier.host &&
742 strcmp(k1->identifier.host, k2->identifier.host)))
745 if ((k1->identifier.realname && !k2->identifier.realname) ||
746 (!k1->identifier.realname && k2->identifier.realname) ||
747 (k1->identifier.realname && k2->identifier.realname &&
748 strcmp(k1->identifier.realname, k2->identifier.realname)))
751 if ((k1->identifier.email && !k2->identifier.email) ||
752 (!k1->identifier.email && k2->identifier.email) ||
753 (k1->identifier.email && k2->identifier.email &&
754 strcmp(k1->identifier.email, k2->identifier.email)))
757 if ((k1->identifier.org && !k2->identifier.org) ||
758 (!k1->identifier.org && k2->identifier.org) ||
759 (k1->identifier.org && k2->identifier.org &&
760 strcmp(k1->identifier.org, k2->identifier.org)))
763 if ((k1->identifier.country && !k2->identifier.country) ||
764 (!k1->identifier.country && k2->identifier.country) ||
765 (k1->identifier.country && k2->identifier.country &&
766 strcmp(k1->identifier.country, k2->identifier.country)))
769 if ((k1->identifier.version && !k2->identifier.version) ||
770 (!k1->identifier.version && k2->identifier.version) ||
771 (k1->identifier.version && k2->identifier.version &&
772 strcmp(k1->identifier.version, k2->identifier.version)))
775 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
778 /* Frees public key */
780 void silc_pkcs_silc_public_key_free(void *public_key)
782 SilcSILCPublicKey silc_pubkey = public_key;
784 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
786 silc_free(silc_pubkey->identifier.username);
787 silc_free(silc_pubkey->identifier.host);
788 silc_free(silc_pubkey->identifier.realname);
789 silc_free(silc_pubkey->identifier.email);
790 silc_free(silc_pubkey->identifier.org);
791 silc_free(silc_pubkey->identifier.country);
792 silc_free(silc_pubkey->identifier.version);
793 silc_free(silc_pubkey);
797 /*************************** Private key routines ****************************/
799 /* Private key file magic */
800 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
802 /* Imports SILC implementation style private key file */
804 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
805 SilcUInt32 filedata_len,
806 const char *passphrase,
807 SilcUInt32 passphrase_len,
808 SilcPKCSFileEncoding encoding,
809 void **ret_private_key)
815 unsigned char tmp[32], keymat[64], *data = NULL;
816 SilcUInt32 i, len, magic, mac_len;
819 SILC_LOG_DEBUG(("Parsing SILC private key file"));
821 /* Check start of file and remove header from the data. */
822 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
823 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
825 for (i = 0; i < len; i++) {
826 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
831 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
832 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
835 case SILC_PKCS_FILE_BIN:
838 case SILC_PKCS_FILE_BASE64:
839 data = silc_base64_decode(filedata, filedata_len, &len);
846 memset(tmp, 0, sizeof(tmp));
847 memset(keymat, 0, sizeof(keymat));
849 /* Check file magic */
850 SILC_GET32_MSB(magic, filedata);
851 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
852 SILC_LOG_DEBUG(("Private key does not have correct magic"));
856 /* Allocate the AES cipher */
857 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
858 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
861 blocklen = silc_cipher_get_block_len(aes);
862 if (blocklen * 2 > sizeof(tmp)) {
863 silc_cipher_free(aes);
867 /* Allocate SHA1 hash */
868 if (!silc_hash_alloc("sha1", &sha1)) {
869 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
870 silc_cipher_free(aes);
875 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
876 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
877 silc_hash_free(sha1);
878 silc_cipher_free(aes);
882 /* Derive the decryption key from the provided key material. The key
883 is 256 bits length, and derived by taking hash of the data, then
884 re-hashing the data and the previous digest, and using the first and
885 second digest as the key. */
886 silc_hash_init(sha1);
887 silc_hash_update(sha1, passphrase, passphrase_len);
888 silc_hash_final(sha1, keymat);
889 silc_hash_init(sha1);
890 silc_hash_update(sha1, passphrase, passphrase_len);
891 silc_hash_update(sha1, keymat, 16);
892 silc_hash_final(sha1, keymat + 16);
894 /* Set the key to the cipher */
895 silc_cipher_set_key(aes, keymat, 256, FALSE);
897 /* First, verify the MAC of the private key data */
898 mac_len = silc_hmac_len(sha1hmac);
899 silc_hmac_init_with_key(sha1hmac, keymat, 16);
900 silc_hmac_update(sha1hmac, filedata, len - mac_len);
901 silc_hmac_final(sha1hmac, tmp, NULL);
902 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
903 SILC_LOG_DEBUG(("Integrity check for private key failed"));
904 memset(keymat, 0, sizeof(keymat));
905 memset(tmp, 0, sizeof(tmp));
906 silc_hmac_free(sha1hmac);
907 silc_hash_free(sha1);
908 silc_cipher_free(aes);
914 /* Decrypt the private key buffer */
915 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
916 SILC_GET32_MSB(i, filedata);
918 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
919 memset(keymat, 0, sizeof(keymat));
920 memset(tmp, 0, sizeof(tmp));
921 silc_hmac_free(sha1hmac);
922 silc_hash_free(sha1);
923 silc_cipher_free(aes);
930 memset(keymat, 0, sizeof(keymat));
931 memset(tmp, 0, sizeof(tmp));
932 silc_hmac_free(sha1hmac);
933 silc_hash_free(sha1);
934 silc_cipher_free(aes);
936 /* Import the private key */
937 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
941 return ret ? TRUE : FALSE;
944 /* Private key version */
945 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
946 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
948 /* Imports SILC implementation style private key */
950 int silc_pkcs_silc_import_private_key(unsigned char *key,
952 void **ret_private_key)
954 SilcBufferStruct buf;
955 const SilcPKCSAlgorithm *pkcs;
956 SilcBufferStruct alg_key;
957 SilcSILCPrivateKey silc_privkey = NULL;
958 SilcAsn1 asn1 = NULL;
960 SilcUInt32 keydata_len;
961 unsigned char *pkcs_name = NULL, *key_data;
964 SILC_LOG_DEBUG(("Parsing SILC private key"));
966 if (!ret_private_key)
969 silc_buffer_set(&buf, key, key_len);
971 /* Get algorithm name and identifier */
973 silc_buffer_unformat(&buf,
974 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
977 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
981 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
982 SILC_LOG_DEBUG(("Malformed private key buffer"));
986 /* Get key data. We assume that rest of the buffer is key data. */
987 silc_buffer_pull(&buf, 2 + pkcs_len);
988 keydata_len = silc_buffer_len(&buf);
989 ret = silc_buffer_unformat(&buf,
990 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
995 /* Allocate SILC private key context */
996 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1000 asn1 = silc_asn1_alloc();
1004 if (!strcmp(pkcs_name, "rsa")) {
1005 /* Parse the RSA SILC private key */
1007 SilcMPInt n, e, d, dp, dq, qp, p, q;
1009 SilcUInt32 len, ver;
1011 if (keydata_len < 4)
1013 silc_buffer_set(&k, key_data, keydata_len);
1015 /* Get version. Key without the version is old style private key
1016 and we need to do some computation to get it to correct format. */
1017 if (silc_buffer_unformat(&k,
1018 SILC_STR_UI_INT(&ver),
1021 silc_buffer_pull(&k, 4);
1023 if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1024 ver != SILC_PRIVATE_KEY_VERSION_2) {
1028 if (silc_buffer_unformat(&k,
1029 SILC_STR_UI_INT(&len),
1032 silc_buffer_pull(&k, 4);
1035 /* Get PKCS object. Different PKCS #1 scheme is used with different
1037 if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1038 /* Version 0 and 1 */
1039 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1041 /* Version 2 and newer */
1042 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1045 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1048 silc_privkey->pkcs = pkcs;
1050 SILC_LOG_DEBUG(("Private key version %s",
1051 (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1052 ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1055 if (silc_buffer_unformat(&k,
1056 SILC_STR_DATA(&tmp, len),
1060 silc_mp_bin2mp(tmp, len, &e);
1061 silc_buffer_pull(&k, len);
1064 if (silc_buffer_unformat(&k,
1065 SILC_STR_UI_INT(&len),
1068 silc_buffer_pull(&k, 4);
1069 if (silc_buffer_unformat(&k,
1070 SILC_STR_DATA(&tmp, len),
1074 silc_mp_bin2mp(tmp, len, &n);
1075 silc_buffer_pull(&k, len);
1078 if (silc_buffer_unformat(&k,
1079 SILC_STR_UI_INT(&len),
1082 silc_buffer_pull(&k, 4);
1083 if (silc_buffer_unformat(&k,
1084 SILC_STR_DATA(&tmp, len),
1088 silc_mp_bin2mp(tmp, len, &d);
1089 silc_buffer_pull(&k, len);
1092 if (silc_buffer_unformat(&k,
1093 SILC_STR_UI_INT(&len),
1096 silc_buffer_pull(&k, 4);
1097 if (silc_buffer_unformat(&k,
1098 SILC_STR_DATA(&tmp, len),
1102 silc_mp_bin2mp(tmp, len, &dp);
1103 silc_buffer_pull(&k, len);
1106 if (silc_buffer_unformat(&k,
1107 SILC_STR_UI_INT(&len),
1110 silc_buffer_pull(&k, 4);
1111 if (silc_buffer_unformat(&k,
1112 SILC_STR_DATA(&tmp, len),
1116 silc_mp_bin2mp(tmp, len, &dq);
1117 silc_buffer_pull(&k, len);
1123 if (silc_buffer_unformat(&k,
1124 SILC_STR_UI_INT(&len),
1127 silc_buffer_pull(&k, 4);
1128 if (silc_buffer_len(&k) < len)
1130 silc_buffer_pull(&k, len);
1133 if (silc_buffer_unformat(&k,
1134 SILC_STR_UI_INT(&len),
1137 silc_buffer_pull(&k, 4);
1138 if (silc_buffer_len(&k) < len)
1140 silc_buffer_pull(&k, len);
1145 if (silc_buffer_unformat(&k,
1146 SILC_STR_UI_INT(&len),
1149 silc_buffer_pull(&k, 4);
1150 if (silc_buffer_unformat(&k,
1151 SILC_STR_DATA(&tmp, len),
1155 silc_mp_bin2mp(tmp, len, &qp);
1156 silc_buffer_pull(&k, len);
1160 if (silc_buffer_unformat(&k,
1161 SILC_STR_UI_INT(&len),
1164 silc_buffer_pull(&k, 4);
1165 if (silc_buffer_unformat(&k,
1166 SILC_STR_DATA(&tmp, len),
1170 silc_mp_bin2mp(tmp, len, &p);
1171 silc_buffer_pull(&k, len);
1174 if (silc_buffer_unformat(&k,
1175 SILC_STR_UI_INT(&len),
1178 silc_buffer_pull(&k, 4);
1179 if (silc_buffer_unformat(&k,
1180 SILC_STR_DATA(&tmp, len),
1184 silc_mp_bin2mp(tmp, len, &q);
1185 silc_buffer_pull(&k, len);
1188 /* Old version. Compute to new version */
1189 SILC_LOG_DEBUG(("Old version private key"));
1191 silc_mp_modinv(&qp, &q, &p);
1194 /* Encode to PKCS #1 format */
1195 memset(&alg_key, 0, sizeof(alg_key));
1196 if (!silc_asn1_encode(asn1, &alg_key,
1198 SILC_ASN1_SHORT_INT(0),
1207 SILC_ASN1_END, SILC_ASN1_END))
1216 silc_mp_uninit(&dp);
1217 silc_mp_uninit(&dq);
1218 silc_mp_uninit(&qp);
1220 } else if (!strcmp(pkcs_name, "dsa")) {
1221 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1225 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1229 /* Import PKCS algorithm private key */
1230 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1231 &silc_privkey->private_key))
1234 silc_free(pkcs_name);
1235 silc_asn1_free(asn1);
1237 *ret_private_key = silc_privkey;
1242 silc_free(pkcs_name);
1243 silc_free(silc_privkey);
1245 silc_asn1_free(asn1);
1249 /* Exports private key as SILC implementation style private key file */
1252 silc_pkcs_silc_export_private_key_file(void *private_key,
1253 const char *passphrase,
1254 SilcUInt32 passphrase_len,
1255 SilcPKCSFileEncoding encoding,
1257 SilcUInt32 *ret_len)
1262 SilcBuffer buf, enc;
1263 SilcUInt32 len, blocklen, padlen, key_len;
1264 unsigned char *key, *data;
1265 unsigned char tmp[32], keymat[64];
1268 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1270 /* Export the private key */
1271 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1275 memset(tmp, 0, sizeof(tmp));
1276 memset(keymat, 0, sizeof(keymat));
1278 /* Allocate the AES cipher */
1279 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1280 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1284 blocklen = silc_cipher_get_block_len(aes);
1285 if (blocklen * 2 > sizeof(tmp)) {
1286 silc_cipher_free(aes);
1291 /* Allocate SHA1 hash */
1292 if (!silc_hash_alloc("sha1", &sha1)) {
1293 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1294 silc_cipher_free(aes);
1299 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1300 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1301 silc_hash_free(sha1);
1302 silc_cipher_free(aes);
1306 /* Derive the encryption key from the provided key material. The key
1307 is 256 bits length, and derived by taking hash of the data, then
1308 re-hashing the data and the previous digest, and using the first and
1309 second digest as the key. */
1310 silc_hash_init(sha1);
1311 silc_hash_update(sha1, passphrase, passphrase_len);
1312 silc_hash_final(sha1, keymat);
1313 silc_hash_init(sha1);
1314 silc_hash_update(sha1, passphrase, passphrase_len);
1315 silc_hash_update(sha1, keymat, 16);
1316 silc_hash_final(sha1, keymat + 16);
1318 /* Set the key to the cipher */
1319 silc_cipher_set_key(aes, keymat, 256, TRUE);
1321 /* Encode the buffer to be encrypted. Add padding to it too, at least
1322 block size of the cipher. */
1324 /* Allocate buffer for encryption */
1325 len = silc_hmac_len(sha1hmac);
1326 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1327 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1329 silc_hmac_free(sha1hmac);
1330 silc_hash_free(sha1);
1331 silc_cipher_free(aes);
1335 /* Generate padding */
1336 for (i = 0; i < padlen; i++)
1337 tmp[i] = silc_rng_get_byte_fast(rng);
1339 /* Put magic number */
1340 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1341 silc_buffer_pull(enc, 4);
1343 /* Encode the buffer */
1344 silc_buffer_format(enc,
1345 SILC_STR_UI_INT(key_len),
1346 SILC_STR_UI_XNSTRING(key, key_len),
1347 SILC_STR_UI_XNSTRING(tmp, padlen),
1352 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1353 silc_cipher_get_iv(aes));
1355 silc_buffer_push(enc, 4);
1357 /* Compute HMAC over the encrypted data and append the MAC to data.
1358 The key is the first digest of the original key material. */
1359 key_len = silc_buffer_len(enc) - len;
1360 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1361 silc_hmac_update(sha1hmac, enc->data, key_len);
1362 silc_buffer_pull(enc, key_len);
1363 silc_hmac_final(sha1hmac, enc->data, NULL);
1364 silc_buffer_push(enc, key_len);
1367 memset(keymat, 0, sizeof(keymat));
1368 memset(tmp, 0, sizeof(tmp));
1369 silc_hmac_free(sha1hmac);
1370 silc_hash_free(sha1);
1371 silc_cipher_free(aes);
1374 case SILC_PKCS_FILE_BIN:
1377 case SILC_PKCS_FILE_BASE64:
1378 data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1380 silc_buffer_clear(enc);
1381 silc_buffer_free(enc);
1384 silc_free(silc_buffer_steal(enc, NULL));
1385 silc_buffer_set(enc, data, strlen(data));
1390 key_len = silc_buffer_len(enc);
1392 /* Encode the data and save to file */
1393 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1394 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1395 buf = silc_buffer_alloc_size(len);
1397 silc_buffer_free(enc);
1400 silc_buffer_format(buf,
1401 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1402 SILC_STR_UI_XNSTRING(key, key_len),
1403 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1406 silc_buffer_free(enc);
1407 data = silc_buffer_steal(buf, ret_len);
1408 silc_buffer_free(buf);
1413 /* Exports private key as SILC implementation style private key */
1415 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1416 SilcUInt32 *ret_len)
1418 SilcSILCPrivateKey silc_privkey = private_key;
1419 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1420 SilcBufferStruct alg_key;
1421 SilcBuffer buf = NULL;
1422 SilcAsn1 asn1 = NULL;
1423 unsigned char *prv = NULL, *key = NULL, *ret;
1424 SilcUInt32 prv_len, key_len, totlen;
1426 SILC_LOG_DEBUG(("Encoding SILC private key"));
1428 /* Export PKCS algorithm private key */
1429 if (pkcs->export_private_key)
1430 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1433 silc_buffer_set(&alg_key, prv, prv_len);
1435 asn1 = silc_asn1_alloc();
1439 if (!strcmp(pkcs->name, "rsa")) {
1440 /* Parse the PKCS #1 private key */
1441 SilcMPInt n, e, d, dp, dq, qp, p, q;
1442 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1443 qp_len, p_len, q_len, len = 0;
1444 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1446 if (!silc_asn1_decode(asn1, &alg_key,
1448 SILC_ASN1_INT(NULL),
1457 SILC_ASN1_END, SILC_ASN1_END))
1460 /* Encode to SILC RSA private key */
1461 eb = silc_mp_mp2bin(&e, 0, &e_len);
1462 nb = silc_mp_mp2bin(&n, 0, &n_len);
1463 db = silc_mp_mp2bin(&d, 0, &d_len);
1464 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1465 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1466 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1467 pb = silc_mp_mp2bin(&p, 0, &p_len);
1468 qb = silc_mp_mp2bin(&q, 0, &q_len);
1469 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1470 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1472 buf = silc_buffer_alloc_size(len);
1475 if (silc_buffer_format(buf,
1476 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1477 SILC_STR_UI_INT(e_len),
1478 SILC_STR_UI_XNSTRING(eb, e_len),
1479 SILC_STR_UI_INT(n_len),
1480 SILC_STR_UI_XNSTRING(nb, n_len),
1481 SILC_STR_UI_INT(d_len),
1482 SILC_STR_UI_XNSTRING(db, d_len),
1483 SILC_STR_UI_INT(dp_len),
1484 SILC_STR_UI_XNSTRING(dpb, dp_len),
1485 SILC_STR_UI_INT(dq_len),
1486 SILC_STR_UI_XNSTRING(dqb, dq_len),
1487 SILC_STR_UI_INT(qp_len),
1488 SILC_STR_UI_XNSTRING(qpb, qp_len),
1489 SILC_STR_UI_INT(p_len),
1490 SILC_STR_UI_XNSTRING(pb, p_len),
1491 SILC_STR_UI_INT(q_len),
1492 SILC_STR_UI_XNSTRING(qb, q_len),
1496 key = silc_buffer_steal(buf, &key_len);
1497 silc_buffer_free(buf);
1507 } else if (!strcmp(pkcs->name, "dsa")) {
1508 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1512 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1516 /* Encode SILC private key */
1517 totlen = 2 + strlen(pkcs->name) + key_len;
1518 buf = silc_buffer_alloc_size(totlen);
1521 if (silc_buffer_format(buf,
1522 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1523 SILC_STR_UI32_STRING(pkcs->name),
1524 SILC_STR_UI_XNSTRING(key, key_len),
1528 ret = silc_buffer_steal(buf, ret_len);
1529 silc_buffer_free(buf);
1532 silc_asn1_free(asn1);
1540 silc_buffer_free(buf);
1544 /* Return key length */
1546 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1548 SilcSILCPrivateKey silc_privkey = private_key;
1549 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1552 /* Frees private key */
1554 void silc_pkcs_silc_private_key_free(void *private_key)
1556 SilcSILCPrivateKey silc_privkey = private_key;
1558 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1560 silc_free(silc_privkey);
1564 /***************************** PKCS operations ******************************/
1566 /* Encrypts as specified in SILC protocol specification */
1568 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1572 SilcUInt32 dst_size,
1573 SilcUInt32 *ret_dst_len,
1576 SilcSILCPublicKey silc_pubkey = public_key;
1578 if (!silc_pubkey->pkcs->encrypt)
1581 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1583 dst, dst_size, ret_dst_len, rng);
1586 /* Decrypts as specified in SILC protocol specification */
1588 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1592 SilcUInt32 dst_size,
1593 SilcUInt32 *ret_dst_len)
1595 SilcSILCPrivateKey silc_privkey = private_key;
1597 if (!silc_privkey->pkcs->decrypt)
1600 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1602 dst, dst_size, ret_dst_len);
1605 /* Signs as specified in SILC protocol specification */
1607 SilcBool silc_pkcs_silc_sign(void *private_key,
1610 unsigned char *signature,
1611 SilcUInt32 signature_size,
1612 SilcUInt32 *ret_signature_len,
1613 SilcBool compute_hash,
1616 SilcSILCPrivateKey silc_privkey = private_key;
1618 if (!silc_privkey->pkcs->sign)
1621 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1623 signature, signature_size,
1624 ret_signature_len, compute_hash, hash);
1627 /* Verifies as specified in SILC protocol specification */
1629 SilcBool silc_pkcs_silc_verify(void *public_key,
1630 unsigned char *signature,
1631 SilcUInt32 signature_len,
1632 unsigned char *data,
1633 SilcUInt32 data_len,
1636 SilcSILCPublicKey silc_pubkey = public_key;
1638 if (!silc_pubkey->pkcs->verify)
1641 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1642 signature, signature_len,
1643 data, data_len, hash);