5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 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 #include "silcssh_pkcs.h"
25 /************************** Types and definitions ***************************/
27 /* RFC 4716 public key file markers */
28 #define SILC_SSH_PUBLIC_KEY_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
29 #define SILC_SSH_PUBLIC_KEY_END "---- END SSH2 PUBLIC KEY ----"
31 /* OpenSSH private key file markers */
32 #define SILC_SSH_RSA_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
33 #define SILC_SSH_RSA_END "-----END RSA PRIVATE KEY-----"
34 #define SILC_SSH_DSA_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
35 #define SILC_SSH_DSA_END "-----END DSA PRIVATE KEY-----"
37 /****************************** SSH2 PKCS API *******************************/
39 /* Get algorithm context */
41 SILC_PKCS_GET_ALGORITHM(silc_pkcs_ssh_get_algorithm)
43 SilcSshPublicKey pubkey = public_key;
47 /* Import public key file */
49 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_ssh_import_public_key_file)
51 SilcSshPublicKey pubkey;
52 SilcBufferStruct keybuf, line;
58 SILC_LOG_DEBUG(("Parsing SSH2 public key file"));
62 if (encoding == SILC_PKCS_FILE_BIN)
65 silc_buffer_set(&keybuf, filedata, filedata_len);
67 /* Check for RFC 4716 style public key markers */
68 if (!silc_ssh_parse_line(&keybuf, &line, TRUE)) {
69 SILC_LOG_DEBUG(("Malformed SSH2 public key markers"));
72 if ((silc_buffer_len(&keybuf) < (strlen(SILC_SSH_PUBLIC_KEY_BEGIN) +
73 strlen(SILC_SSH_PUBLIC_KEY_END))) ||
74 strncmp(silc_buffer_data(&line), SILC_SSH_PUBLIC_KEY_BEGIN,
75 silc_buffer_len(&line))) {
76 /* We assume the key is OpenSSH style public key. */
77 type = SILC_SSH_KEY_OPENSSH;
78 silc_buffer_set(&keybuf, filedata, filedata_len);
80 /* Get subject name from the end of the file */
81 if (!silc_buffer_strchr(&keybuf, ' ', FALSE)) {
82 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
85 if (!silc_buffer_pull(&keybuf, 1)) {
86 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
89 if (!silc_buffer_len(&keybuf)) {
90 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
94 /* Add subject name to public key headers */
95 fields = silc_ssh_allocate_fields();
98 silc_hash_table_add(fields, strdup("Subject"),
99 silc_memdup(silc_buffer_data(&keybuf),
100 silc_buffer_len(&keybuf)));
102 filedata_len = silc_buffer_headlen(&keybuf) - 1;
103 SILC_LOG_DEBUG(("Add Subject header to public key"));
105 /* Skip algorithm name */
106 silc_buffer_start(&keybuf);
107 if (!silc_buffer_strchr(&keybuf, ' ', TRUE)) {
108 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
109 silc_hash_table_free(fields);
112 if (!silc_buffer_pull(&keybuf, 1)) {
113 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
114 silc_hash_table_free(fields);
117 if (silc_buffer_len(&keybuf) < filedata_len) {
118 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
119 silc_hash_table_free(fields);
123 filedata = silc_buffer_data(&keybuf);
124 SILC_LOG_DEBUG(("Public key is OpenSSH public key"));
127 /* RFC 4716 style public key */
128 type = SILC_SSH_KEY_SSH2;
130 filedata = silc_buffer_data(&keybuf);
131 filedata_len = silc_buffer_len(&keybuf) - strlen(SILC_SSH_PUBLIC_KEY_END);
132 silc_buffer_set(&keybuf, filedata, filedata_len);
134 /* Parse public key headers */
135 fields = silc_ssh_parse_headers(&keybuf);
139 filedata = silc_buffer_data(&keybuf);
140 filedata_len = silc_buffer_len(&keybuf);
142 SILC_LOG_DEBUG(("Public key is standard SSH2 public key"));
146 data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len);
148 silc_hash_table_free(fields);
153 /* Decode the public key */
154 ret = silc_pkcs_ssh_import_public_key(pkcs, NULL, filedata, filedata_len,
155 (void *)&pubkey, ret_alg);
159 pubkey->fields = fields;
161 *ret_public_key = pubkey;
162 SILC_LOG_DEBUG(("SSH2 public key file imported successfully"));
166 silc_hash_table_free(fields);
170 /* Import public key */
172 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_ssh_import_public_key)
174 SilcSshPublicKey pubkey;
177 ret = silc_ssh_public_key_decode(key, key_len, &pubkey);
180 *ret_alg = pubkey->pkcs;
182 *ret_public_key = pubkey;
188 /* Export public key file */
190 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_ssh_export_public_key_file)
192 SilcSshPublicKey pubkey = public_key;
193 SilcHashTableList htl;
194 SilcBufferStruct buf, fields;
195 unsigned char *key, *data;
197 char *field, *value, tmp[1024], tmp2[1024 + 24];
200 SILC_LOG_DEBUG(("Encoding %s public key file",
201 pubkey->type == SILC_SSH_KEY_SSH2 ? "SSH2" : "OpenSSH"));
204 key = silc_pkcs_ssh_export_public_key(pkcs, stack, pubkey, &key_len);
208 /* Base64 encode the key data */
209 if (pubkey->type == SILC_SSH_KEY_SSH2)
210 data = silc_base64_encode_file(stack, key, key_len);
212 data = silc_base64_encode(stack, key, key_len);
215 silc_sfree(stack, key);
217 key_len = strlen(data);
219 memset(&buf, 0, sizeof(buf));
220 memset(&fields, 0, sizeof(fields));
221 memset(tmp, 0, sizeof(tmp));
222 memset(tmp2, 0, sizeof(tmp2));
224 switch (pubkey->type) {
225 case SILC_SSH_KEY_SSH2:
226 /* RFC 4716 style public key file */
228 if (pubkey->fields) {
229 /* Encode public key headers */
230 silc_hash_table_list(pubkey->fields, &htl);
231 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) {
232 /* Wrap lines with over 72 characters */
233 silc_snprintf(tmp, sizeof(tmp), "%s: %s", field, value);
234 for (i = 0, j = 0, c = 1; i < strlen(tmp); i++, c++) {
247 if (silc_buffer_sstrformat(stack, &fields, tmp2, SILC_STRFMT_END) < 0) {
248 silc_buffer_spurge(stack, &fields);
249 silc_sfree(stack, key);
253 memset(tmp2, 0, sizeof(tmp2));
255 silc_hash_table_list_reset(&htl);
258 /* Encode the file */
259 if (silc_buffer_sformat(stack, &buf,
260 SILC_STR_UI32_STRING(SILC_SSH_PUBLIC_KEY_BEGIN),
261 SILC_STR_UI32_STRING("\n"),
262 SILC_STR_UI_XNSTRING(silc_buffer_data(&fields),
263 silc_buffer_len(&fields)),
264 SILC_STR_UI_XNSTRING(key, key_len),
265 SILC_STR_UI32_STRING("\n"),
266 SILC_STR_UI32_STRING(SILC_SSH_PUBLIC_KEY_END),
267 SILC_STR_UI32_STRING("\n"),
269 silc_buffer_spurge(stack, &fields);
270 silc_sfree(stack, key);
276 case SILC_SSH_KEY_OPENSSH:
277 /* OpenSSH style public key file */
279 if (!strcmp(pubkey->pkcs->name, "rsa"))
280 silc_snprintf(tmp, sizeof(tmp), "ssh-rsa ");
281 else if (!strcmp(pubkey->pkcs->name, "dsa"))
282 silc_snprintf(tmp, sizeof(tmp), "ssh-dss ");
285 value = (char *)silc_ssh_public_key_get_field(pubkey, "Subject");
287 /* Encode the file */
288 if (silc_buffer_sformat(stack, &buf,
289 SILC_STR_UI32_STRING(tmp),
290 SILC_STR_UI_XNSTRING(key, key_len),
291 SILC_STR_UI32_STRING(" "),
292 SILC_STR_UI32_STRING(value),
293 SILC_STR_UI32_STRING("\n"),
295 silc_buffer_spurge(stack, &buf);
296 silc_sfree(stack, key);
303 silc_sfree(stack, key);
308 silc_sfree(stack, key);
309 key = silc_buffer_steal(&buf, ret_len);
311 silc_buffer_spurge(stack, &fields);
316 /* Export public key */
318 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_ssh_export_public_key)
320 return silc_ssh_public_key_encode(stack, public_key, ret_len);
323 /* Return key length in bits */
325 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_ssh_public_key_bitlen)
327 SilcSshPublicKey pubkey = public_key;
328 return pubkey->pkcs->public_key_bitlen(pubkey->pkcs, pubkey->public_key);
331 /* Copy public key */
333 SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_ssh_public_key_copy)
335 SilcSshPublicKey pubkey = public_key, new_pubkey;
336 SilcHashTableList htl;
339 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
342 new_pubkey->pkcs = pubkey->pkcs;
343 new_pubkey->type = pubkey->type;
345 new_pubkey->public_key =
346 pubkey->pkcs->public_key_copy(pubkey->pkcs, pubkey->public_key);
347 if (!new_pubkey->public_key) {
348 silc_free(new_pubkey);
352 if (pubkey->fields) {
353 new_pubkey->fields = silc_ssh_allocate_fields();
354 if (!new_pubkey->fields) {
355 pubkey->pkcs->public_key_free(pubkey->pkcs, pubkey->public_key);
356 silc_free(new_pubkey);
360 silc_hash_table_list(pubkey->fields, &htl);
361 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value))
362 silc_hash_table_add(new_pubkey->fields, strdup(field), strdup(value));
363 silc_hash_table_list_reset(&htl);
369 /* Compare two public keys */
371 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_ssh_public_key_compare)
373 SilcSshPublicKey k1 = key1, k2 = key2;
374 SilcHashTableList htl;
375 char *field, *value, *value2;
377 if (strcmp(k1->pkcs->name, k2->pkcs->name))
380 if (k1->fields && !k2->fields)
382 if (!k1->fields && k2->fields)
385 if (k1->fields && k2->fields) {
386 if (silc_hash_table_count(k1->fields) != silc_hash_table_count(k2->fields))
389 silc_hash_table_list(k1->fields, &htl);
390 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) {
391 value2 = (char *)silc_ssh_public_key_get_field(k2, field);
394 if (strcmp(value, value2))
397 silc_hash_table_list_reset(&htl);
400 return k1->pkcs->public_key_compare(k1->pkcs, k1->public_key,
404 /* Free public key */
406 SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_ssh_public_key_free)
408 silc_ssh_public_key_free(public_key);
411 /* Import private key file. Supports only OpenSSH (OpenSSL to be exact)
412 private key files. */
414 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_ssh_import_private_key_file)
416 const SilcPKCSAlgorithm *alg;
417 SilcSshPrivateKey privkey = NULL;
418 SilcHashTable fields;
419 SilcBufferStruct keybuf, line;
420 unsigned char *data, iv[8], key[32];
422 char *proctype, *dekinfo;
427 SILC_LOG_DEBUG(("Parsing SSH2 private key file"));
429 if (!ret_private_key)
431 if (encoding == SILC_PKCS_FILE_BIN)
434 silc_buffer_set(&keybuf, filedata, filedata_len);
436 /* Check for private key markers */
437 if (!silc_ssh_parse_line(&keybuf, &line, TRUE)) {
438 SILC_LOG_DEBUG(("Malformed SSH2 private key markers"));
441 if ((silc_buffer_len(&keybuf) < (strlen(SILC_SSH_RSA_BEGIN) +
442 strlen(SILC_SSH_RSA_END))) ||
443 (strncmp(silc_buffer_data(&line), SILC_SSH_RSA_BEGIN,
444 silc_buffer_len(&line)) &&
445 strncmp(silc_buffer_data(&line), SILC_SSH_DSA_BEGIN,
446 silc_buffer_len(&line)))) {
447 SILC_LOG_DEBUG(("Malformed SSH2 private key markers"));
451 /* Get PKCS algorithm */
452 if (!strncmp(silc_buffer_data(&line), SILC_SSH_RSA_BEGIN,
453 silc_buffer_len(&line))) {
454 alg = silc_pkcs_find_algorithm("rsa", "ssh");
456 SILC_LOG_ERROR(("Unsupported PKCS algorithm rsa/ssh"));
459 } else if (!strncmp(silc_buffer_data(&line), SILC_SSH_DSA_BEGIN,
460 silc_buffer_len(&line))) {
461 alg = silc_pkcs_find_algorithm("dsa", "ssh");
463 SILC_LOG_ERROR(("Unsupported PKCS algorithm dsa/ssh"));
469 type = SILC_SSH_KEY_OPENSSH;
470 filedata = silc_buffer_data(&keybuf);
472 /* Skip end marker */
473 if (!silc_buffer_strchr(&keybuf, '-', FALSE)) {
474 SILC_LOG_DEBUG(("Malformed SSH2 private key markers"));
477 filedata_len = silc_buffer_data(&keybuf) - filedata;
478 silc_buffer_set(&keybuf, filedata, filedata_len);
480 /* Parse private key headers. They define how the private key has been
482 fields = silc_ssh_parse_headers(&keybuf);
486 /* Skip empty line after headers */
487 if (silc_hash_table_count(fields) > 0)
488 silc_ssh_parse_line(&keybuf, NULL, TRUE);
490 filedata = silc_buffer_data(&keybuf);
491 filedata_len = silc_buffer_len(&keybuf);
494 data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len);
496 SILC_LOG_DEBUG(("Malformed SSH2 private key"));
501 SILC_LOG_DEBUG(("Private key is %s", (silc_hash_table_count(fields) ?
502 "encrypted" : "not encrypted")));
504 if (silc_hash_table_count(fields) > 0 && passphrase) {
507 /* Get encryption info */
508 if (!silc_hash_table_find(fields, "Proc-Type", NULL, (void *)&proctype)) {
509 SILC_LOG_ERROR(("Malformed SSH2 private key"));
512 if (strcmp(proctype, "4,ENCRYPTED")) {
513 SILC_LOG_ERROR(("Malformed SSH2 private key"));
517 /* OpenSSH uses 3DES-EDE only */
518 if (!silc_hash_table_find(fields, "DEK-Info", NULL, (void *)&dekinfo)) {
519 SILC_LOG_ERROR(("Malformed SSH2 private key"));
522 if (strncmp(dekinfo, "DES-EDE3-CBC", strlen("DES-EDE3-CBC"))) {
523 SILC_LOG_ERROR(("Unsupported SSH2 private key cipher '%s'", dekinfo));
527 /* Allocate cipher */
528 if (!silc_cipher_alloc("3des-168-cbc", &des)) {
529 SILC_LOG_ERROR(("Unsupported algorithm 3des-168-cbc"));
534 if (!silc_hash_alloc("md5", &md5)) {
535 SILC_LOG_ERROR(("Unsupported hash algorithm md5"));
539 /* Get IV from private key file */
540 dekinfo = strchr(dekinfo, ',');
541 if (!dekinfo || strlen(dekinfo) < 16) {
542 SILC_LOG_ERROR(("Malformed SSH2 private key"));
546 silc_hex2data(dekinfo, iv, sizeof(iv), NULL);
548 /* Generate key from passphrase and IV as salt. The passphrase is
549 hashed with the IV, then rehashed with the previous hash, passphrase
550 and the IV to produce the final key, which is the concatenation of
553 silc_hash_update(md5, passphrase, passphrase_len);
554 silc_hash_update(md5, iv, 8);
555 silc_hash_final(md5, key);
557 silc_hash_update(md5, key, 16);
558 silc_hash_update(md5, passphrase, passphrase_len);
559 silc_hash_update(md5, iv, 8);
560 silc_hash_final(md5, key + 16);
563 silc_cipher_set_key(des, key, 192, FALSE);
564 if (!silc_cipher_decrypt(des, filedata, filedata, filedata_len, iv)) {
565 SILC_LOG_ERROR(("Malformed SSH2 private key"));
566 silc_cipher_free(des);
571 silc_cipher_free(des);
575 /* Decode the private key */
576 ret = silc_pkcs_ssh_import_private_key(pkcs, alg, filedata, filedata_len,
577 (void *)&privkey, ret_alg);
581 privkey->fields = fields;
582 privkey->type = type;
583 *ret_private_key = privkey;
584 SILC_LOG_DEBUG(("SSH2 private key file imported successfully"));
590 silc_hash_table_free(fields);
594 /* Import private key. The key format for RSA is PKCS#1 compliant and for
595 DSA is equivalent to our DSA implementation, so we just simply call the
596 algorithm specific import function to do the magic. */
598 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_ssh_import_private_key)
600 SilcSshPrivateKey privkey;
603 if (!ret_private_key || !alg)
606 /* Allocate SSH private key context */
607 privkey = silc_calloc(1, sizeof(*privkey));
611 /* Import PKCS algorithm private key */
612 ret = alg->import_private_key(alg, key, key_len, &privkey->private_key);
619 privkey->type = SILC_SSH_KEY_OPENSSH;
621 *ret_private_key = privkey;
628 /* Export private key file */
630 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_ssh_export_private_key_file)
632 SilcSshPrivateKey privkey = private_key;
633 const SilcPKCSAlgorithm *alg = privkey->pkcs;
634 SilcBufferStruct buf;
635 unsigned char *key, *keyenc, ivdata[8], iv[16 + 1], enc[32];
636 SilcUInt32 key_len, pad_len;
637 SilcCipher des = NULL;
640 SILC_LOG_DEBUG(("Encode SSH2 private key file"));
642 /* Export the private key */
643 key = silc_pkcs_ssh_export_private_key(pkcs, stack, private_key, &key_len);
647 memset(&buf, 0, sizeof(buf));
648 if (!strcmp(alg->name, "rsa")) {
649 if (silc_buffer_sformat(stack, &buf,
651 SILC_STR_UI32_STRING(SILC_SSH_RSA_BEGIN),
652 SILC_STR_UI32_STRING("\n"),
655 } else if (!strcmp(alg->name, "dsa")) {
656 if (silc_buffer_sformat(stack, &buf,
658 SILC_STR_UI32_STRING(SILC_SSH_DSA_BEGIN),
659 SILC_STR_UI32_STRING("\n"),
665 if (passphrase && strlen(passphrase) > 0) {
666 /* Encrypt the key */
668 /* Allocate cipher */
669 if (!silc_cipher_alloc("3des-168-cbc", &des)) {
670 SILC_LOG_ERROR(("Unsupported algorithm 3des-168-cbc"));
675 if (!silc_hash_alloc("md5", &md5)) {
676 SILC_LOG_ERROR(("Unsupported hash algorithm md5"));
681 silc_rng_get_rn_data(rng, sizeof(ivdata), ivdata, sizeof(ivdata));
682 silc_data2hex(ivdata, sizeof(ivdata), iv, sizeof(iv));
685 if (silc_buffer_sformat(stack, &buf,
687 SILC_STR_UI32_STRING("Proc-Type: 4,ENCRYPTED\n"),
688 SILC_STR_UI32_STRING("DEK-Info: DES-EDE3-CBC,"),
689 SILC_STR_UI32_STRING(iv),
690 SILC_STR_UI32_STRING("\n\n"),
694 /* Generate key from passphrase and IV as salt. The passphrase is
695 hashed with the IV, then rehashed with the previous hash, passphrase
696 and the IV to produce the final key, which is the concatenation of
699 silc_hash_update(md5, passphrase, passphrase_len);
700 silc_hash_update(md5, ivdata, 8);
701 silc_hash_final(md5, enc);
703 silc_hash_update(md5, enc, 16);
704 silc_hash_update(md5, passphrase, passphrase_len);
705 silc_hash_update(md5, ivdata, 8);
706 silc_hash_final(md5, enc + 16);
709 pad_len = 8 - (key_len % 8);
711 keyenc = silc_smalloc(stack, (key_len + pad_len) * sizeof(*keyenc));
714 memset(keyenc + key_len, 'F', pad_len);
715 memcpy(keyenc, key, key_len);
717 keyenc = silc_memdup(key, key_len);
723 silc_cipher_set_key(des, enc, 192, TRUE);
724 silc_cipher_encrypt(des, keyenc, keyenc, key_len + pad_len, ivdata);
726 silc_sfree(stack, key);
730 silc_cipher_free(des);
735 keyenc = silc_base64_encode_file(stack, key, key_len);
739 silc_sfree(stack, key);
741 key_len = strlen(keyenc);
743 /* Encode rest of the public key */
744 if (!strcmp(alg->name, "rsa")) {
745 if (silc_buffer_sformat(stack, &buf,
747 SILC_STR_DATA(key, key_len),
748 SILC_STR_UI32_STRING("\n"),
749 SILC_STR_UI32_STRING(SILC_SSH_RSA_END),
750 SILC_STR_UI32_STRING("\n"),
753 } else if (!strcmp(alg->name, "dsa")) {
754 if (silc_buffer_sformat(stack, &buf,
756 SILC_STR_DATA(key, key_len),
757 SILC_STR_UI32_STRING("\n"),
758 SILC_STR_UI32_STRING(SILC_SSH_DSA_END),
759 SILC_STR_UI32_STRING("\n"),
764 silc_sfree(stack, key);
765 key = silc_buffer_steal(&buf, ret_len);
770 silc_cipher_free(des);
773 silc_sfree(stack, key);
777 /* Export private key */
779 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_ssh_export_private_key)
781 SilcSshPrivateKey privkey = private_key;
782 const SilcPKCSAlgorithm *alg = privkey->pkcs;
784 SILC_LOG_DEBUG(("Encode SSH2 private key"));
786 /* Export PKCS algorithm private key */
787 if (alg->export_private_key)
788 return alg->export_private_key(alg, stack,
789 privkey->private_key, ret_len);
793 /* Return key length in bits */
795 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_ssh_private_key_bitlen)
797 SilcSshPrivateKey privkey = private_key;
798 return privkey->pkcs->private_key_bitlen(privkey->pkcs,
799 privkey->private_key);
802 /* Free private key */
804 SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_ssh_private_key_free)
806 SilcSshPrivateKey privkey = private_key;
808 privkey->pkcs->private_key_free(privkey->pkcs,
809 privkey->private_key);
812 silc_hash_table_free(privkey->fields);
818 SILC_PKCS_ENCRYPT(silc_pkcs_ssh_encrypt)
820 SilcSshPublicKey pubkey = public_key;
822 if (!pubkey->pkcs->encrypt) {
823 encrypt_cb(FALSE, NULL, 0, context);
827 return pubkey->pkcs->encrypt(pubkey->pkcs, pubkey->public_key,
828 src, src_len, rng, encrypt_cb, context);
833 SILC_PKCS_DECRYPT(silc_pkcs_ssh_decrypt)
835 SilcSshPrivateKey privkey = private_key;
837 if (!privkey->pkcs->decrypt) {
838 decrypt_cb(FALSE, NULL, 0, context);
842 return privkey->pkcs->decrypt(privkey->pkcs, privkey->private_key,
843 src, src_len, decrypt_cb, context);
848 SILC_PKCS_SIGN(silc_pkcs_ssh_sign)
850 SilcSshPrivateKey privkey = private_key;
852 if (!privkey->pkcs->sign) {
853 sign_cb(FALSE, NULL, 0, context);
857 return privkey->pkcs->sign(privkey->pkcs, privkey->private_key,
859 compute_hash, hash, rng,
865 SILC_PKCS_VERIFY(silc_pkcs_ssh_verify)
867 SilcSshPublicKey pubkey = public_key;
869 if (!pubkey->pkcs->verify) {
870 verify_cb(FALSE, context);
874 return pubkey->pkcs->verify(pubkey->pkcs, pubkey->public_key,
875 signature, signature_len,
876 data, data_len, hash, rng,
880 /************************** SSH2 PKCS RSA Alg API ***************************/
882 /* The SSH2 RSA PKCS Algorithm API. We implement here only the necessary
883 parts of the API and the common code is used from PKCS#1 Algorithm API
884 in silccrypt/silcpkcs1.c. Basically everything else is PKCS#1 except
885 the format of the public key. */
887 /* Import RSA public key. Both RFC 4716 and OpenSSH have same format. */
889 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_ssh_rsa_import_public_key)
891 SilcBufferStruct alg_key;
892 RsaPublicKey *pubkey;
893 unsigned char *n, *e;
894 SilcUInt32 n_len, e_len;
897 SILC_LOG_DEBUG(("Import public key"));
902 /* Allocate RSA public key */
903 *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
907 /* Parse SSH2 RSA public key */
908 silc_buffer_set(&alg_key, key, key_len);
909 ret = silc_buffer_unformat(&alg_key,
910 SILC_STR_UI32_NSTRING(&e, &e_len),
911 SILC_STR_UI32_NSTRING(&n, &n_len),
915 if (!n_len || !e_len)
918 /* Get MP integers */
919 silc_mp_init(&pubkey->n);
920 silc_mp_init(&pubkey->e);
921 silc_mp_bin2mp(n, n_len, &pubkey->n);
922 silc_mp_bin2mp(e, e_len, &pubkey->e);
925 pubkey->bits = ((silc_mp_sizeinbase(&pubkey->n, 2) + 7) / 8) * 8;
934 /* Export RSA public key. Both RFC 4716 and OpenSSH have same format. */
936 SILC_PKCS_ALG_EXPORT_PUBLIC_KEY(silc_ssh_rsa_export_public_key)
938 RsaPublicKey *pubkey = public_key;
939 SilcBufferStruct alg_key;
940 unsigned char *n = NULL, *e = NULL, *ret;
941 SilcUInt32 n_len, e_len;
943 SILC_LOG_DEBUG(("Export public key"));
945 /* Encode MP integers */
946 n = silc_mp_mp2bin(&pubkey->n, 0, &n_len);
949 e = silc_mp_mp2bin(&pubkey->e, 0, &e_len);
953 /* Encode SSH2 RSA public key */
954 memset(&alg_key, 0, sizeof(alg_key));
955 if (silc_buffer_sformat(stack, &alg_key,
956 SILC_STR_UI_INT(e_len),
957 SILC_STR_DATA(e, e_len),
958 SILC_STR_UI_INT(n_len),
959 SILC_STR_DATA(n, n_len),
966 ret = silc_buffer_steal(&alg_key, ret_len);
975 /************************** SSH2 PKCS DSA Alg API ***************************/
977 /* The SSH2 DSA PKCS Algorithm API. We implement here only the necessary
978 parts of the API and the common code is used from DSS Algorithm API
979 in silccrypt/dsa.c. */
981 /* Import DSA public key. Both RFC 4716 and OpenSSH have same format. */
983 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_ssh_dsa_import_public_key)
985 SilcBufferStruct alg_key;
986 DsaPublicKey *pubkey;
987 unsigned char *p, *q, *g, *y;
988 SilcUInt32 p_len, q_len, g_len, y_len;
991 SILC_LOG_DEBUG(("Import public key"));
996 /* Allocate DSA public key */
997 *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
1001 /* Parse SSH2 DSA public key */
1002 silc_buffer_set(&alg_key, key, key_len);
1003 ret = silc_buffer_unformat(&alg_key,
1004 SILC_STR_UI32_NSTRING(&p, &p_len),
1005 SILC_STR_UI32_NSTRING(&q, &q_len),
1006 SILC_STR_UI32_NSTRING(&g, &g_len),
1007 SILC_STR_UI32_NSTRING(&y, &y_len),
1011 if (!p_len || !q_len || !g_len || !y_len)
1014 /* Get MP integers */
1015 silc_mp_init(&pubkey->p);
1016 silc_mp_init(&pubkey->q);
1017 silc_mp_init(&pubkey->g);
1018 silc_mp_init(&pubkey->y);
1019 silc_mp_bin2mp(p, p_len, &pubkey->p);
1020 silc_mp_bin2mp(q, q_len, &pubkey->q);
1021 silc_mp_bin2mp(g, g_len, &pubkey->g);
1022 silc_mp_bin2mp(y, y_len, &pubkey->y);
1024 /* Set key length */
1025 pubkey->bits = ((silc_mp_sizeinbase(&pubkey->p, 2) + 7) / 8) * 8;
1034 /* Export DSA public key. Both RFC 4716 and OpenSSH have same format. */
1036 SILC_PKCS_ALG_EXPORT_PUBLIC_KEY(silc_ssh_dsa_export_public_key)
1038 DsaPublicKey *pubkey = public_key;
1039 SilcBufferStruct alg_key;
1040 unsigned char *p = NULL, *q = NULL, *g = NULL, *y = NULL, *ret;
1041 SilcUInt32 p_len, q_len, g_len, y_len;
1043 SILC_LOG_DEBUG(("Export public key"));
1045 /* Encode MP integers */
1046 p = silc_mp_mp2bin(&pubkey->p, 0, &p_len);
1049 q = silc_mp_mp2bin(&pubkey->q, 0, &q_len);
1052 g = silc_mp_mp2bin(&pubkey->g, 0, &g_len);
1055 y = silc_mp_mp2bin(&pubkey->y, 0, &y_len);
1059 /* Encode SSH2 DSA public key */
1060 memset(&alg_key, 0, sizeof(alg_key));
1061 if (silc_buffer_sformat(stack, &alg_key,
1062 SILC_STR_UI_INT(p_len),
1063 SILC_STR_DATA(p, p_len),
1064 SILC_STR_UI_INT(q_len),
1065 SILC_STR_DATA(q, q_len),
1066 SILC_STR_UI_INT(g_len),
1067 SILC_STR_DATA(g, g_len),
1068 SILC_STR_UI_INT(y_len),
1069 SILC_STR_DATA(y, y_len),
1078 ret = silc_buffer_steal(&alg_key, ret_len);