Home | History | Annotate | Download | only in dropbear
      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 
     26 #include "includes.h"
     27 #include "buffer.h"
     28 #include "dbutil.h"
     29 #include "session.h"
     30 #include "ssh.h"
     31 #include "runopts.h"
     32 #include "auth.h"
     33 
     34 #ifdef ENABLE_CLI_PUBKEY_AUTH
     35 static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
     36 
     37 /* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
     38  * We use it to remove the key we tried from the list */
     39 void cli_pubkeyfail() {
     40 
     41 	struct SignKeyList *keyitem;
     42 	struct SignKeyList **previtem;
     43 
     44 	TRACE(("enter cli_pubkeyfail"))
     45 	previtem = &cli_opts.privkeys;
     46 
     47 	/* Find the key we failed with, and remove it */
     48 	for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
     49 		if (keyitem == cli_ses.lastprivkey) {
     50 			*previtem = keyitem->next;
     51 		}
     52 		previtem = &keyitem;
     53 	}
     54 
     55 	sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
     56 	m_free(cli_ses.lastprivkey);
     57 
     58 	TRACE(("leave cli_pubkeyfail"))
     59 }
     60 
     61 void recv_msg_userauth_pk_ok() {
     62 
     63 	struct SignKeyList *keyitem = NULL;
     64 	buffer* keybuf = NULL;
     65 	char* algotype = NULL;
     66 	unsigned int algolen;
     67 	int keytype;
     68 	unsigned int remotelen;
     69 
     70 	TRACE(("enter recv_msg_userauth_pk_ok"))
     71 
     72 	algotype = buf_getstring(ses.payload, &algolen);
     73 	keytype = signkey_type_from_name(algotype, algolen);
     74 	TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
     75 	m_free(algotype);
     76 
     77 	keybuf = buf_new(MAX_PUBKEY_SIZE);
     78 
     79 	remotelen = buf_getint(ses.payload);
     80 
     81 	/* Iterate through our keys, find which one it was that matched, and
     82 	 * send a real request with that key */
     83 	for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
     84 
     85 		if (keyitem->type != keytype) {
     86 			/* Types differed */
     87 			TRACE(("types differed"))
     88 			continue;
     89 		}
     90 
     91 		/* Now we compare the contents of the key */
     92 		keybuf->pos = keybuf->len = 0;
     93 		buf_put_pub_key(keybuf, keyitem->key, keytype);
     94 		buf_setpos(keybuf, 0);
     95 		buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
     96 								   remotelen) which has already been taken from
     97 								   the remote buffer */
     98 
     99 
    100 		if (keybuf->len-4 != remotelen) {
    101 			TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen))
    102 			/* Lengths differed */
    103 			continue;
    104 		}
    105 		if (memcmp(buf_getptr(keybuf, remotelen),
    106 					buf_getptr(ses.payload, remotelen), remotelen) != 0) {
    107 			/* Data didn't match this key */
    108 			TRACE(("data differed"))
    109 			continue;
    110 		}
    111 
    112 		/* Success */
    113 		break;
    114 	}
    115 	buf_free(keybuf);
    116 
    117 	if (keyitem != NULL) {
    118 		TRACE(("matching key"))
    119 		/* XXX TODO: if it's an encrypted key, here we ask for their
    120 		 * password */
    121 		send_msg_userauth_pubkey(keyitem->key, keytype, 1);
    122 	} else {
    123 		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"))
    124 	}
    125 
    126 	TRACE(("leave recv_msg_userauth_pk_ok"))
    127 }
    128 
    129 /* TODO: make it take an agent reference to use as well */
    130 static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
    131 
    132 	const char *algoname = NULL;
    133 	int algolen;
    134 	buffer* sigbuf = NULL;
    135 
    136 	TRACE(("enter send_msg_userauth_pubkey"))
    137 	CHECKCLEARTOWRITE();
    138 
    139 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
    140 
    141 	buf_putstring(ses.writepayload, cli_opts.username,
    142 			strlen(cli_opts.username));
    143 
    144 	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
    145 			SSH_SERVICE_CONNECTION_LEN);
    146 
    147 	buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
    148 			AUTH_METHOD_PUBKEY_LEN);
    149 
    150 	buf_putbyte(ses.writepayload, realsign);
    151 
    152 	algoname = signkey_name_from_type(type, &algolen);
    153 
    154 	buf_putstring(ses.writepayload, algoname, algolen);
    155 	buf_put_pub_key(ses.writepayload, key, type);
    156 
    157 	if (realsign) {
    158 		TRACE(("realsign"))
    159 		/* We put the signature as well - this contains string(session id), then
    160 		 * the contents of the write payload to this point */
    161 		sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
    162 		buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
    163 		buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
    164 		buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
    165 		buf_free(sigbuf); /* Nothing confidential in the buffer */
    166 	}
    167 
    168 	encrypt_packet();
    169 	TRACE(("leave send_msg_userauth_pubkey"))
    170 }
    171 
    172 int cli_auth_pubkey() {
    173 
    174 	TRACE(("enter cli_auth_pubkey"))
    175 
    176 	if (cli_opts.privkeys != NULL) {
    177 		/* Send a trial request */
    178 		send_msg_userauth_pubkey(cli_opts.privkeys->key,
    179 				cli_opts.privkeys->type, 0);
    180 		cli_ses.lastprivkey = cli_opts.privkeys;
    181 		TRACE(("leave cli_auth_pubkey-success"))
    182 		return 1;
    183 	} else {
    184 		TRACE(("leave cli_auth_pubkey-failure"))
    185 		return 0;
    186 	}
    187 }
    188 #endif /* Pubkey auth */
    189