5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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,
29 SilcUInt32 bits_key_len,
30 const char *identifier,
32 SilcPublicKey *ret_public_key,
33 SilcPrivateKey *ret_private_key)
35 SilcSILCPublicKey pubkey;
36 SilcSILCPrivateKey privkey;
37 const SilcPKCSAlgorithm *alg;
38 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 alg = silc_pkcs_find_algorithm(algorithm, scheme);
54 /* Allocate SILC public key */
55 pubkey = silc_calloc(1, sizeof(*pubkey));
60 /* Decode identifier */
61 if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier)) {
66 /* Allocate SILC private key */
67 privkey = silc_calloc(1, sizeof(*privkey));
74 /* Allocate public key */
75 *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
76 if (!(*ret_public_key)) {
81 (*ret_public_key)->pkcs = pkcs;
82 (*ret_public_key)->public_key = pubkey;
84 /* Allocate private key */
85 *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
86 if (!(*ret_private_key)) {
89 silc_free(*ret_public_key);
92 (*ret_private_key)->pkcs = pkcs;
93 (*ret_private_key)->private_key = privkey;
95 /* Generate the algorithm key pair */
96 if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
97 &privkey->private_key)) {
100 silc_free(*ret_public_key);
101 silc_free(*ret_private_key);
109 /**************************** Utility functions ******************************/
111 /* Decodes the provided `identifier' */
113 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
114 SilcPublicKeyIdentifier ident)
119 /* Protocol says that at least UN and HN must be provided as identifier */
120 if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
121 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
126 cp = (char *)identifier;
128 len = strcspn(cp, ",");
133 if (len - 1 >= 0 && cp[len - 1] == '\\') {
135 if (len + 1 > strlen(cp)) {
140 len = strcspn(cp, ",") + len;
145 if (len - 1 >= 0 && cp[len - 1] != '\\')
153 item = silc_calloc(len + 1, sizeof(char));
156 if (len > strlen(cp))
158 memcpy(item, cp, len);
160 if (strstr(item, "UN="))
161 ident->username = strdup(item + strcspn(cp, "=") + 1);
162 else if (strstr(item, "HN="))
163 ident->host = strdup(item + strcspn(cp, "=") + 1);
164 else if (strstr(item, "RN="))
165 ident->realname = strdup(item + strcspn(cp, "=") + 1);
166 else if (strstr(item, "E="))
167 ident->email = strdup(item + strcspn(cp, "=") + 1);
168 else if (strstr(item, "O="))
169 ident->org = strdup(item + strcspn(cp, "=") + 1);
170 else if (strstr(item, "C="))
171 ident->country = strdup(item + strcspn(cp, "=") + 1);
186 /* Encodes and returns SILC public key identifier. If some of the
187 arguments is NULL those are not encoded into the identifier string.
188 Protocol says that at least username and host must be provided. */
190 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
191 char *realname, char *email,
192 char *org, char *country)
196 SilcUInt32 len, tlen = 0;
198 if (!username || !host)
201 len = (username ? strlen(username) : 0) +
202 (host ? strlen(host) : 0) +
203 (realname ? strlen(realname) : 0) +
204 (email ? strlen(email) : 0) +
205 (org ? strlen(org) : 0) +
206 (country ? strlen(country) : 0);
211 len += 3 + 5 + 5 + 4 + 4 + 4;
212 buf = silc_buffer_alloc(len);
215 silc_buffer_pull_tail(buf, len);
218 silc_buffer_format(buf,
219 SILC_STR_UI32_STRING("UN="),
220 SILC_STR_UI32_STRING(username),
222 silc_buffer_pull(buf, 3 + strlen(username));
223 tlen = 3 + strlen(username);
227 silc_buffer_format(buf,
228 SILC_STR_UI32_STRING(", "),
229 SILC_STR_UI32_STRING("HN="),
230 SILC_STR_UI32_STRING(host),
232 silc_buffer_pull(buf, 5 + strlen(host));
233 tlen += 5 + strlen(host);
237 silc_buffer_format(buf,
238 SILC_STR_UI32_STRING(", "),
239 SILC_STR_UI32_STRING("RN="),
240 SILC_STR_UI32_STRING(realname),
242 silc_buffer_pull(buf, 5 + strlen(realname));
243 tlen += 5 + strlen(realname);
247 silc_buffer_format(buf,
248 SILC_STR_UI32_STRING(", "),
249 SILC_STR_UI32_STRING("E="),
250 SILC_STR_UI32_STRING(email),
252 silc_buffer_pull(buf, 4 + strlen(email));
253 tlen += 4 + strlen(email);
257 silc_buffer_format(buf,
258 SILC_STR_UI32_STRING(", "),
259 SILC_STR_UI32_STRING("O="),
260 SILC_STR_UI32_STRING(org),
262 silc_buffer_pull(buf, 4 + strlen(org));
263 tlen += 4 + strlen(org);
267 silc_buffer_format(buf,
268 SILC_STR_UI32_STRING(", "),
269 SILC_STR_UI32_STRING("C="),
270 SILC_STR_UI32_STRING(country),
272 silc_buffer_pull(buf, 4 + strlen(country));
273 tlen += 4 + strlen(country);
276 silc_buffer_push(buf, buf->data - buf->head);
277 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
280 memcpy(identifier, buf->data, tlen);
281 silc_buffer_free(buf);
287 /*************************** Public key routines *****************************/
289 /* Returns PKCS algorithm context */
291 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
293 SilcSILCPublicKey silc_pubkey = public_key;
294 return silc_pubkey->pkcs;
297 /* Imports SILC protocol style public key from SILC public key file */
299 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
300 SilcUInt32 filedata_len,
301 SilcPKCSFileEncoding encoding,
302 void **ret_public_key)
305 unsigned char *data = NULL;
308 SILC_LOG_DEBUG(("Parsing SILC public key file"));
313 /* Check start of file and remove header from the data. */
314 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
315 if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))
317 for (i = 0; i < len; i++) {
318 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
322 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
323 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
326 case SILC_PKCS_FILE_BIN:
329 case SILC_PKCS_FILE_BASE64:
330 data = silc_pem_decode(filedata, filedata_len, &filedata_len);
337 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
344 /* Imports SILC protocol style public key */
346 SilcBool silc_pkcs_silc_import_public_key(unsigned char *key,
348 void **ret_public_key)
350 const SilcPKCSAlgorithm *pkcs;
351 SilcBufferStruct buf, alg_key;
352 SilcSILCPublicKey silc_pubkey = NULL;
353 SilcAsn1 asn1 = NULL;
354 SilcUInt32 totlen, keydata_len;
355 SilcUInt16 pkcs_len, identifier_len;
356 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
359 SILC_LOG_DEBUG(("Parsing SILC public key"));
364 silc_buffer_set(&buf, key, key_len);
367 ret = silc_buffer_unformat(&buf,
368 SILC_STR_UI_INT(&totlen),
373 if (totlen + 4 != key_len)
376 /* Get algorithm name and identifier */
378 silc_buffer_unformat(&buf,
380 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
381 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
386 if (pkcs_len < 1 || identifier_len < 3 ||
387 pkcs_len + identifier_len > totlen)
391 silc_buffer_pull(&buf, 4 + 2 + pkcs_len + 2 + identifier_len);
392 keydata_len = silc_buffer_len(&buf);
393 ret = silc_buffer_unformat(&buf,
394 SILC_STR_UI_XNSTRING(&key_data,
400 /* Allocate SILC public key context */
401 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
405 /* Decode SILC identifier */
406 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
409 asn1 = silc_asn1_alloc();
413 if (!strcmp(pkcs_name, "rsa")) {
414 /* Parse the SILC RSA public key */
415 SilcUInt32 e_len, n_len;
418 /* Get PKCS object */
419 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
421 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
424 silc_pubkey->pkcs = pkcs;
428 SILC_GET32_MSB(e_len, key_data);
429 if (!e_len || e_len + 4 > keydata_len)
432 silc_mp_bin2mp(key_data + 4, e_len, &e);
433 if (keydata_len < 4 + e_len + 4) {
437 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
438 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
443 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
445 /* Encode to PKCS #1 format */
446 memset(&alg_key, 0, sizeof(alg_key));
447 if (!silc_asn1_encode(asn1, &alg_key,
451 SILC_ASN1_END, SILC_ASN1_END)) {
460 } else if (!strcmp(pkcs_name, "dsa")) {
461 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
465 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
469 /* Import PKCS algorithm public key */
470 if (pkcs->import_public_key)
471 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
472 &silc_pubkey->public_key))
475 silc_free(pkcs_name);
477 silc_asn1_free(asn1);
479 *ret_public_key = silc_pubkey;
484 silc_free(pkcs_name);
486 silc_free(silc_pubkey);
488 silc_asn1_free(asn1);
492 /* Exports public key as SILC protocol style public key file */
495 silc_pkcs_silc_export_public_key_file(void *public_key,
496 SilcPKCSFileEncoding encoding,
500 unsigned char *key, *data;
503 SILC_LOG_DEBUG(("Encoding SILC public key file"));
506 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
511 case SILC_PKCS_FILE_BIN:
514 case SILC_PKCS_FILE_BASE64:
515 data = silc_pem_encode_file(key, key_len);
520 key_len = strlen(data);
524 /* Encode SILC public key file */
525 buf = silc_buffer_alloc_size(key_len +
526 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
527 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
533 if (silc_buffer_format(buf,
534 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
535 SILC_STR_UI_XNSTRING(key, key_len),
536 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
538 silc_buffer_free(buf);
544 key = silc_buffer_steal(buf, ret_len);
545 silc_buffer_free(buf);
550 /* Exports public key as SILC protocol style public key */
552 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
555 SilcSILCPublicKey silc_pubkey = public_key;
556 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
557 SilcBufferStruct alg_key;
558 SilcBuffer buf = NULL;
559 SilcAsn1 asn1 = NULL;
560 unsigned char *pk = NULL, *key = NULL, *ret;
561 SilcUInt32 pk_len, key_len, totlen;
564 SILC_LOG_DEBUG(("Encoding SILC public key"));
566 /* Export PKCS algorithm public key */
567 if (pkcs->export_public_key)
568 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
571 silc_buffer_set(&alg_key, pk, pk_len);
573 /* Encode identifier */
575 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
576 silc_pubkey->identifier.host,
577 silc_pubkey->identifier.realname,
578 silc_pubkey->identifier.email,
579 silc_pubkey->identifier.org,
580 silc_pubkey->identifier.country);
584 asn1 = silc_asn1_alloc();
588 if (!strcmp(pkcs->name, "rsa")) {
589 /* Parse the PKCS #1 public key */
591 SilcUInt32 n_len, e_len;
592 unsigned char *nb, *eb;
594 memset(&n, 0, sizeof(n));
595 memset(&e, 0, sizeof(e));
596 if (!silc_asn1_decode(asn1, &alg_key,
600 SILC_ASN1_END, SILC_ASN1_END))
603 /* Encode to SILC RSA public key */
604 eb = silc_mp_mp2bin(&e, 0, &e_len);
607 nb = silc_mp_mp2bin(&n, 0, &n_len);
610 key_len = e_len + 4 + n_len + 4;
611 key = silc_calloc(key_len, sizeof(*key));
615 /* Put e length and e */
616 SILC_PUT32_MSB(e_len, key);
617 memcpy(key + 4, eb, e_len);
619 /* Put n length and n. */
620 SILC_PUT32_MSB(n_len, key + 4 + e_len);
621 memcpy(key + 4 + e_len + 4, nb, n_len);
626 } else if (!strcmp(pkcs->name, "dsa")) {
627 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
631 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
635 /* Encode SILC Public Key */
636 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
637 buf = silc_buffer_alloc_size(totlen + 4);
640 if (silc_buffer_format(buf,
641 SILC_STR_UI_INT(totlen),
642 SILC_STR_UI_SHORT(strlen(pkcs->name)),
643 SILC_STR_UI32_STRING(pkcs->name),
644 SILC_STR_UI_SHORT(strlen(identifier)),
645 SILC_STR_UI32_STRING(identifier),
646 SILC_STR_UI_XNSTRING(key, key_len),
650 ret = silc_buffer_steal(buf, ret_len);
651 silc_buffer_free(buf);
653 silc_free(identifier);
654 silc_asn1_free(asn1);
659 silc_free(identifier);
663 silc_buffer_free(buf);
665 silc_asn1_free(asn1);
669 /* Return key length */
671 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
673 SilcSILCPublicKey silc_pubkey = public_key;
674 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
677 /* Copy public key */
679 void *silc_pkcs_silc_public_key_copy(void *public_key)
681 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
683 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
686 new_pubkey->pkcs = silc_pubkey->pkcs;
688 new_pubkey->public_key =
689 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
690 if (!new_pubkey->public_key) {
691 silc_free(new_pubkey);
698 /* Compares public keys */
700 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
702 SilcSILCPublicKey k1 = key1, k2 = key2;
704 if (strcmp(k1->pkcs->name, k2->pkcs->name))
707 if ((k1->identifier.username && !k2->identifier.username) ||
708 (!k1->identifier.username && k2->identifier.username) ||
709 (k1->identifier.username && k2->identifier.username &&
710 strcmp(k1->identifier.username, k2->identifier.username)))
713 if ((k1->identifier.host && !k2->identifier.host) ||
714 (!k1->identifier.host && k2->identifier.host) ||
715 (k1->identifier.host && k2->identifier.host &&
716 strcmp(k1->identifier.host, k2->identifier.host)))
719 if ((k1->identifier.realname && !k2->identifier.realname) ||
720 (!k1->identifier.realname && k2->identifier.realname) ||
721 (k1->identifier.realname && k2->identifier.realname &&
722 strcmp(k1->identifier.realname, k2->identifier.realname)))
725 if ((k1->identifier.email && !k2->identifier.email) ||
726 (!k1->identifier.email && k2->identifier.email) ||
727 (k1->identifier.email && k2->identifier.email &&
728 strcmp(k1->identifier.email, k2->identifier.email)))
731 if ((k1->identifier.org && !k2->identifier.org) ||
732 (!k1->identifier.org && k2->identifier.org) ||
733 (k1->identifier.org && k2->identifier.org &&
734 strcmp(k1->identifier.org, k2->identifier.org)))
737 if ((k1->identifier.country && !k2->identifier.country) ||
738 (!k1->identifier.country && k2->identifier.country) ||
739 (k1->identifier.country && k2->identifier.country &&
740 strcmp(k1->identifier.country, k2->identifier.country)))
743 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
746 /* Frees public key */
748 void silc_pkcs_silc_public_key_free(void *public_key)
750 SilcSILCPublicKey silc_pubkey = public_key;
752 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
754 silc_free(silc_pubkey->identifier.username);
755 silc_free(silc_pubkey->identifier.host);
756 silc_free(silc_pubkey->identifier.realname);
757 silc_free(silc_pubkey->identifier.email);
758 silc_free(silc_pubkey->identifier.org);
759 silc_free(silc_pubkey->identifier.country);
760 silc_free(silc_pubkey);
764 /*************************** Private key routines ****************************/
766 /* Private key file magic */
767 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
769 /* Imports SILC implementation style private key file */
771 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
772 SilcUInt32 filedata_len,
773 const char *passphrase,
774 SilcUInt32 passphrase_len,
775 SilcPKCSFileEncoding encoding,
776 void **ret_private_key)
782 unsigned char tmp[32], keymat[64], *data = NULL;
783 SilcUInt32 i, len, magic, mac_len;
786 SILC_LOG_DEBUG(("Parsing SILC private key file"));
788 /* Check start of file and remove header from the data. */
789 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
790 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
792 for (i = 0; i < len; i++) {
793 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
798 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
799 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
802 case SILC_PKCS_FILE_BIN:
805 case SILC_PKCS_FILE_BASE64:
806 data = silc_pem_decode(filedata, filedata_len, &len);
813 memset(tmp, 0, sizeof(tmp));
814 memset(keymat, 0, sizeof(keymat));
816 /* Check file magic */
817 SILC_GET32_MSB(magic, filedata);
818 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
819 SILC_LOG_ERROR(("Private key does not have correct magic"));
823 /* Allocate the AES cipher */
824 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
825 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
828 blocklen = silc_cipher_get_block_len(aes);
829 if (blocklen * 2 > sizeof(tmp)) {
830 silc_cipher_free(aes);
834 /* Allocate SHA1 hash */
835 if (!silc_hash_alloc("sha1", &sha1)) {
836 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
837 silc_cipher_free(aes);
842 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
843 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
844 silc_hash_free(sha1);
845 silc_cipher_free(aes);
849 /* Derive the decryption key from the provided key material. The key
850 is 256 bits length, and derived by taking hash of the data, then
851 re-hashing the data and the previous digest, and using the first and
852 second digest as the key. */
853 silc_hash_init(sha1);
854 silc_hash_update(sha1, passphrase, passphrase_len);
855 silc_hash_final(sha1, keymat);
856 silc_hash_init(sha1);
857 silc_hash_update(sha1, passphrase, passphrase_len);
858 silc_hash_update(sha1, keymat, 16);
859 silc_hash_final(sha1, keymat + 16);
861 /* Set the key to the cipher */
862 silc_cipher_set_key(aes, keymat, 256);
864 /* First, verify the MAC of the private key data */
865 mac_len = silc_hmac_len(sha1hmac);
866 silc_hmac_init_with_key(sha1hmac, keymat, 16);
867 silc_hmac_update(sha1hmac, filedata, len - mac_len);
868 silc_hmac_final(sha1hmac, tmp, NULL);
869 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
870 SILC_LOG_DEBUG(("Integrity check for private key failed"));
871 memset(keymat, 0, sizeof(keymat));
872 memset(tmp, 0, sizeof(tmp));
873 silc_hmac_free(sha1hmac);
874 silc_hash_free(sha1);
875 silc_cipher_free(aes);
881 /* Decrypt the private key buffer */
882 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
883 SILC_GET32_MSB(i, filedata);
885 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
886 memset(keymat, 0, sizeof(keymat));
887 memset(tmp, 0, sizeof(tmp));
888 silc_hmac_free(sha1hmac);
889 silc_hash_free(sha1);
890 silc_cipher_free(aes);
897 memset(keymat, 0, sizeof(keymat));
898 memset(tmp, 0, sizeof(tmp));
899 silc_hmac_free(sha1hmac);
900 silc_hash_free(sha1);
901 silc_cipher_free(aes);
903 /* Import the private key */
904 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
911 /* Private key version */
912 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
914 /* Imports SILC implementation style private key */
916 SilcBool silc_pkcs_silc_import_private_key(unsigned char *key,
918 void **ret_private_key)
920 SilcBufferStruct buf;
921 const SilcPKCSAlgorithm *pkcs;
922 SilcBufferStruct alg_key;
923 SilcSILCPrivateKey silc_privkey = NULL;
924 SilcAsn1 asn1 = NULL;
926 SilcUInt32 keydata_len;
927 unsigned char *pkcs_name = NULL, *key_data;
930 SILC_LOG_DEBUG(("Parsing SILC private key"));
932 if (!ret_private_key)
935 silc_buffer_set(&buf, key, key_len);
937 /* Get algorithm name and identifier */
939 silc_buffer_unformat(&buf,
940 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
943 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
947 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
948 SILC_LOG_DEBUG(("Malformed private key buffer"));
952 /* Get key data. We assume that rest of the buffer is key data. */
953 silc_buffer_pull(&buf, 2 + pkcs_len);
954 keydata_len = silc_buffer_len(&buf);
955 ret = silc_buffer_unformat(&buf,
956 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
961 /* Allocate SILC private key context */
962 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
966 asn1 = silc_asn1_alloc();
970 if (!strcmp(pkcs_name, "rsa")) {
971 /* Parse the RSA SILC private key */
973 SilcMPInt n, e, d, dp, dq, qp, p, q;
977 /* Get PKCS object */
978 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
980 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
983 silc_privkey->pkcs = pkcs;
988 silc_buffer_set(&k, key_data, keydata_len);
990 /* Get version. Key without the version is old style private key
991 and we need to do some computation to get it to correct format. */
992 if (silc_buffer_unformat(&k,
993 SILC_STR_UI_INT(&ver),
996 silc_buffer_pull(&k, 4);
998 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1001 if (silc_buffer_unformat(&k,
1002 SILC_STR_UI_INT(&len),
1005 silc_buffer_pull(&k, 4);
1009 if (silc_buffer_unformat(&k,
1010 SILC_STR_UI_XNSTRING(&tmp, len),
1014 silc_mp_bin2mp(tmp, len, &e);
1015 silc_buffer_pull(&k, len);
1018 if (silc_buffer_unformat(&k,
1019 SILC_STR_UI_INT(&len),
1022 silc_buffer_pull(&k, 4);
1023 if (silc_buffer_unformat(&k,
1024 SILC_STR_UI_XNSTRING(&tmp, len),
1028 silc_mp_bin2mp(tmp, len, &n);
1029 silc_buffer_pull(&k, len);
1032 if (silc_buffer_unformat(&k,
1033 SILC_STR_UI_INT(&len),
1036 silc_buffer_pull(&k, 4);
1037 if (silc_buffer_unformat(&k,
1038 SILC_STR_UI_XNSTRING(&tmp, len),
1042 silc_mp_bin2mp(tmp, len, &d);
1043 silc_buffer_pull(&k, len);
1046 if (silc_buffer_unformat(&k,
1047 SILC_STR_UI_INT(&len),
1050 silc_buffer_pull(&k, 4);
1051 if (silc_buffer_unformat(&k,
1052 SILC_STR_UI_XNSTRING(&tmp, len),
1056 silc_mp_bin2mp(tmp, len, &dp);
1057 silc_buffer_pull(&k, len);
1060 if (silc_buffer_unformat(&k,
1061 SILC_STR_UI_INT(&len),
1064 silc_buffer_pull(&k, 4);
1065 if (silc_buffer_unformat(&k,
1066 SILC_STR_UI_XNSTRING(&tmp, len),
1070 silc_mp_bin2mp(tmp, len, &dq);
1071 silc_buffer_pull(&k, len);
1073 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1077 if (silc_buffer_unformat(&k,
1078 SILC_STR_UI_INT(&len),
1081 silc_buffer_pull(&k, 4);
1082 if (silc_buffer_len(&k) < len)
1084 silc_buffer_pull(&k, len);
1087 if (silc_buffer_unformat(&k,
1088 SILC_STR_UI_INT(&len),
1091 silc_buffer_pull(&k, 4);
1092 if (silc_buffer_len(&k) < len)
1094 silc_buffer_pull(&k, len);
1099 if (silc_buffer_unformat(&k,
1100 SILC_STR_UI_INT(&len),
1103 silc_buffer_pull(&k, 4);
1104 if (silc_buffer_unformat(&k,
1105 SILC_STR_UI_XNSTRING(&tmp, len),
1109 silc_mp_bin2mp(tmp, len, &qp);
1110 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_UI_XNSTRING(&tmp, len),
1124 silc_mp_bin2mp(tmp, len, &p);
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_UI_XNSTRING(&tmp, len),
1138 silc_mp_bin2mp(tmp, len, &q);
1139 silc_buffer_pull(&k, len);
1141 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1142 /* Old version. Compute to new version */
1143 SILC_LOG_DEBUG(("Old version private key"));
1145 silc_mp_modinv(&qp, &q, &p);
1148 /* Encode to PKCS #1 format */
1149 memset(&alg_key, 0, sizeof(alg_key));
1150 if (!silc_asn1_encode(asn1, &alg_key,
1152 SILC_ASN1_SHORT_INT(0),
1161 SILC_ASN1_END, SILC_ASN1_END))
1170 silc_mp_uninit(&dp);
1171 silc_mp_uninit(&dq);
1172 silc_mp_uninit(&qp);
1174 } else if (!strcmp(pkcs_name, "dsa")) {
1175 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1179 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1183 /* Import PKCS algorithm private key */
1184 if (pkcs->import_private_key)
1185 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1186 &silc_privkey->private_key))
1189 silc_free(pkcs_name);
1190 silc_asn1_free(asn1);
1192 *ret_private_key = silc_privkey;
1197 silc_free(pkcs_name);
1198 silc_free(silc_privkey);
1200 silc_asn1_free(asn1);
1204 /* Exports private key as SILC implementation style private key file */
1207 silc_pkcs_silc_export_private_key_file(void *private_key,
1208 const char *passphrase,
1209 SilcUInt32 passphrase_len,
1210 SilcPKCSFileEncoding encoding,
1212 SilcUInt32 *ret_len)
1217 SilcBuffer buf, enc;
1218 SilcUInt32 len, blocklen, padlen, key_len;
1219 unsigned char *key, *data;
1220 unsigned char tmp[32], keymat[64];
1223 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1225 /* Export the private key */
1226 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1230 memset(tmp, 0, sizeof(tmp));
1231 memset(keymat, 0, sizeof(keymat));
1233 /* Allocate the AES cipher */
1234 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1235 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1239 blocklen = silc_cipher_get_block_len(aes);
1240 if (blocklen * 2 > sizeof(tmp)) {
1241 silc_cipher_free(aes);
1246 /* Allocate SHA1 hash */
1247 if (!silc_hash_alloc("sha1", &sha1)) {
1248 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1249 silc_cipher_free(aes);
1254 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1255 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1256 silc_hash_free(sha1);
1257 silc_cipher_free(aes);
1261 /* Derive the encryption key from the provided key material. The key
1262 is 256 bits length, and derived by taking hash of the data, then
1263 re-hashing the data and the previous digest, and using the first and
1264 second digest as the key. */
1265 silc_hash_init(sha1);
1266 silc_hash_update(sha1, passphrase, passphrase_len);
1267 silc_hash_final(sha1, keymat);
1268 silc_hash_init(sha1);
1269 silc_hash_update(sha1, passphrase, passphrase_len);
1270 silc_hash_update(sha1, keymat, 16);
1271 silc_hash_final(sha1, keymat + 16);
1273 /* Set the key to the cipher */
1274 silc_cipher_set_key(aes, keymat, 256);
1276 /* Encode the buffer to be encrypted. Add padding to it too, at least
1277 block size of the cipher. */
1279 /* Allocate buffer for encryption */
1280 len = silc_hmac_len(sha1hmac);
1281 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1282 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1284 silc_hmac_free(sha1hmac);
1285 silc_hash_free(sha1);
1286 silc_cipher_free(aes);
1290 /* Generate padding */
1291 for (i = 0; i < padlen; i++)
1292 tmp[i] = silc_rng_get_byte_fast(rng);
1294 /* Put magic number */
1295 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1296 silc_buffer_pull(enc, 4);
1298 /* Encode the buffer */
1299 silc_buffer_format(enc,
1300 SILC_STR_UI_INT(key_len),
1301 SILC_STR_UI_XNSTRING(key, key_len),
1302 SILC_STR_UI_XNSTRING(tmp, padlen),
1307 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1308 silc_cipher_get_iv(aes));
1310 silc_buffer_push(enc, 4);
1312 /* Compute HMAC over the encrypted data and append the MAC to data.
1313 The key is the first digest of the original key material. */
1314 key_len = silc_buffer_len(enc) - len;
1315 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1316 silc_hmac_update(sha1hmac, enc->data, key_len);
1317 silc_buffer_pull(enc, key_len);
1318 silc_hmac_final(sha1hmac, enc->data, NULL);
1319 silc_buffer_push(enc, key_len);
1322 memset(keymat, 0, sizeof(keymat));
1323 memset(tmp, 0, sizeof(tmp));
1324 silc_hmac_free(sha1hmac);
1325 silc_hash_free(sha1);
1326 silc_cipher_free(aes);
1329 case SILC_PKCS_FILE_BIN:
1332 case SILC_PKCS_FILE_BASE64:
1333 data = silc_pem_encode_file(enc->data, silc_buffer_len(enc));
1335 silc_buffer_clear(enc);
1336 silc_buffer_free(enc);
1339 silc_free(silc_buffer_steal(enc, NULL));
1340 silc_buffer_set(enc, data, strlen(data));
1345 key_len = silc_buffer_len(enc);
1347 /* Encode the data and save to file */
1348 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1349 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1350 buf = silc_buffer_alloc_size(len);
1352 silc_buffer_free(enc);
1355 silc_buffer_format(buf,
1356 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1357 SILC_STR_UI_XNSTRING(key, key_len),
1358 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1361 silc_buffer_free(enc);
1362 data = silc_buffer_steal(buf, ret_len);
1363 silc_buffer_free(buf);
1368 /* Exports private key as SILC implementation style private key */
1370 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1371 SilcUInt32 *ret_len)
1373 SilcSILCPrivateKey silc_privkey = private_key;
1374 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1375 SilcBufferStruct alg_key;
1376 SilcBuffer buf = NULL;
1377 SilcAsn1 asn1 = NULL;
1378 unsigned char *prv = NULL, *key = NULL, *ret;
1379 SilcUInt32 prv_len, key_len, totlen;
1381 SILC_LOG_DEBUG(("Encoding SILC private key"));
1383 /* Export PKCS algorithm private key */
1384 if (pkcs->export_private_key)
1385 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1388 silc_buffer_set(&alg_key, prv, prv_len);
1390 asn1 = silc_asn1_alloc();
1394 if (!strcmp(pkcs->name, "rsa")) {
1395 /* Parse the PKCS #1 private key */
1396 SilcMPInt n, e, d, dp, dq, qp, p, q;
1397 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1398 qp_len, p_len, q_len, len = 0;
1399 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1401 if (!silc_asn1_decode(asn1, &alg_key,
1403 SILC_ASN1_INT(NULL),
1412 SILC_ASN1_END, SILC_ASN1_END))
1415 /* Encode to SILC RSA private key */
1416 eb = silc_mp_mp2bin(&e, 0, &e_len);
1417 nb = silc_mp_mp2bin(&n, 0, &n_len);
1418 db = silc_mp_mp2bin(&d, 0, &d_len);
1419 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1420 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1421 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1422 pb = silc_mp_mp2bin(&p, 0, &p_len);
1423 qb = silc_mp_mp2bin(&q, 0, &q_len);
1424 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1425 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1427 buf = silc_buffer_alloc_size(len);
1430 if (silc_buffer_format(buf,
1431 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1432 SILC_STR_UI_INT(e_len),
1433 SILC_STR_UI_XNSTRING(eb, e_len),
1434 SILC_STR_UI_INT(n_len),
1435 SILC_STR_UI_XNSTRING(nb, n_len),
1436 SILC_STR_UI_INT(d_len),
1437 SILC_STR_UI_XNSTRING(db, d_len),
1438 SILC_STR_UI_INT(dp_len),
1439 SILC_STR_UI_XNSTRING(dpb, dp_len),
1440 SILC_STR_UI_INT(dq_len),
1441 SILC_STR_UI_XNSTRING(dqb, dq_len),
1442 SILC_STR_UI_INT(qp_len),
1443 SILC_STR_UI_XNSTRING(qpb, qp_len),
1444 SILC_STR_UI_INT(p_len),
1445 SILC_STR_UI_XNSTRING(pb, p_len),
1446 SILC_STR_UI_INT(q_len),
1447 SILC_STR_UI_XNSTRING(qb, q_len),
1451 key = silc_buffer_steal(buf, &key_len);
1452 silc_buffer_free(buf);
1462 } else if (!strcmp(pkcs->name, "dsa")) {
1463 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1467 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1471 /* Encode SILC private key */
1472 totlen = 2 + strlen(pkcs->name) + key_len;
1473 buf = silc_buffer_alloc_size(totlen);
1476 if (silc_buffer_format(buf,
1477 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1478 SILC_STR_UI32_STRING(pkcs->name),
1479 SILC_STR_UI_XNSTRING(key, key_len),
1483 ret = silc_buffer_steal(buf, ret_len);
1484 silc_buffer_free(buf);
1487 silc_asn1_free(asn1);
1495 silc_buffer_free(buf);
1499 /* Return key length */
1501 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1503 SilcSILCPrivateKey silc_privkey = private_key;
1504 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1507 /* Frees private key */
1509 void silc_pkcs_silc_private_key_free(void *private_key)
1511 SilcSILCPrivateKey silc_privkey = private_key;
1513 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1515 silc_free(silc_privkey);
1519 /***************************** PKCS operations ******************************/
1521 /* Encrypts as specified in SILC protocol specification */
1523 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1527 SilcUInt32 dst_size,
1528 SilcUInt32 *ret_dst_len)
1530 SilcSILCPublicKey silc_pubkey = public_key;
1532 if (!silc_pubkey->pkcs->encrypt)
1535 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1537 dst, dst_size, ret_dst_len);
1540 /* Decrypts as specified in SILC protocol specification */
1542 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1546 SilcUInt32 dst_size,
1547 SilcUInt32 *ret_dst_len)
1549 SilcSILCPrivateKey silc_privkey = private_key;
1551 if (!silc_privkey->pkcs->decrypt)
1554 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1556 dst, dst_size, ret_dst_len);
1559 /* Signs as specified in SILC protocol specification */
1561 SilcBool silc_pkcs_silc_sign(void *private_key,
1564 unsigned char *signature,
1565 SilcUInt32 signature_size,
1566 SilcUInt32 *ret_signature_len,
1569 SilcSILCPrivateKey silc_privkey = private_key;
1571 if (!silc_privkey->pkcs->sign)
1574 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1576 signature, signature_size,
1577 ret_signature_len, hash);
1580 /* Verifies as specified in SILC protocol specification */
1582 SilcBool silc_pkcs_silc_verify(void *public_key,
1583 unsigned char *signature,
1584 SilcUInt32 signature_len,
1585 unsigned char *data,
1586 SilcUInt32 data_len,
1589 SilcSILCPublicKey silc_pubkey = public_key;
1591 if (!silc_pubkey->pkcs->verify)
1594 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1595 signature, signature_len,
1596 data, data_len, hash);