cli-authpubkey.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Dropbear SSH
  3. *
  4. * Copyright (c) 2002,2003 Matt Johnston
  5. * Copyright (c) 2004 by Mihnea Stoenescu
  6. * All rights reserved.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. * SOFTWARE. */
  25. #include "includes.h"
  26. #include "buffer.h"
  27. #include "dbutil.h"
  28. #include "session.h"
  29. #include "ssh.h"
  30. #include "runopts.h"
  31. #include "auth.h"
  32. #include "agentfwd.h"
  33. #ifdef ENABLE_CLI_PUBKEY_AUTH
  34. static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
  35. /* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
  36. * We use it to remove the key we tried from the list */
  37. void cli_pubkeyfail() {
  38. m_list_elem *iter;
  39. for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
  40. sign_key *iter_key = (sign_key*)iter->item;
  41. if (iter_key == cli_ses.lastprivkey)
  42. {
  43. /* found the failing key */
  44. list_remove(iter);
  45. sign_key_free(iter_key);
  46. cli_ses.lastprivkey = NULL;
  47. return;
  48. }
  49. }
  50. }
  51. void recv_msg_userauth_pk_ok() {
  52. m_list_elem *iter;
  53. buffer* keybuf = NULL;
  54. char* algotype = NULL;
  55. unsigned int algolen;
  56. enum signkey_type keytype;
  57. unsigned int remotelen;
  58. TRACE(("enter recv_msg_userauth_pk_ok"))
  59. algotype = buf_getstring(ses.payload, &algolen);
  60. keytype = signkey_type_from_name(algotype, algolen);
  61. TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
  62. m_free(algotype);
  63. keybuf = buf_new(MAX_PUBKEY_SIZE);
  64. remotelen = buf_getint(ses.payload);
  65. /* Iterate through our keys, find which one it was that matched, and
  66. * send a real request with that key */
  67. for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
  68. sign_key *key = (sign_key*)iter->item;
  69. if (key->type != keytype) {
  70. /* Types differed */
  71. TRACE(("types differed"))
  72. continue;
  73. }
  74. /* Now we compare the contents of the key */
  75. keybuf->pos = keybuf->len = 0;
  76. buf_put_pub_key(keybuf, key, keytype);
  77. buf_setpos(keybuf, 0);
  78. buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
  79. remotelen) which has already been taken from
  80. the remote buffer */
  81. if (keybuf->len-4 != remotelen) {
  82. TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen))
  83. /* Lengths differed */
  84. continue;
  85. }
  86. if (memcmp(buf_getptr(keybuf, remotelen),
  87. buf_getptr(ses.payload, remotelen), remotelen) != 0) {
  88. /* Data didn't match this key */
  89. TRACE(("data differed"))
  90. continue;
  91. }
  92. /* Success */
  93. break;
  94. }
  95. buf_free(keybuf);
  96. if (iter != NULL) {
  97. TRACE(("matching key"))
  98. /* XXX TODO: if it's an encrypted key, here we ask for their
  99. * password */
  100. send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
  101. } else {
  102. TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
  103. }
  104. TRACE(("leave recv_msg_userauth_pk_ok"))
  105. }
  106. void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
  107. buffer *data_buf) {
  108. #ifdef ENABLE_CLI_AGENTFWD
  109. if (key->source == SIGNKEY_SOURCE_AGENT) {
  110. /* Format the agent signature ourselves, as buf_put_sign would. */
  111. buffer *sigblob;
  112. sigblob = buf_new(MAX_PUBKEY_SIZE);
  113. agent_buf_sign(sigblob, key, data_buf);
  114. buf_putbufstring(buf, sigblob);
  115. buf_free(sigblob);
  116. } else
  117. #endif /* ENABLE_CLI_AGENTFWD */
  118. {
  119. buf_put_sign(buf, key, type, data_buf);
  120. }
  121. }
  122. /* TODO: make it take an agent reference to use as well */
  123. static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
  124. const char *algoname = NULL;
  125. unsigned int algolen;
  126. buffer* sigbuf = NULL;
  127. TRACE(("enter send_msg_userauth_pubkey"))
  128. CHECKCLEARTOWRITE();
  129. buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
  130. buf_putstring(ses.writepayload, cli_opts.username,
  131. strlen(cli_opts.username));
  132. buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
  133. SSH_SERVICE_CONNECTION_LEN);
  134. buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
  135. AUTH_METHOD_PUBKEY_LEN);
  136. buf_putbyte(ses.writepayload, realsign);
  137. algoname = signkey_name_from_type(type, &algolen);
  138. buf_putstring(ses.writepayload, algoname, algolen);
  139. buf_put_pub_key(ses.writepayload, key, type);
  140. if (realsign) {
  141. TRACE(("realsign"))
  142. /* We put the signature as well - this contains string(session id), then
  143. * the contents of the write payload to this point */
  144. sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
  145. buf_putbufstring(sigbuf, ses.session_id);
  146. buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
  147. cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
  148. buf_free(sigbuf); /* Nothing confidential in the buffer */
  149. }
  150. encrypt_packet();
  151. TRACE(("leave send_msg_userauth_pubkey"))
  152. }
  153. /* Returns 1 if a key was tried */
  154. int cli_auth_pubkey() {
  155. TRACE(("enter cli_auth_pubkey"))
  156. #ifdef ENABLE_CLI_AGENTFWD
  157. if (!cli_opts.agent_keys_loaded) {
  158. /* get the list of available keys from the agent */
  159. cli_load_agent_keys(cli_opts.privkeys);
  160. cli_opts.agent_keys_loaded = 1;
  161. }
  162. #endif
  163. if (cli_opts.privkeys->first) {
  164. sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
  165. /* Send a trial request */
  166. send_msg_userauth_pubkey(key, key->type, 0);
  167. cli_ses.lastprivkey = key;
  168. TRACE(("leave cli_auth_pubkey-success"))
  169. return 1;
  170. } else {
  171. /* no more keys left */
  172. TRACE(("leave cli_auth_pubkey-failure"))
  173. return 0;
  174. }
  175. }
  176. void cli_auth_pubkey_cleanup() {
  177. #ifdef ENABLE_CLI_AGENTFWD
  178. m_close(cli_opts.agent_fd);
  179. cli_opts.agent_fd = -1;
  180. #endif
  181. while (cli_opts.privkeys->first) {
  182. sign_key * key = list_remove(cli_opts.privkeys->first);
  183. sign_key_free(key);
  184. }
  185. }
  186. #endif /* Pubkey auth */