key-type.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* key-type.c -- SSH key smobs.
  2. *
  3. * Copyright (C) 2013, 2014, 2015, 2016 Artyom V. Poptsov <poptsov.artyom@gmail.com>
  4. *
  5. * This file is part of Guile-SSH
  6. *
  7. * Guile-SSH is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation, either version 3 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * Guile-SSH is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Guile-SSH. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <config.h>
  21. #include <libguile.h>
  22. #include <libssh/libssh.h>
  23. #include "key-type.h"
  24. #include "common.h"
  25. #include "error.h"
  26. /* BUG: Currently a SSH key that has been read from a file has both
  27. public and private flags. It means that we cannot distinguish
  28. whether the key is private or public by means of
  29. `ssh_key_is_private' and `ssh_key_is_public' procedures (they both
  30. return true).
  31. See `ssh_pki_import_privkey_file' and `pki_private_key_from_base64'
  32. in libssh 0.6.3 for details. -avp */
  33. scm_t_bits key_tag; /* Smob tag. */
  34. static const struct symbol_mapping key_types[] = {
  35. { "dss", SSH_KEYTYPE_DSS },
  36. { "rsa", SSH_KEYTYPE_RSA },
  37. { "rsa1", SSH_KEYTYPE_RSA1 },
  38. { "ecdsa", SSH_KEYTYPE_ECDSA },
  39. { "ed25519", SSH_KEYTYPE_ED25519 },
  40. { "unknown", SSH_KEYTYPE_UNKNOWN },
  41. { NULL, -1 }
  42. };
  43. /* Smob marking */
  44. static SCM
  45. mark_key_smob (SCM key_smob)
  46. {
  47. struct key_data *kd = _scm_to_key_data (key_smob);
  48. return kd->parent;
  49. }
  50. /* Free the smob. */
  51. static size_t
  52. free_key_smob (SCM arg1)
  53. {
  54. struct key_data *data = (struct key_data *) SCM_SMOB_DATA (arg1);
  55. if (scm_is_false (data->parent))
  56. {
  57. /* It's safe to free the key only if it was not derived from some other
  58. object and thereby does not share any resources with it. If the key
  59. does have a parent then all the resources will be freed along with
  60. it. */
  61. ssh_key_free (data->ssh_key);
  62. }
  63. return 0;
  64. }
  65. static int
  66. print_key (SCM smob, SCM port, scm_print_state *pstate)
  67. {
  68. struct key_data *key_data = _scm_to_key_data (smob);
  69. SCM type = guile_ssh_key_get_type (smob);
  70. scm_puts ("#<key ", port);
  71. scm_display (type, port);
  72. scm_putc (' ', port);
  73. scm_puts (_private_key_p (key_data) ? "(private) " : "(public) ", port);
  74. scm_display (_scm_object_hex_address (smob), port);
  75. scm_puts (">", port);
  76. return 1;
  77. }
  78. /* Convert SSH key type to/from a Scheme symbol.
  79. Possible symbols are: 'dss, 'rsa, 'rsa1, 'ecdsa, 'unknown */
  80. SCM
  81. _ssh_key_type_to_scm (int type)
  82. {
  83. return _ssh_const_to_scm (key_types, type);
  84. }
  85. const struct symbol_mapping *
  86. _scm_to_ssh_key_type (SCM type)
  87. {
  88. return _scm_to_ssh_const (key_types, type);
  89. }
  90. /* Get the type of the key KEY_SMOB.
  91. Return a key type as a Scheme symbol. The type can be one of the
  92. following list: 'dss, 'rsa, 'rsa1, 'unknown */
  93. SCM_DEFINE (guile_ssh_key_get_type, "get-key-type", 1, 0, 0,
  94. (SCM key),
  95. "\
  96. Get a symbol that represents the type of the SSH key KEY.\n\
  97. Possible types are: 'dss, 'rsa, 'rsa1, 'ecdsa, 'unknown\
  98. ")
  99. {
  100. struct key_data *data = _scm_to_key_data (key);
  101. enum ssh_keytypes_e type = ssh_key_type (data->ssh_key);
  102. return _ssh_key_type_to_scm (type);
  103. }
  104. SCM_DEFINE (guile_ssh_make_keypair, "make-keypair", 2, 0, 0,
  105. (SCM type, SCM length),
  106. "\
  107. Generate a keypair of specified TYPE and LENGTH. This may take some time.\
  108. Return newly generated private key. Throw `guile-ssh-error' on error.\
  109. ")
  110. #define FUNC_NAME s_guile_ssh_make_keypair
  111. {
  112. ssh_key key = NULL;
  113. const struct symbol_mapping *c_type = _scm_to_ssh_key_type (type);
  114. int c_length;
  115. int res;
  116. SCM_ASSERT (scm_is_unsigned_integer (length, 9, UINT32_MAX), length,
  117. SCM_ARG2, FUNC_NAME);
  118. if (! c_type)
  119. guile_ssh_error1 (FUNC_NAME, "Wrong key type", type);
  120. c_length = scm_to_int (length);
  121. res = ssh_pki_generate (c_type->value, c_length, &key);
  122. if (res == SSH_ERROR)
  123. {
  124. guile_ssh_error1 (FUNC_NAME, "Could not generate key",
  125. scm_list_2 (type, length));
  126. }
  127. return _scm_from_ssh_key (key, SCM_BOOL_F);
  128. }
  129. #undef FUNC_NAME
  130. /* Predicates */
  131. SCM_DEFINE (guile_ssh_is_key_p, "key?", 1, 0, 0,
  132. (SCM x),
  133. "\
  134. Return #t if X is a SSH key, #f otherwise.\
  135. ")
  136. {
  137. return scm_from_bool (SCM_SMOB_PREDICATE (key_tag, x));
  138. }
  139. SCM_DEFINE (guile_ssh_is_public_key_p, "public-key?", 1, 0, 0,
  140. (SCM x),
  141. "\
  142. Return #t if X is a SSH key and it contains a public key, #f otherwise.\
  143. ")
  144. {
  145. return scm_from_bool (SCM_SMOB_PREDICATE (key_tag, x)
  146. && _public_key_p (_scm_to_key_data (x)));
  147. }
  148. SCM_DEFINE (guile_ssh_is_private_key_p, "private-key?", 1, 0, 0,
  149. (SCM x),
  150. "\
  151. Return #t if X is a SSH private-key, #f otherwise.\
  152. ")
  153. {
  154. return scm_from_bool (SCM_SMOB_PREDICATE (key_tag, x)
  155. && _private_key_p (_scm_to_key_data (x)));
  156. }
  157. static SCM
  158. equalp_key (SCM x1, SCM x2)
  159. {
  160. struct key_data *key1 = _scm_to_key_data (x1);
  161. struct key_data *key2 = _scm_to_key_data (x2);
  162. if ((! key1) || (! key2))
  163. return SCM_BOOL_F;
  164. else if (key1 != key2)
  165. return SCM_BOOL_F;
  166. else
  167. return SCM_BOOL_T;
  168. }
  169. /* Helper procedures */
  170. SCM
  171. _scm_from_ssh_key (ssh_key key, SCM parent)
  172. {
  173. struct key_data *key_data;
  174. SCM key_smob;
  175. key_data = (struct key_data *) scm_gc_malloc (sizeof (struct key_data),
  176. "ssh key");
  177. key_data->ssh_key = key;
  178. key_data->parent = parent;
  179. SCM_NEWSMOB (key_smob, key_tag, key_data);
  180. return key_smob;
  181. }
  182. /* Convert X to a SSH key */
  183. struct key_data *
  184. _scm_to_key_data (SCM x)
  185. {
  186. scm_assert_smob_type (key_tag, x);
  187. return (struct key_data *) SCM_SMOB_DATA (x);
  188. }
  189. /* Check that KEY is a SSH private key. */
  190. int
  191. _private_key_p (struct key_data *key)
  192. {
  193. return ssh_key_is_private (key->ssh_key);
  194. }
  195. /* Check that KEY is a SSH public key */
  196. int
  197. _public_key_p (struct key_data *key)
  198. {
  199. return ssh_key_is_public (key->ssh_key);
  200. }
  201. /* Key smob initialization. */
  202. void
  203. init_key_type (void)
  204. {
  205. key_tag = scm_make_smob_type ("key", sizeof (struct key_data));
  206. scm_set_smob_mark (key_tag, mark_key_smob);
  207. scm_set_smob_free (key_tag, free_key_smob);
  208. scm_set_smob_print (key_tag, print_key);
  209. scm_set_smob_equalp (key_tag, equalp_key);
  210. #include "key-type.x"
  211. }
  212. /* private-key.c ends here */