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 = (SilcPKCSObject *)pkcs;
89 (*ret_public_key)->alg = alg;
90 (*ret_public_key)->public_key = pubkey;
92 /* Allocate private key */
93 *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
94 if (!(*ret_private_key)) {
97 silc_free(*ret_public_key);
100 (*ret_private_key)->pkcs = (SilcPKCSObject *)pkcs;
101 (*ret_private_key)->alg = alg;
102 (*ret_private_key)->private_key = privkey;
104 /* Generate the algorithm key pair */
105 if (!alg->generate_key(alg, bits_key_len, rng, &pubkey->public_key,
106 &privkey->private_key)) {
109 silc_free(*ret_public_key);
110 silc_free(*ret_private_key);
118 /**************************** Utility functions ******************************/
120 /* Decodes the provided `identifier' */
122 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
123 SilcPublicKeyIdentifier ident)
128 /* Protocol says that at least UN and HN must be provided as identifier */
129 if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
130 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
135 cp = (char *)identifier;
137 len = strcspn(cp, ",");
142 if (len - 1 >= 0 && cp[len - 1] == '\\') {
144 if (len + 1 > strlen(cp)) {
149 len = strcspn(cp, ",") + len;
154 if (len - 1 >= 0 && cp[len - 1] != '\\')
162 item = silc_calloc(len + 1, sizeof(char));
165 if (len > strlen(cp))
167 memcpy(item, cp, len);
169 if (strstr(item, "UN="))
170 ident->username = strdup(item + strcspn(cp, "=") + 1);
171 else if (strstr(item, "HN="))
172 ident->host = strdup(item + strcspn(cp, "=") + 1);
173 else if (strstr(item, "RN="))
174 ident->realname = strdup(item + strcspn(cp, "=") + 1);
175 else if (strstr(item, "E="))
176 ident->email = strdup(item + strcspn(cp, "=") + 1);
177 else if (strstr(item, "O="))
178 ident->org = strdup(item + strcspn(cp, "=") + 1);
179 else if (strstr(item, "C="))
180 ident->country = strdup(item + strcspn(cp, "=") + 1);
181 else if (strstr(item, "V="))
182 ident->version = strdup(item + strcspn(cp, "=") + 1);
197 /* Encodes and returns SILC public key identifier. If some of the
198 arguments is NULL those are not encoded into the identifier string.
199 Protocol says that at least username and host must be provided. */
201 char *silc_pkcs_silc_encode_identifier(SilcStack stack,
202 char *username, char *host,
203 char *realname, char *email,
204 char *org, char *country,
207 SilcBufferStruct buf;
210 if (!username || !host) {
211 SILC_LOG_ERROR(("Public key identifier is missing UN and/or HN"));
214 if (strlen(username) < 1 || strlen(host) < 1)
217 memset(&buf, 0, sizeof(buf));
220 silc_buffer_sformat(stack, &buf,
222 SILC_STR_UI32_STRING("UN="),
223 SILC_STR_UI32_STRING(username),
227 silc_buffer_sformat(stack, &buf,
229 SILC_STR_UI32_STRING(", "),
230 SILC_STR_UI32_STRING("HN="),
231 SILC_STR_UI32_STRING(host),
235 silc_buffer_sformat(stack, &buf,
237 SILC_STR_UI32_STRING(", "),
238 SILC_STR_UI32_STRING("RN="),
239 SILC_STR_UI32_STRING(realname),
243 silc_buffer_sformat(stack, &buf,
245 SILC_STR_UI32_STRING(", "),
246 SILC_STR_UI32_STRING("E="),
247 SILC_STR_UI32_STRING(email),
251 silc_buffer_sformat(stack, &buf,
253 SILC_STR_UI32_STRING(", "),
254 SILC_STR_UI32_STRING("O="),
255 SILC_STR_UI32_STRING(org),
259 silc_buffer_sformat(stack, &buf,
261 SILC_STR_UI32_STRING(", "),
262 SILC_STR_UI32_STRING("C="),
263 SILC_STR_UI32_STRING(country),
267 if (strlen(version) > 1 || !isdigit(version[0])) {
268 silc_buffer_spurge(stack, &buf);
269 SILC_LOG_ERROR(("Public key identifier has invalid version (V)"));
272 silc_buffer_sformat(stack, &buf,
274 SILC_STR_UI32_STRING(", "),
275 SILC_STR_UI32_STRING("V="),
276 SILC_STR_UI32_STRING(version),
280 silc_buffer_sformat(stack, &buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
282 identifier = silc_buffer_steal(&buf, NULL);
286 /* Return SILC public key version */
288 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
290 SilcSILCPublicKey silc_pubkey;
292 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
295 silc_pubkey = public_key->public_key;
297 /* If version identifire is not present it is version 1. */
298 if (!silc_pubkey->identifier.version)
301 return atoi(silc_pubkey->identifier.version);
304 /*************************** Public key routines *****************************/
306 /* Returns PKCS algorithm context */
308 SILC_PKCS_GET_ALGORITHM(silc_pkcs_silc_get_algorithm)
310 SilcSILCPublicKey silc_pubkey = public_key;
311 return silc_pubkey->pkcs;
314 /* Imports SILC protocol style public key from SILC public key file */
316 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_import_public_key_file)
319 unsigned char *data = NULL;
322 SILC_LOG_DEBUG(("Parsing SILC public key file"));
327 /* Check start of file and remove header from the data. */
328 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
329 if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) {
330 SILC_LOG_DEBUG(("Malformed SILC public key header"));
333 for (i = 0; i < len; i++) {
334 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
335 SILC_LOG_DEBUG(("Malformed SILC public key header"));
340 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
341 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
344 case SILC_PKCS_FILE_BIN:
347 case SILC_PKCS_FILE_BASE64:
348 data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len);
355 ret = silc_pkcs_silc_import_public_key(pkcs, NULL, filedata, filedata_len,
356 ret_public_key, ret_alg);
359 return ret ? TRUE : FALSE;
362 /* Imports SILC protocol style public key */
364 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_silc_import_public_key)
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(NULL);
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 alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
447 /* Version 2 and newer */
448 alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
451 SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
454 silc_pubkey->pkcs = alg;
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 (!alg->import_public_key(alg, 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;
514 silc_free(pkcs_name);
516 silc_free(silc_pubkey);
518 silc_asn1_free(asn1);
522 /* Exports public key as SILC protocol style public key file */
524 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_export_public_key_file)
527 unsigned char *key, *data;
530 SILC_LOG_DEBUG(("Encoding SILC public key file"));
533 key = silc_pkcs_silc_export_public_key(pkcs, stack, public_key, &key_len);
538 case SILC_PKCS_FILE_BIN:
541 case SILC_PKCS_FILE_BASE64:
542 data = silc_base64_encode_file(stack, key, key_len);
545 silc_sfree(stack, key);
547 key_len = strlen(data);
551 /* Encode SILC public key file */
552 buf = silc_buffer_salloc_size(stack, key_len +
553 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
554 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
556 silc_sfree(stack, key);
560 if (silc_buffer_sformat(stack, buf,
561 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
562 SILC_STR_UI_XNSTRING(key, key_len),
563 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
565 silc_buffer_sfree(stack, buf);
566 silc_sfree(stack, key);
570 silc_sfree(stack, key);
571 key = silc_buffer_steal(buf, ret_len);
572 silc_buffer_sfree(stack, buf);
577 /* Exports public key as SILC protocol style public key */
579 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_silc_export_public_key)
581 SilcSILCPublicKey silc_pubkey = public_key;
582 const SilcPKCSAlgorithm *alg = silc_pubkey->pkcs;
583 SilcBufferStruct alg_key;
584 SilcBuffer buf = NULL;
585 SilcAsn1 asn1 = NULL;
586 unsigned char *pk = NULL, *key = NULL, *ret;
587 SilcUInt32 pk_len, key_len, totlen;
590 SILC_LOG_DEBUG(("Encoding SILC public key"));
592 /* Export PKCS algorithm public key */
593 if (alg->export_public_key)
594 pk = alg->export_public_key(alg, stack, silc_pubkey->public_key, &pk_len);
596 SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
599 silc_buffer_set(&alg_key, pk, pk_len);
601 /* Encode identifier */
603 silc_pkcs_silc_encode_identifier(stack,
604 silc_pubkey->identifier.username,
605 silc_pubkey->identifier.host,
606 silc_pubkey->identifier.realname,
607 silc_pubkey->identifier.email,
608 silc_pubkey->identifier.org,
609 silc_pubkey->identifier.country,
610 silc_pubkey->identifier.version);
612 SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
616 asn1 = silc_asn1_alloc(stack);
620 if (!strcmp(alg->name, "rsa")) {
621 /* Parse the PKCS #1 public key */
623 SilcUInt32 n_len, e_len;
624 unsigned char *nb, *eb;
626 memset(&n, 0, sizeof(n));
627 memset(&e, 0, sizeof(e));
628 if (!silc_asn1_decode(asn1, &alg_key,
632 SILC_ASN1_END, SILC_ASN1_END))
635 /* Encode to SILC RSA public key */
636 eb = silc_mp_mp2bin(&e, 0, &e_len);
639 nb = silc_mp_mp2bin(&n, 0, &n_len);
642 key_len = e_len + 4 + n_len + 4;
643 key = silc_scalloc(stack, key_len, sizeof(*key));
647 /* Put e length and e */
648 SILC_PUT32_MSB(e_len, key);
649 memcpy(key + 4, eb, e_len);
651 /* Put n length and n. */
652 SILC_PUT32_MSB(n_len, key + 4 + e_len);
653 memcpy(key + 4 + e_len + 4, nb, n_len);
658 } else if (!strcmp(alg->name, "dsa")) {
659 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
663 SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", alg->name));
667 /* Encode SILC Public Key */
668 totlen = 2 + strlen(alg->name) + 2 + strlen(identifier) + key_len;
669 buf = silc_buffer_salloc_size(stack, totlen + 4);
672 if (silc_buffer_sformat(stack, buf,
673 SILC_STR_UI_INT(totlen),
674 SILC_STR_UI_SHORT(strlen(alg->name)),
675 SILC_STR_UI32_STRING(alg->name),
676 SILC_STR_UI_SHORT(strlen(identifier)),
677 SILC_STR_UI32_STRING(identifier),
678 SILC_STR_UI_XNSTRING(key, key_len),
682 ret = silc_buffer_steal(buf, ret_len);
683 silc_buffer_sfree(stack, buf);
684 silc_sfree(stack, key);
685 silc_sfree(stack, identifier);
686 silc_buffer_spurge(stack, &alg_key);
687 silc_asn1_free(asn1);
692 silc_sfree(stack, identifier);
693 silc_sfree(stack, pk);
694 silc_sfree(stack, key);
695 silc_buffer_sfree(stack, buf);
697 silc_asn1_free(asn1);
701 /* Return key length */
703 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_silc_public_key_bitlen)
705 SilcSILCPublicKey silc_pubkey = public_key;
706 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->pkcs,
707 silc_pubkey->public_key);
710 /* Copy public key */
712 SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_silc_public_key_copy)
714 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
715 SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
717 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
720 new_pubkey->pkcs = silc_pubkey->pkcs;
722 new_pubkey->public_key =
723 silc_pubkey->pkcs->public_key_copy(silc_pubkey->pkcs,
724 silc_pubkey->public_key);
725 if (!new_pubkey->public_key) {
726 silc_free(new_pubkey);
731 new_pubkey->identifier.username =
732 silc_memdup(ident->username, strlen(ident->username));
734 new_pubkey->identifier.host =
735 silc_memdup(ident->host, strlen(ident->host));
737 new_pubkey->identifier.realname =
738 silc_memdup(ident->realname, strlen(ident->realname));
740 new_pubkey->identifier.email =
741 silc_memdup(ident->email, strlen(ident->email));
743 new_pubkey->identifier.org =
744 silc_memdup(ident->org, strlen(ident->org));
746 new_pubkey->identifier.country =
747 silc_memdup(ident->country, strlen(ident->country));
749 new_pubkey->identifier.version =
750 silc_memdup(ident->version, strlen(ident->version));
755 /* Compares public keys */
757 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_silc_public_key_compare)
759 SilcSILCPublicKey k1 = key1, k2 = key2;
761 if (strcmp(k1->pkcs->name, k2->pkcs->name))
764 if ((k1->identifier.username && !k2->identifier.username) ||
765 (!k1->identifier.username && k2->identifier.username) ||
766 (k1->identifier.username && k2->identifier.username &&
767 strcmp(k1->identifier.username, k2->identifier.username)))
770 if ((k1->identifier.host && !k2->identifier.host) ||
771 (!k1->identifier.host && k2->identifier.host) ||
772 (k1->identifier.host && k2->identifier.host &&
773 strcmp(k1->identifier.host, k2->identifier.host)))
776 if ((k1->identifier.realname && !k2->identifier.realname) ||
777 (!k1->identifier.realname && k2->identifier.realname) ||
778 (k1->identifier.realname && k2->identifier.realname &&
779 strcmp(k1->identifier.realname, k2->identifier.realname)))
782 if ((k1->identifier.email && !k2->identifier.email) ||
783 (!k1->identifier.email && k2->identifier.email) ||
784 (k1->identifier.email && k2->identifier.email &&
785 strcmp(k1->identifier.email, k2->identifier.email)))
788 if ((k1->identifier.org && !k2->identifier.org) ||
789 (!k1->identifier.org && k2->identifier.org) ||
790 (k1->identifier.org && k2->identifier.org &&
791 strcmp(k1->identifier.org, k2->identifier.org)))
794 if ((k1->identifier.country && !k2->identifier.country) ||
795 (!k1->identifier.country && k2->identifier.country) ||
796 (k1->identifier.country && k2->identifier.country &&
797 strcmp(k1->identifier.country, k2->identifier.country)))
800 if ((k1->identifier.version && !k2->identifier.version) ||
801 (!k1->identifier.version && k2->identifier.version) ||
802 (k1->identifier.version && k2->identifier.version &&
803 strcmp(k1->identifier.version, k2->identifier.version)))
806 return k1->pkcs->public_key_compare(k1->pkcs, k1->public_key, k2->public_key);
809 /* Frees public key */
811 SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_silc_public_key_free)
813 SilcSILCPublicKey silc_pubkey = public_key;
815 silc_pubkey->pkcs->public_key_free(silc_pubkey->pkcs,
816 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 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_import_private_key_file)
842 unsigned char tmp[32], keymat[64], *data = NULL;
843 SilcUInt32 i, len, magic, mac_len;
846 SILC_LOG_DEBUG(("Parsing SILC private key file"));
848 /* Check start of file and remove header from the data. */
849 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
850 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
851 SILC_LOG_DEBUG(("Malformed SILC private key header"));
854 for (i = 0; i < len; i++) {
855 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
856 SILC_LOG_DEBUG(("Malformed SILC private key header"));
862 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
863 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
866 case SILC_PKCS_FILE_BIN:
869 case SILC_PKCS_FILE_BASE64:
870 data = silc_base64_decode(NULL, filedata, filedata_len, &len);
877 memset(tmp, 0, sizeof(tmp));
878 memset(keymat, 0, sizeof(keymat));
880 /* Check file magic */
881 SILC_GET32_MSB(magic, filedata);
882 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
883 SILC_LOG_DEBUG(("Private key does not have correct magic"));
887 /* Allocate the AES cipher */
888 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
889 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
892 blocklen = silc_cipher_get_block_len(aes);
893 if (blocklen * 2 > sizeof(tmp)) {
894 silc_cipher_free(aes);
898 /* Allocate SHA1 hash */
899 if (!silc_hash_alloc("sha1", &sha1)) {
900 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
901 silc_cipher_free(aes);
906 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
907 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
908 silc_hash_free(sha1);
909 silc_cipher_free(aes);
913 /* Derive the decryption key from the provided key material. The key
914 is 256 bits length, and derived by taking hash of the data, then
915 re-hashing the data and the previous digest, and using the first and
916 second digest as the key. */
917 silc_hash_init(sha1);
918 silc_hash_update(sha1, passphrase, passphrase_len);
919 silc_hash_final(sha1, keymat);
920 silc_hash_init(sha1);
921 silc_hash_update(sha1, passphrase, passphrase_len);
922 silc_hash_update(sha1, keymat, 16);
923 silc_hash_final(sha1, keymat + 16);
925 /* Set the key to the cipher */
926 silc_cipher_set_key(aes, keymat, 256, FALSE);
928 /* First, verify the MAC of the private key data */
929 mac_len = silc_hmac_len(sha1hmac);
930 silc_hmac_init_with_key(sha1hmac, keymat, 16);
931 silc_hmac_update(sha1hmac, filedata, len - mac_len);
932 silc_hmac_final(sha1hmac, tmp, NULL);
933 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
934 SILC_LOG_DEBUG(("Integrity check for private key failed"));
935 memset(keymat, 0, sizeof(keymat));
936 memset(tmp, 0, sizeof(tmp));
937 silc_hmac_free(sha1hmac);
938 silc_hash_free(sha1);
939 silc_cipher_free(aes);
945 /* Decrypt the private key buffer */
946 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
947 SILC_GET32_MSB(i, filedata);
949 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
950 memset(keymat, 0, sizeof(keymat));
951 memset(tmp, 0, sizeof(tmp));
952 silc_hmac_free(sha1hmac);
953 silc_hash_free(sha1);
954 silc_cipher_free(aes);
961 memset(keymat, 0, sizeof(keymat));
962 memset(tmp, 0, sizeof(tmp));
963 silc_hmac_free(sha1hmac);
964 silc_hash_free(sha1);
965 silc_cipher_free(aes);
967 /* Import the private key */
968 ret = silc_pkcs_silc_import_private_key(pkcs, NULL, filedata,
969 len, ret_private_key, ret_alg);
973 return ret ? TRUE : FALSE;
976 /* Private key version */
977 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
978 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
980 /* Imports SILC implementation style private key */
982 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_silc_import_private_key)
984 SilcBufferStruct buf;
985 SilcBufferStruct alg_key;
986 SilcSILCPrivateKey silc_privkey = NULL;
987 SilcAsn1 asn1 = NULL;
989 SilcUInt32 keydata_len;
990 unsigned char *pkcs_name = NULL, *key_data;
993 SILC_LOG_DEBUG(("Parsing SILC private key"));
995 if (!ret_private_key)
998 silc_buffer_set(&buf, (unsigned char *)key, key_len);
1000 /* Get algorithm name and identifier */
1002 silc_buffer_unformat(&buf,
1003 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1006 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1010 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1011 SILC_LOG_DEBUG(("Malformed private key buffer"));
1015 /* Get key data. We assume that rest of the buffer is key data. */
1016 silc_buffer_pull(&buf, 2 + pkcs_len);
1017 keydata_len = silc_buffer_len(&buf);
1018 ret = silc_buffer_unformat(&buf,
1019 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1024 /* Allocate SILC private key context */
1025 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1029 asn1 = silc_asn1_alloc(NULL);
1033 if (!strcmp(pkcs_name, "rsa")) {
1034 /* Parse the RSA SILC private key */
1036 SilcMPInt n, e, d, dp, dq, qp, p, q;
1038 SilcUInt32 len, ver;
1040 if (keydata_len < 4)
1042 silc_buffer_set(&k, key_data, keydata_len);
1044 /* Get version. Key without the version is old style private key
1045 and we need to do some computation to get it to correct format. */
1046 if (silc_buffer_unformat(&k,
1047 SILC_STR_UI_INT(&ver),
1050 silc_buffer_pull(&k, 4);
1052 if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1053 ver != SILC_PRIVATE_KEY_VERSION_2) {
1057 if (silc_buffer_unformat(&k,
1058 SILC_STR_UI_INT(&len),
1061 silc_buffer_pull(&k, 4);
1064 /* Get PKCS object. Different PKCS #1 scheme is used with different
1066 if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1067 /* Version 0 and 1 */
1068 alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1070 /* Version 2 and newer */
1071 alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1074 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1077 silc_privkey->pkcs = alg;
1079 SILC_LOG_DEBUG(("Private key version %s",
1080 (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1081 ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1084 if (silc_buffer_unformat(&k,
1085 SILC_STR_DATA(&tmp, len),
1089 silc_mp_bin2mp(tmp, len, &e);
1090 silc_buffer_pull(&k, len);
1093 if (silc_buffer_unformat(&k,
1094 SILC_STR_UI_INT(&len),
1097 silc_buffer_pull(&k, 4);
1098 if (silc_buffer_unformat(&k,
1099 SILC_STR_DATA(&tmp, len),
1103 silc_mp_bin2mp(tmp, len, &n);
1104 silc_buffer_pull(&k, len);
1107 if (silc_buffer_unformat(&k,
1108 SILC_STR_UI_INT(&len),
1111 silc_buffer_pull(&k, 4);
1112 if (silc_buffer_unformat(&k,
1113 SILC_STR_DATA(&tmp, len),
1117 silc_mp_bin2mp(tmp, len, &d);
1118 silc_buffer_pull(&k, len);
1121 if (silc_buffer_unformat(&k,
1122 SILC_STR_UI_INT(&len),
1125 silc_buffer_pull(&k, 4);
1126 if (silc_buffer_unformat(&k,
1127 SILC_STR_DATA(&tmp, len),
1131 silc_mp_bin2mp(tmp, len, &dp);
1132 silc_buffer_pull(&k, len);
1135 if (silc_buffer_unformat(&k,
1136 SILC_STR_UI_INT(&len),
1139 silc_buffer_pull(&k, 4);
1140 if (silc_buffer_unformat(&k,
1141 SILC_STR_DATA(&tmp, len),
1145 silc_mp_bin2mp(tmp, len, &dq);
1146 silc_buffer_pull(&k, len);
1152 if (silc_buffer_unformat(&k,
1153 SILC_STR_UI_INT(&len),
1156 silc_buffer_pull(&k, 4);
1157 if (silc_buffer_len(&k) < len)
1159 silc_buffer_pull(&k, len);
1162 if (silc_buffer_unformat(&k,
1163 SILC_STR_UI_INT(&len),
1166 silc_buffer_pull(&k, 4);
1167 if (silc_buffer_len(&k) < len)
1169 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, &qp);
1185 silc_buffer_pull(&k, len);
1189 if (silc_buffer_unformat(&k,
1190 SILC_STR_UI_INT(&len),
1193 silc_buffer_pull(&k, 4);
1194 if (silc_buffer_unformat(&k,
1195 SILC_STR_DATA(&tmp, len),
1199 silc_mp_bin2mp(tmp, len, &p);
1200 silc_buffer_pull(&k, len);
1203 if (silc_buffer_unformat(&k,
1204 SILC_STR_UI_INT(&len),
1207 silc_buffer_pull(&k, 4);
1208 if (silc_buffer_unformat(&k,
1209 SILC_STR_DATA(&tmp, len),
1213 silc_mp_bin2mp(tmp, len, &q);
1214 silc_buffer_pull(&k, len);
1217 /* Old version. Compute to new version */
1218 SILC_LOG_DEBUG(("Old version private key"));
1220 silc_mp_modinv(&qp, &q, &p);
1223 /* Encode to PKCS #1 format */
1224 memset(&alg_key, 0, sizeof(alg_key));
1225 if (!silc_asn1_encode(asn1, &alg_key,
1227 SILC_ASN1_SHORT_INT(0),
1236 SILC_ASN1_END, SILC_ASN1_END))
1245 silc_mp_uninit(&dp);
1246 silc_mp_uninit(&dq);
1247 silc_mp_uninit(&qp);
1249 } else if (!strcmp(pkcs_name, "dsa")) {
1250 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1254 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1258 /* Import PKCS algorithm private key */
1259 if (!alg->import_private_key(alg, alg_key.data, silc_buffer_len(&alg_key),
1260 &silc_privkey->private_key))
1263 silc_free(pkcs_name);
1264 silc_asn1_free(asn1);
1266 *ret_private_key = silc_privkey;
1272 silc_free(pkcs_name);
1273 silc_free(silc_privkey);
1275 silc_asn1_free(asn1);
1276 SILC_LOG_ERROR(("Malformed SILC private key "));
1280 /* Exports private key as SILC implementation style private key file */
1282 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_export_private_key_file)
1287 SilcBuffer buf, enc;
1288 SilcUInt32 len, blocklen, padlen, key_len;
1289 unsigned char *key, *data;
1290 unsigned char tmp[32], keymat[64];
1293 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1295 /* Export the private key */
1296 key = silc_pkcs_silc_export_private_key(pkcs, stack, private_key, &key_len);
1300 memset(tmp, 0, sizeof(tmp));
1301 memset(keymat, 0, sizeof(keymat));
1303 /* Allocate the AES cipher */
1304 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1305 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1306 silc_sfree(stack, key);
1309 blocklen = silc_cipher_get_block_len(aes);
1310 if (blocklen * 2 > sizeof(tmp)) {
1311 silc_cipher_free(aes);
1312 silc_sfree(stack, key);
1316 /* Allocate SHA1 hash */
1317 if (!silc_hash_alloc("sha1", &sha1)) {
1318 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1319 silc_sfree(stack, key);
1320 silc_cipher_free(aes);
1325 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1326 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1327 silc_sfree(stack, key);
1328 silc_hash_free(sha1);
1329 silc_cipher_free(aes);
1333 /* Derive the encryption key from the provided key material. The key
1334 is 256 bits length, and derived by taking hash of the data, then
1335 re-hashing the data and the previous digest, and using the first and
1336 second digest as the key. */
1337 silc_hash_init(sha1);
1338 silc_hash_update(sha1, passphrase, passphrase_len);
1339 silc_hash_final(sha1, keymat);
1340 silc_hash_init(sha1);
1341 silc_hash_update(sha1, passphrase, passphrase_len);
1342 silc_hash_update(sha1, keymat, 16);
1343 silc_hash_final(sha1, keymat + 16);
1345 /* Set the key to the cipher */
1346 silc_cipher_set_key(aes, keymat, 256, TRUE);
1348 /* Encode the buffer to be encrypted. Add padding to it too, at least
1349 block size of the cipher. */
1351 /* Allocate buffer for encryption */
1352 len = silc_hmac_len(sha1hmac);
1353 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1354 enc = silc_buffer_salloc_size(stack, 4 + 4 + key_len + padlen + len);
1356 silc_sfree(stack, key);
1357 silc_hmac_free(sha1hmac);
1358 silc_hash_free(sha1);
1359 silc_cipher_free(aes);
1363 /* Generate padding */
1364 for (i = 0; i < padlen; i++)
1365 tmp[i] = silc_rng_get_byte_fast(rng);
1367 /* Put magic number */
1368 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1369 silc_buffer_pull(enc, 4);
1371 /* Encode the buffer */
1372 silc_buffer_sformat(stack, enc,
1373 SILC_STR_UI_INT(key_len),
1374 SILC_STR_UI_XNSTRING(key, key_len),
1375 SILC_STR_UI_XNSTRING(tmp, padlen),
1377 silc_sfree(stack, key);
1380 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1381 silc_cipher_get_iv(aes));
1383 silc_buffer_push(enc, 4);
1385 /* Compute HMAC over the encrypted data and append the MAC to data.
1386 The key is the first digest of the original key material. */
1387 key_len = silc_buffer_len(enc) - len;
1388 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1389 silc_hmac_update(sha1hmac, enc->data, key_len);
1390 silc_buffer_pull(enc, key_len);
1391 silc_hmac_final(sha1hmac, enc->data, NULL);
1392 silc_buffer_push(enc, key_len);
1395 memset(keymat, 0, sizeof(keymat));
1396 memset(tmp, 0, sizeof(tmp));
1397 silc_hmac_free(sha1hmac);
1398 silc_hash_free(sha1);
1399 silc_cipher_free(aes);
1402 case SILC_PKCS_FILE_BIN:
1405 case SILC_PKCS_FILE_BASE64:
1406 data = silc_base64_encode_file(stack, enc->data, silc_buffer_len(enc));
1408 silc_buffer_clear(enc);
1409 silc_buffer_sfree(stack, enc);
1412 silc_sfree(stack, silc_buffer_steal(enc, NULL));
1413 silc_buffer_set(enc, data, strlen(data));
1418 key_len = silc_buffer_len(enc);
1420 /* Encode the data and save to file */
1421 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1422 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1423 buf = silc_buffer_salloc_size(stack, len);
1425 silc_buffer_sfree(stack, enc);
1428 silc_buffer_sformat(stack, buf,
1429 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1430 SILC_STR_UI_XNSTRING(key, key_len),
1431 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1434 silc_buffer_sfree(stack, enc);
1435 data = silc_buffer_steal(buf, ret_len);
1436 silc_buffer_sfree(stack, buf);
1441 /* Exports private key as SILC implementation style private key */
1443 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_silc_export_private_key)
1445 SilcSILCPrivateKey silc_privkey = private_key;
1446 const SilcPKCSAlgorithm *alg = silc_privkey->pkcs;
1447 SilcBufferStruct alg_key;
1448 SilcBuffer buf = NULL;
1449 SilcAsn1 asn1 = NULL;
1450 unsigned char *prv = NULL, *key = NULL, *ret;
1451 SilcUInt32 prv_len, key_len, totlen;
1453 SILC_LOG_DEBUG(("Encoding SILC private key"));
1455 /* Export PKCS algorithm private key */
1456 if (alg->export_private_key)
1457 prv = alg->export_private_key(alg, stack,
1458 silc_privkey->private_key, &prv_len);
1461 silc_buffer_set(&alg_key, prv, prv_len);
1463 asn1 = silc_asn1_alloc(stack);
1467 if (!strcmp(alg->name, "rsa")) {
1468 /* Parse the PKCS #1 private key */
1469 SilcMPInt n, e, d, dp, dq, qp, p, q;
1470 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1471 qp_len, p_len, q_len, len = 0;
1472 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1474 if (!silc_asn1_decode(asn1, &alg_key,
1476 SILC_ASN1_INT(NULL),
1485 SILC_ASN1_END, SILC_ASN1_END))
1488 /* Encode to SILC RSA private key */
1489 eb = silc_mp_mp2bin(&e, 0, &e_len);
1490 nb = silc_mp_mp2bin(&n, 0, &n_len);
1491 db = silc_mp_mp2bin(&d, 0, &d_len);
1492 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1493 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1494 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1495 pb = silc_mp_mp2bin(&p, 0, &p_len);
1496 qb = silc_mp_mp2bin(&q, 0, &q_len);
1497 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1498 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1500 buf = silc_buffer_salloc_size(stack, len);
1503 if (silc_buffer_sformat(stack, buf,
1504 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1505 SILC_STR_UI_INT(e_len),
1506 SILC_STR_UI_XNSTRING(eb, e_len),
1507 SILC_STR_UI_INT(n_len),
1508 SILC_STR_UI_XNSTRING(nb, n_len),
1509 SILC_STR_UI_INT(d_len),
1510 SILC_STR_UI_XNSTRING(db, d_len),
1511 SILC_STR_UI_INT(dp_len),
1512 SILC_STR_UI_XNSTRING(dpb, dp_len),
1513 SILC_STR_UI_INT(dq_len),
1514 SILC_STR_UI_XNSTRING(dqb, dq_len),
1515 SILC_STR_UI_INT(qp_len),
1516 SILC_STR_UI_XNSTRING(qpb, qp_len),
1517 SILC_STR_UI_INT(p_len),
1518 SILC_STR_UI_XNSTRING(pb, p_len),
1519 SILC_STR_UI_INT(q_len),
1520 SILC_STR_UI_XNSTRING(qb, q_len),
1524 key = silc_buffer_steal(buf, &key_len);
1525 silc_buffer_sfree(stack, buf);
1535 } else if (!strcmp(alg->name, "dsa")) {
1536 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1540 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1544 /* Encode SILC private key */
1545 totlen = 2 + strlen(alg->name) + key_len;
1546 buf = silc_buffer_salloc_size(stack, totlen);
1549 if (silc_buffer_sformat(stack, buf,
1550 SILC_STR_UI_SHORT(strlen(alg->name)),
1551 SILC_STR_UI32_STRING(alg->name),
1552 SILC_STR_UI_XNSTRING(key, key_len),
1556 ret = silc_buffer_steal(buf, ret_len);
1557 silc_buffer_sfree(stack, buf);
1558 silc_sfree(stack, prv);
1559 silc_sfree(stack, key);
1560 silc_asn1_free(asn1);
1565 silc_sfree(stack, prv);
1566 silc_sfree(stack, key);
1567 silc_buffer_sfree(stack, buf);
1571 /* Return key length */
1573 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_silc_private_key_bitlen)
1575 SilcSILCPrivateKey silc_privkey = private_key;
1576 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->pkcs,
1577 silc_privkey->private_key);
1580 /* Frees private key */
1582 SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_silc_private_key_free)
1584 SilcSILCPrivateKey silc_privkey = private_key;
1586 silc_privkey->pkcs->private_key_free(silc_privkey->pkcs,
1587 silc_privkey->private_key);
1588 silc_free(silc_privkey);
1592 /***************************** PKCS operations ******************************/
1594 /* Encrypts as specified in SILC protocol specification */
1596 SILC_PKCS_ENCRYPT(silc_pkcs_silc_encrypt)
1598 SilcSILCPublicKey silc_pubkey = public_key;
1600 if (!silc_pubkey->pkcs->encrypt) {
1601 encrypt_cb(FALSE, NULL, 0, context);
1605 return silc_pubkey->pkcs->encrypt(silc_pubkey->pkcs,
1606 silc_pubkey->public_key,
1607 src, src_len, rng, encrypt_cb, context);
1610 /* Decrypts as specified in SILC protocol specification */
1612 SILC_PKCS_DECRYPT(silc_pkcs_silc_decrypt)
1614 SilcSILCPrivateKey silc_privkey = private_key;
1616 if (!silc_privkey->pkcs->decrypt) {
1617 decrypt_cb(FALSE, NULL, 0, context);
1621 return silc_privkey->pkcs->decrypt(silc_privkey->pkcs,
1622 silc_privkey->private_key,
1623 src, src_len, decrypt_cb, context);
1626 /* Signs as specified in SILC protocol specification */
1628 SILC_PKCS_SIGN(silc_pkcs_silc_sign)
1630 SilcSILCPrivateKey silc_privkey = private_key;
1632 if (!silc_privkey->pkcs->sign) {
1633 sign_cb(FALSE, NULL, 0, context);
1637 return silc_privkey->pkcs->sign(silc_privkey->pkcs,
1638 silc_privkey->private_key,
1640 compute_hash, hash, rng,
1644 /* Verifies as specified in SILC protocol specification */
1646 SILC_PKCS_VERIFY(silc_pkcs_silc_verify)
1648 SilcSILCPublicKey silc_pubkey = public_key;
1650 if (!silc_pubkey->pkcs->verify) {
1651 verify_cb(FALSE, context);
1655 return silc_pubkey->pkcs->verify(silc_pubkey->pkcs,
1656 silc_pubkey->public_key,
1657 signature, signature_len,
1658 data, data_len, hash, rng,
1659 verify_cb, context);