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,
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_base64_decode(filedata, filedata_len, &filedata_len);
337 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
341 return ret ? TRUE : FALSE;
344 /* Imports SILC protocol style public key */
346 int 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,
369 SILC_STR_UI_INT(&totlen),
374 /* Backwards compatibility */
375 if (totlen == key_len)
378 if (totlen + 4 != key_len)
381 /* Get algorithm name and identifier */
383 silc_buffer_unformat(&buf,
385 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
386 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
391 if (pkcs_len < 1 || identifier_len < 3 ||
392 pkcs_len + identifier_len > totlen)
396 keydata_len = silc_buffer_len(&buf);
397 ret = silc_buffer_unformat(&buf,
398 SILC_STR_DATA(&key_data, keydata_len),
403 /* Allocate SILC public key context */
404 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
408 /* Decode SILC identifier */
409 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
412 asn1 = silc_asn1_alloc();
416 if (!strcmp(pkcs_name, "rsa")) {
417 /* Parse the SILC RSA public key */
418 SilcUInt32 e_len, n_len;
421 /* Get PKCS object */
422 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
424 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
427 silc_pubkey->pkcs = pkcs;
431 SILC_GET32_MSB(e_len, key_data);
432 if (!e_len || e_len + 4 > keydata_len)
435 silc_mp_bin2mp(key_data + 4, e_len, &e);
436 if (keydata_len < 4 + e_len + 4) {
440 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
441 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
446 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
448 /* Encode to PKCS #1 format */
449 memset(&alg_key, 0, sizeof(alg_key));
450 if (!silc_asn1_encode(asn1, &alg_key,
454 SILC_ASN1_END, SILC_ASN1_END)) {
463 } else if (!strcmp(pkcs_name, "dsa")) {
464 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
468 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
472 /* Import PKCS algorithm public key */
473 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
474 &silc_pubkey->public_key))
477 silc_free(pkcs_name);
479 silc_asn1_free(asn1);
481 *ret_public_key = silc_pubkey;
486 silc_free(pkcs_name);
488 silc_free(silc_pubkey);
490 silc_asn1_free(asn1);
494 /* Exports public key as SILC protocol style public key file */
497 silc_pkcs_silc_export_public_key_file(void *public_key,
498 SilcPKCSFileEncoding encoding,
502 unsigned char *key, *data;
505 SILC_LOG_DEBUG(("Encoding SILC public key file"));
508 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
513 case SILC_PKCS_FILE_BIN:
516 case SILC_PKCS_FILE_BASE64:
517 data = silc_base64_encode_file(key, key_len);
522 key_len = strlen(data);
526 /* Encode SILC public key file */
527 buf = silc_buffer_alloc_size(key_len +
528 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
529 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
535 if (silc_buffer_format(buf,
536 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
537 SILC_STR_UI_XNSTRING(key, key_len),
538 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
540 silc_buffer_free(buf);
546 key = silc_buffer_steal(buf, ret_len);
547 silc_buffer_free(buf);
552 /* Exports public key as SILC protocol style public key */
554 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
557 SilcSILCPublicKey silc_pubkey = public_key;
558 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
559 SilcBufferStruct alg_key;
560 SilcBuffer buf = NULL;
561 SilcAsn1 asn1 = NULL;
562 unsigned char *pk = NULL, *key = NULL, *ret;
563 SilcUInt32 pk_len, key_len, totlen;
566 SILC_LOG_DEBUG(("Encoding SILC public key"));
568 /* Export PKCS algorithm public key */
569 if (pkcs->export_public_key)
570 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
573 silc_buffer_set(&alg_key, pk, pk_len);
575 /* Encode identifier */
577 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
578 silc_pubkey->identifier.host,
579 silc_pubkey->identifier.realname,
580 silc_pubkey->identifier.email,
581 silc_pubkey->identifier.org,
582 silc_pubkey->identifier.country);
586 asn1 = silc_asn1_alloc();
590 if (!strcmp(pkcs->name, "rsa")) {
591 /* Parse the PKCS #1 public key */
593 SilcUInt32 n_len, e_len;
594 unsigned char *nb, *eb;
596 memset(&n, 0, sizeof(n));
597 memset(&e, 0, sizeof(e));
598 if (!silc_asn1_decode(asn1, &alg_key,
602 SILC_ASN1_END, SILC_ASN1_END))
605 /* Encode to SILC RSA public key */
606 eb = silc_mp_mp2bin(&e, 0, &e_len);
609 nb = silc_mp_mp2bin(&n, 0, &n_len);
612 key_len = e_len + 4 + n_len + 4;
613 key = silc_calloc(key_len, sizeof(*key));
617 /* Put e length and e */
618 SILC_PUT32_MSB(e_len, key);
619 memcpy(key + 4, eb, e_len);
621 /* Put n length and n. */
622 SILC_PUT32_MSB(n_len, key + 4 + e_len);
623 memcpy(key + 4 + e_len + 4, nb, n_len);
628 } else if (!strcmp(pkcs->name, "dsa")) {
629 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
633 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
637 /* Encode SILC Public Key */
638 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
639 buf = silc_buffer_alloc_size(totlen + 4);
642 if (silc_buffer_format(buf,
643 SILC_STR_UI_INT(totlen),
644 SILC_STR_UI_SHORT(strlen(pkcs->name)),
645 SILC_STR_UI32_STRING(pkcs->name),
646 SILC_STR_UI_SHORT(strlen(identifier)),
647 SILC_STR_UI32_STRING(identifier),
648 SILC_STR_UI_XNSTRING(key, key_len),
652 ret = silc_buffer_steal(buf, ret_len);
653 silc_buffer_free(buf);
655 silc_free(identifier);
656 silc_asn1_free(asn1);
661 silc_free(identifier);
665 silc_buffer_free(buf);
667 silc_asn1_free(asn1);
671 /* Return key length */
673 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
675 SilcSILCPublicKey silc_pubkey = public_key;
676 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
679 /* Copy public key */
681 void *silc_pkcs_silc_public_key_copy(void *public_key)
683 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
685 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
688 new_pubkey->pkcs = silc_pubkey->pkcs;
690 new_pubkey->public_key =
691 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
692 if (!new_pubkey->public_key) {
693 silc_free(new_pubkey);
700 /* Compares public keys */
702 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
704 SilcSILCPublicKey k1 = key1, k2 = key2;
706 if (strcmp(k1->pkcs->name, k2->pkcs->name))
709 if ((k1->identifier.username && !k2->identifier.username) ||
710 (!k1->identifier.username && k2->identifier.username) ||
711 (k1->identifier.username && k2->identifier.username &&
712 strcmp(k1->identifier.username, k2->identifier.username)))
715 if ((k1->identifier.host && !k2->identifier.host) ||
716 (!k1->identifier.host && k2->identifier.host) ||
717 (k1->identifier.host && k2->identifier.host &&
718 strcmp(k1->identifier.host, k2->identifier.host)))
721 if ((k1->identifier.realname && !k2->identifier.realname) ||
722 (!k1->identifier.realname && k2->identifier.realname) ||
723 (k1->identifier.realname && k2->identifier.realname &&
724 strcmp(k1->identifier.realname, k2->identifier.realname)))
727 if ((k1->identifier.email && !k2->identifier.email) ||
728 (!k1->identifier.email && k2->identifier.email) ||
729 (k1->identifier.email && k2->identifier.email &&
730 strcmp(k1->identifier.email, k2->identifier.email)))
733 if ((k1->identifier.org && !k2->identifier.org) ||
734 (!k1->identifier.org && k2->identifier.org) ||
735 (k1->identifier.org && k2->identifier.org &&
736 strcmp(k1->identifier.org, k2->identifier.org)))
739 if ((k1->identifier.country && !k2->identifier.country) ||
740 (!k1->identifier.country && k2->identifier.country) ||
741 (k1->identifier.country && k2->identifier.country &&
742 strcmp(k1->identifier.country, k2->identifier.country)))
745 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
748 /* Frees public key */
750 void silc_pkcs_silc_public_key_free(void *public_key)
752 SilcSILCPublicKey silc_pubkey = public_key;
754 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
756 silc_free(silc_pubkey->identifier.username);
757 silc_free(silc_pubkey->identifier.host);
758 silc_free(silc_pubkey->identifier.realname);
759 silc_free(silc_pubkey->identifier.email);
760 silc_free(silc_pubkey->identifier.org);
761 silc_free(silc_pubkey->identifier.country);
762 silc_free(silc_pubkey);
766 /*************************** Private key routines ****************************/
768 /* Private key file magic */
769 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
771 /* Imports SILC implementation style private key file */
773 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
774 SilcUInt32 filedata_len,
775 const char *passphrase,
776 SilcUInt32 passphrase_len,
777 SilcPKCSFileEncoding encoding,
778 void **ret_private_key)
784 unsigned char tmp[32], keymat[64], *data = NULL;
785 SilcUInt32 i, len, magic, mac_len;
788 SILC_LOG_DEBUG(("Parsing SILC private key file"));
790 /* Check start of file and remove header from the data. */
791 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
792 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
794 for (i = 0; i < len; i++) {
795 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
800 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
801 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
804 case SILC_PKCS_FILE_BIN:
807 case SILC_PKCS_FILE_BASE64:
808 data = silc_base64_decode(filedata, filedata_len, &len);
815 memset(tmp, 0, sizeof(tmp));
816 memset(keymat, 0, sizeof(keymat));
818 /* Check file magic */
819 SILC_GET32_MSB(magic, filedata);
820 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
821 SILC_LOG_DEBUG(("Private key does not have correct magic"));
825 /* Allocate the AES cipher */
826 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
827 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
830 blocklen = silc_cipher_get_block_len(aes);
831 if (blocklen * 2 > sizeof(tmp)) {
832 silc_cipher_free(aes);
836 /* Allocate SHA1 hash */
837 if (!silc_hash_alloc("sha1", &sha1)) {
838 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
839 silc_cipher_free(aes);
844 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
845 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
846 silc_hash_free(sha1);
847 silc_cipher_free(aes);
851 /* Derive the decryption key from the provided key material. The key
852 is 256 bits length, and derived by taking hash of the data, then
853 re-hashing the data and the previous digest, and using the first and
854 second digest as the key. */
855 silc_hash_init(sha1);
856 silc_hash_update(sha1, passphrase, passphrase_len);
857 silc_hash_final(sha1, keymat);
858 silc_hash_init(sha1);
859 silc_hash_update(sha1, passphrase, passphrase_len);
860 silc_hash_update(sha1, keymat, 16);
861 silc_hash_final(sha1, keymat + 16);
863 /* Set the key to the cipher */
864 silc_cipher_set_key(aes, keymat, 256, FALSE);
866 /* First, verify the MAC of the private key data */
867 mac_len = silc_hmac_len(sha1hmac);
868 silc_hmac_init_with_key(sha1hmac, keymat, 16);
869 silc_hmac_update(sha1hmac, filedata, len - mac_len);
870 silc_hmac_final(sha1hmac, tmp, NULL);
871 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
872 SILC_LOG_DEBUG(("Integrity check for private key failed"));
873 memset(keymat, 0, sizeof(keymat));
874 memset(tmp, 0, sizeof(tmp));
875 silc_hmac_free(sha1hmac);
876 silc_hash_free(sha1);
877 silc_cipher_free(aes);
883 /* Decrypt the private key buffer */
884 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
885 SILC_GET32_MSB(i, filedata);
887 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
888 memset(keymat, 0, sizeof(keymat));
889 memset(tmp, 0, sizeof(tmp));
890 silc_hmac_free(sha1hmac);
891 silc_hash_free(sha1);
892 silc_cipher_free(aes);
899 memset(keymat, 0, sizeof(keymat));
900 memset(tmp, 0, sizeof(tmp));
901 silc_hmac_free(sha1hmac);
902 silc_hash_free(sha1);
903 silc_cipher_free(aes);
905 /* Import the private key */
906 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
910 return ret ? TRUE : FALSE;
913 /* Private key version */
914 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
916 /* Imports SILC implementation style private key */
918 int silc_pkcs_silc_import_private_key(unsigned char *key,
920 void **ret_private_key)
922 SilcBufferStruct buf;
923 const SilcPKCSAlgorithm *pkcs;
924 SilcBufferStruct alg_key;
925 SilcSILCPrivateKey silc_privkey = NULL;
926 SilcAsn1 asn1 = NULL;
928 SilcUInt32 keydata_len;
929 unsigned char *pkcs_name = NULL, *key_data;
932 SILC_LOG_DEBUG(("Parsing SILC private key"));
934 if (!ret_private_key)
937 silc_buffer_set(&buf, key, key_len);
939 /* Get algorithm name and identifier */
941 silc_buffer_unformat(&buf,
942 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
945 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
949 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
950 SILC_LOG_DEBUG(("Malformed private key buffer"));
954 /* Get key data. We assume that rest of the buffer is key data. */
955 silc_buffer_pull(&buf, 2 + pkcs_len);
956 keydata_len = silc_buffer_len(&buf);
957 ret = silc_buffer_unformat(&buf,
958 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
963 /* Allocate SILC private key context */
964 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
968 asn1 = silc_asn1_alloc();
972 if (!strcmp(pkcs_name, "rsa")) {
973 /* Parse the RSA SILC private key */
975 SilcMPInt n, e, d, dp, dq, qp, p, q;
979 /* Get PKCS object */
980 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
982 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
985 silc_privkey->pkcs = pkcs;
990 silc_buffer_set(&k, key_data, keydata_len);
992 /* Get version. Key without the version is old style private key
993 and we need to do some computation to get it to correct format. */
994 if (silc_buffer_unformat(&k,
995 SILC_STR_UI_INT(&ver),
998 silc_buffer_pull(&k, 4);
1000 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1003 if (silc_buffer_unformat(&k,
1004 SILC_STR_UI_INT(&len),
1007 silc_buffer_pull(&k, 4);
1011 if (silc_buffer_unformat(&k,
1012 SILC_STR_UI_XNSTRING(&tmp, len),
1016 silc_mp_bin2mp(tmp, len, &e);
1017 silc_buffer_pull(&k, len);
1020 if (silc_buffer_unformat(&k,
1021 SILC_STR_UI_INT(&len),
1024 silc_buffer_pull(&k, 4);
1025 if (silc_buffer_unformat(&k,
1026 SILC_STR_UI_XNSTRING(&tmp, len),
1030 silc_mp_bin2mp(tmp, len, &n);
1031 silc_buffer_pull(&k, len);
1034 if (silc_buffer_unformat(&k,
1035 SILC_STR_UI_INT(&len),
1038 silc_buffer_pull(&k, 4);
1039 if (silc_buffer_unformat(&k,
1040 SILC_STR_UI_XNSTRING(&tmp, len),
1044 silc_mp_bin2mp(tmp, len, &d);
1045 silc_buffer_pull(&k, len);
1048 if (silc_buffer_unformat(&k,
1049 SILC_STR_UI_INT(&len),
1052 silc_buffer_pull(&k, 4);
1053 if (silc_buffer_unformat(&k,
1054 SILC_STR_UI_XNSTRING(&tmp, len),
1058 silc_mp_bin2mp(tmp, len, &dp);
1059 silc_buffer_pull(&k, len);
1062 if (silc_buffer_unformat(&k,
1063 SILC_STR_UI_INT(&len),
1066 silc_buffer_pull(&k, 4);
1067 if (silc_buffer_unformat(&k,
1068 SILC_STR_UI_XNSTRING(&tmp, len),
1072 silc_mp_bin2mp(tmp, len, &dq);
1073 silc_buffer_pull(&k, len);
1075 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1079 if (silc_buffer_unformat(&k,
1080 SILC_STR_UI_INT(&len),
1083 silc_buffer_pull(&k, 4);
1084 if (silc_buffer_len(&k) < len)
1086 silc_buffer_pull(&k, len);
1089 if (silc_buffer_unformat(&k,
1090 SILC_STR_UI_INT(&len),
1093 silc_buffer_pull(&k, 4);
1094 if (silc_buffer_len(&k) < len)
1096 silc_buffer_pull(&k, len);
1101 if (silc_buffer_unformat(&k,
1102 SILC_STR_UI_INT(&len),
1105 silc_buffer_pull(&k, 4);
1106 if (silc_buffer_unformat(&k,
1107 SILC_STR_UI_XNSTRING(&tmp, len),
1111 silc_mp_bin2mp(tmp, len, &qp);
1112 silc_buffer_pull(&k, len);
1116 if (silc_buffer_unformat(&k,
1117 SILC_STR_UI_INT(&len),
1120 silc_buffer_pull(&k, 4);
1121 if (silc_buffer_unformat(&k,
1122 SILC_STR_UI_XNSTRING(&tmp, len),
1126 silc_mp_bin2mp(tmp, len, &p);
1127 silc_buffer_pull(&k, len);
1130 if (silc_buffer_unformat(&k,
1131 SILC_STR_UI_INT(&len),
1134 silc_buffer_pull(&k, 4);
1135 if (silc_buffer_unformat(&k,
1136 SILC_STR_UI_XNSTRING(&tmp, len),
1140 silc_mp_bin2mp(tmp, len, &q);
1141 silc_buffer_pull(&k, len);
1143 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1144 /* Old version. Compute to new version */
1145 SILC_LOG_DEBUG(("Old version private key"));
1147 silc_mp_modinv(&qp, &q, &p);
1150 /* Encode to PKCS #1 format */
1151 memset(&alg_key, 0, sizeof(alg_key));
1152 if (!silc_asn1_encode(asn1, &alg_key,
1154 SILC_ASN1_SHORT_INT(0),
1163 SILC_ASN1_END, SILC_ASN1_END))
1172 silc_mp_uninit(&dp);
1173 silc_mp_uninit(&dq);
1174 silc_mp_uninit(&qp);
1176 } else if (!strcmp(pkcs_name, "dsa")) {
1177 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1181 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1185 /* Import PKCS algorithm private key */
1186 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1187 &silc_privkey->private_key))
1190 silc_free(pkcs_name);
1191 silc_asn1_free(asn1);
1193 *ret_private_key = silc_privkey;
1198 silc_free(pkcs_name);
1199 silc_free(silc_privkey);
1201 silc_asn1_free(asn1);
1205 /* Exports private key as SILC implementation style private key file */
1208 silc_pkcs_silc_export_private_key_file(void *private_key,
1209 const char *passphrase,
1210 SilcUInt32 passphrase_len,
1211 SilcPKCSFileEncoding encoding,
1213 SilcUInt32 *ret_len)
1218 SilcBuffer buf, enc;
1219 SilcUInt32 len, blocklen, padlen, key_len;
1220 unsigned char *key, *data;
1221 unsigned char tmp[32], keymat[64];
1224 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1226 /* Export the private key */
1227 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1231 memset(tmp, 0, sizeof(tmp));
1232 memset(keymat, 0, sizeof(keymat));
1234 /* Allocate the AES cipher */
1235 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1236 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1240 blocklen = silc_cipher_get_block_len(aes);
1241 if (blocklen * 2 > sizeof(tmp)) {
1242 silc_cipher_free(aes);
1247 /* Allocate SHA1 hash */
1248 if (!silc_hash_alloc("sha1", &sha1)) {
1249 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1250 silc_cipher_free(aes);
1255 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1256 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1257 silc_hash_free(sha1);
1258 silc_cipher_free(aes);
1262 /* Derive the encryption key from the provided key material. The key
1263 is 256 bits length, and derived by taking hash of the data, then
1264 re-hashing the data and the previous digest, and using the first and
1265 second digest as the key. */
1266 silc_hash_init(sha1);
1267 silc_hash_update(sha1, passphrase, passphrase_len);
1268 silc_hash_final(sha1, keymat);
1269 silc_hash_init(sha1);
1270 silc_hash_update(sha1, passphrase, passphrase_len);
1271 silc_hash_update(sha1, keymat, 16);
1272 silc_hash_final(sha1, keymat + 16);
1274 /* Set the key to the cipher */
1275 silc_cipher_set_key(aes, keymat, 256, TRUE);
1277 /* Encode the buffer to be encrypted. Add padding to it too, at least
1278 block size of the cipher. */
1280 /* Allocate buffer for encryption */
1281 len = silc_hmac_len(sha1hmac);
1282 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1283 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1285 silc_hmac_free(sha1hmac);
1286 silc_hash_free(sha1);
1287 silc_cipher_free(aes);
1291 /* Generate padding */
1292 for (i = 0; i < padlen; i++)
1293 tmp[i] = silc_rng_get_byte_fast(rng);
1295 /* Put magic number */
1296 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1297 silc_buffer_pull(enc, 4);
1299 /* Encode the buffer */
1300 silc_buffer_format(enc,
1301 SILC_STR_UI_INT(key_len),
1302 SILC_STR_UI_XNSTRING(key, key_len),
1303 SILC_STR_UI_XNSTRING(tmp, padlen),
1308 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1309 silc_cipher_get_iv(aes));
1311 silc_buffer_push(enc, 4);
1313 /* Compute HMAC over the encrypted data and append the MAC to data.
1314 The key is the first digest of the original key material. */
1315 key_len = silc_buffer_len(enc) - len;
1316 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1317 silc_hmac_update(sha1hmac, enc->data, key_len);
1318 silc_buffer_pull(enc, key_len);
1319 silc_hmac_final(sha1hmac, enc->data, NULL);
1320 silc_buffer_push(enc, key_len);
1323 memset(keymat, 0, sizeof(keymat));
1324 memset(tmp, 0, sizeof(tmp));
1325 silc_hmac_free(sha1hmac);
1326 silc_hash_free(sha1);
1327 silc_cipher_free(aes);
1330 case SILC_PKCS_FILE_BIN:
1333 case SILC_PKCS_FILE_BASE64:
1334 data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1336 silc_buffer_clear(enc);
1337 silc_buffer_free(enc);
1340 silc_free(silc_buffer_steal(enc, NULL));
1341 silc_buffer_set(enc, data, strlen(data));
1346 key_len = silc_buffer_len(enc);
1348 /* Encode the data and save to file */
1349 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1350 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1351 buf = silc_buffer_alloc_size(len);
1353 silc_buffer_free(enc);
1356 silc_buffer_format(buf,
1357 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1358 SILC_STR_UI_XNSTRING(key, key_len),
1359 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1362 silc_buffer_free(enc);
1363 data = silc_buffer_steal(buf, ret_len);
1364 silc_buffer_free(buf);
1369 /* Exports private key as SILC implementation style private key */
1371 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1372 SilcUInt32 *ret_len)
1374 SilcSILCPrivateKey silc_privkey = private_key;
1375 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1376 SilcBufferStruct alg_key;
1377 SilcBuffer buf = NULL;
1378 SilcAsn1 asn1 = NULL;
1379 unsigned char *prv = NULL, *key = NULL, *ret;
1380 SilcUInt32 prv_len, key_len, totlen;
1382 SILC_LOG_DEBUG(("Encoding SILC private key"));
1384 /* Export PKCS algorithm private key */
1385 if (pkcs->export_private_key)
1386 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1389 silc_buffer_set(&alg_key, prv, prv_len);
1391 asn1 = silc_asn1_alloc();
1395 if (!strcmp(pkcs->name, "rsa")) {
1396 /* Parse the PKCS #1 private key */
1397 SilcMPInt n, e, d, dp, dq, qp, p, q;
1398 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1399 qp_len, p_len, q_len, len = 0;
1400 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1402 if (!silc_asn1_decode(asn1, &alg_key,
1404 SILC_ASN1_INT(NULL),
1413 SILC_ASN1_END, SILC_ASN1_END))
1416 /* Encode to SILC RSA private key */
1417 eb = silc_mp_mp2bin(&e, 0, &e_len);
1418 nb = silc_mp_mp2bin(&n, 0, &n_len);
1419 db = silc_mp_mp2bin(&d, 0, &d_len);
1420 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1421 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1422 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1423 pb = silc_mp_mp2bin(&p, 0, &p_len);
1424 qb = silc_mp_mp2bin(&q, 0, &q_len);
1425 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1426 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1428 buf = silc_buffer_alloc_size(len);
1431 if (silc_buffer_format(buf,
1432 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1433 SILC_STR_UI_INT(e_len),
1434 SILC_STR_UI_XNSTRING(eb, e_len),
1435 SILC_STR_UI_INT(n_len),
1436 SILC_STR_UI_XNSTRING(nb, n_len),
1437 SILC_STR_UI_INT(d_len),
1438 SILC_STR_UI_XNSTRING(db, d_len),
1439 SILC_STR_UI_INT(dp_len),
1440 SILC_STR_UI_XNSTRING(dpb, dp_len),
1441 SILC_STR_UI_INT(dq_len),
1442 SILC_STR_UI_XNSTRING(dqb, dq_len),
1443 SILC_STR_UI_INT(qp_len),
1444 SILC_STR_UI_XNSTRING(qpb, qp_len),
1445 SILC_STR_UI_INT(p_len),
1446 SILC_STR_UI_XNSTRING(pb, p_len),
1447 SILC_STR_UI_INT(q_len),
1448 SILC_STR_UI_XNSTRING(qb, q_len),
1452 key = silc_buffer_steal(buf, &key_len);
1453 silc_buffer_free(buf);
1463 } else if (!strcmp(pkcs->name, "dsa")) {
1464 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1468 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1472 /* Encode SILC private key */
1473 totlen = 2 + strlen(pkcs->name) + key_len;
1474 buf = silc_buffer_alloc_size(totlen);
1477 if (silc_buffer_format(buf,
1478 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1479 SILC_STR_UI32_STRING(pkcs->name),
1480 SILC_STR_UI_XNSTRING(key, key_len),
1484 ret = silc_buffer_steal(buf, ret_len);
1485 silc_buffer_free(buf);
1488 silc_asn1_free(asn1);
1496 silc_buffer_free(buf);
1500 /* Return key length */
1502 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1504 SilcSILCPrivateKey silc_privkey = private_key;
1505 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1508 /* Frees private key */
1510 void silc_pkcs_silc_private_key_free(void *private_key)
1512 SilcSILCPrivateKey silc_privkey = private_key;
1514 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1516 silc_free(silc_privkey);
1520 /***************************** PKCS operations ******************************/
1522 /* Encrypts as specified in SILC protocol specification */
1524 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1528 SilcUInt32 dst_size,
1529 SilcUInt32 *ret_dst_len,
1532 SilcSILCPublicKey silc_pubkey = public_key;
1534 if (!silc_pubkey->pkcs->encrypt)
1537 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1539 dst, dst_size, ret_dst_len, rng);
1542 /* Decrypts as specified in SILC protocol specification */
1544 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1548 SilcUInt32 dst_size,
1549 SilcUInt32 *ret_dst_len)
1551 SilcSILCPrivateKey silc_privkey = private_key;
1553 if (!silc_privkey->pkcs->decrypt)
1556 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1558 dst, dst_size, ret_dst_len);
1561 /* Signs as specified in SILC protocol specification */
1563 SilcBool silc_pkcs_silc_sign(void *private_key,
1566 unsigned char *signature,
1567 SilcUInt32 signature_size,
1568 SilcUInt32 *ret_signature_len,
1571 SilcSILCPrivateKey silc_privkey = private_key;
1573 if (!silc_privkey->pkcs->sign)
1576 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1578 signature, signature_size,
1579 ret_signature_len, hash);
1582 /* Verifies as specified in SILC protocol specification */
1584 SilcBool silc_pkcs_silc_verify(void *public_key,
1585 unsigned char *signature,
1586 SilcUInt32 signature_len,
1587 unsigned char *data,
1588 SilcUInt32 data_len,
1591 SilcSILCPublicKey silc_pubkey = public_key;
1593 if (!silc_pubkey->pkcs->verify)
1596 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1597 signature, signature_len,
1598 data, data_len, hash);