1/* 2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include "includes.h" 26 27#ifdef GSSAPI 28 29#include "includes.h" 30 31#ifdef __APPLE_CRYPTO__ 32#include "ossl-crypto.h" 33#include "ossl-bn.h" 34#else 35#include <openssl/crypto.h> 36#include <openssl/bn.h> 37#endif 38 39#include <string.h> 40 41#include "xmalloc.h" 42#include "buffer.h" 43#include "ssh2.h" 44#include "key.h" 45#include "cipher.h" 46#include "kex.h" 47#include "log.h" 48#include "packet.h" 49#include "dh.h" 50 51#include "ssh-gss.h" 52 53void 54kexgss_client(Kex *kex) { 55 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 56 gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; 57 Gssctxt *ctxt; 58 OM_uint32 maj_status, min_status, ret_flags; 59 u_int klen, kout, slen = 0, hashlen, strlen; 60 DH *dh; 61 BIGNUM *dh_server_pub = NULL; 62 BIGNUM *shared_secret = NULL; 63 BIGNUM *p = NULL; 64 BIGNUM *g = NULL; 65 u_char *kbuf, *hash; 66 u_char *serverhostkey = NULL; 67 u_char *empty = ""; 68 char *msg; 69 char *lang; 70 int type = 0; 71 int first = 1; 72 int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; 73 74 /* Initialise our GSSAPI world */ 75 ssh_gssapi_build_ctx(&ctxt); 76 if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) 77 == GSS_C_NO_OID) 78 fatal("Couldn't identify host exchange"); 79 80 if (ssh_gssapi_import_name(ctxt, kex->gss_host)) 81 fatal("Couldn't import hostname"); 82 83 if (kex->gss_client && 84 ssh_gssapi_client_identity(ctxt, kex->gss_client)) 85 fatal("Couldn't acquire client credentials"); 86 87 switch (kex->kex_type) { 88 case KEX_GSS_GRP1_SHA1: 89 dh = dh_new_group1(); 90 break; 91 case KEX_GSS_GRP14_SHA1: 92 dh = dh_new_group14(); 93 break; 94 case KEX_GSS_GEX_SHA1: 95 debug("Doing group exchange\n"); 96 nbits = dh_estimate(kex->we_need * 8); 97 packet_start(SSH2_MSG_KEXGSS_GROUPREQ); 98 packet_put_int(min); 99 packet_put_int(nbits); 100 packet_put_int(max); 101 102 packet_send(); 103 104 packet_read_expect(SSH2_MSG_KEXGSS_GROUP); 105 106 if ((p = BN_new()) == NULL) 107 fatal("BN_new() failed"); 108 packet_get_bignum2(p); 109 if ((g = BN_new()) == NULL) 110 fatal("BN_new() failed"); 111 packet_get_bignum2(g); 112 packet_check_eom(); 113 114 if (BN_num_bits(p) < min || BN_num_bits(p) > max) 115 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", 116 min, BN_num_bits(p), max); 117 118 dh = dh_new_group(g, p); 119 break; 120 default: 121 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); 122 } 123 124 /* Step 1 - e is dh->pub_key */ 125 dh_gen_key(dh, kex->we_need * 8); 126 127 /* This is f, we initialise it now to make life easier */ 128 dh_server_pub = BN_new(); 129 if (dh_server_pub == NULL) 130 fatal("dh_server_pub == NULL"); 131 132 token_ptr = GSS_C_NO_BUFFER; 133 134 do { 135 debug("Calling gss_init_sec_context"); 136 137 maj_status = ssh_gssapi_init_ctx(ctxt, 138 kex->gss_deleg_creds, token_ptr, &send_tok, 139 &ret_flags); 140 141 if (GSS_ERROR(maj_status)) { 142 if (send_tok.length != 0) { 143 packet_start(SSH2_MSG_KEXGSS_CONTINUE); 144 packet_put_string(send_tok.value, 145 send_tok.length); 146 } 147 fatal("gss_init_context failed"); 148 } 149 150 /* If we've got an old receive buffer get rid of it */ 151 if (token_ptr != GSS_C_NO_BUFFER) 152 xfree(recv_tok.value); 153 154 if (maj_status == GSS_S_COMPLETE) { 155 /* If mutual state flag is not true, kex fails */ 156 if (!(ret_flags & GSS_C_MUTUAL_FLAG)) 157 fatal("Mutual authentication failed"); 158 159 /* If integ avail flag is not true kex fails */ 160 if (!(ret_flags & GSS_C_INTEG_FLAG)) 161 fatal("Integrity check failed"); 162 } 163 164 /* 165 * If we have data to send, then the last message that we 166 * received cannot have been a 'complete'. 167 */ 168 if (send_tok.length != 0) { 169 if (first) { 170 packet_start(SSH2_MSG_KEXGSS_INIT); 171 packet_put_string(send_tok.value, 172 send_tok.length); 173 packet_put_bignum2(dh->pub_key); 174 first = 0; 175 } else { 176 packet_start(SSH2_MSG_KEXGSS_CONTINUE); 177 packet_put_string(send_tok.value, 178 send_tok.length); 179 } 180 packet_send(); 181 gss_release_buffer(&min_status, &send_tok); 182 183 /* If we've sent them data, they should reply */ 184 do { 185 type = packet_read(); 186 if (type == SSH2_MSG_KEXGSS_HOSTKEY) { 187 debug("Received KEXGSS_HOSTKEY"); 188 if (serverhostkey) 189 fatal("Server host key received more than once"); 190 serverhostkey = 191 packet_get_string(&slen); 192 } 193 } while (type == SSH2_MSG_KEXGSS_HOSTKEY); 194 195 switch (type) { 196 case SSH2_MSG_KEXGSS_CONTINUE: 197 debug("Received GSSAPI_CONTINUE"); 198 if (maj_status == GSS_S_COMPLETE) 199 fatal("GSSAPI Continue received from server when complete"); 200 recv_tok.value = packet_get_string(&strlen); 201 recv_tok.length = strlen; 202 break; 203 case SSH2_MSG_KEXGSS_COMPLETE: 204 debug("Received GSSAPI_COMPLETE"); 205 packet_get_bignum2(dh_server_pub); 206 msg_tok.value = packet_get_string(&strlen); 207 msg_tok.length = strlen; 208 209 /* Is there a token included? */ 210 if (packet_get_char()) { 211 recv_tok.value= 212 packet_get_string(&strlen); 213 recv_tok.length = strlen; 214 /* If we're already complete - protocol error */ 215 if (maj_status == GSS_S_COMPLETE) 216 packet_disconnect("Protocol error: received token when complete"); 217 } else { 218 /* No token included */ 219 if (maj_status != GSS_S_COMPLETE) 220 packet_disconnect("Protocol error: did not receive final token"); 221 } 222 break; 223 case SSH2_MSG_KEXGSS_ERROR: 224 debug("Received Error"); 225 maj_status = packet_get_int(); 226 min_status = packet_get_int(); 227 msg = packet_get_string(NULL); 228 lang = packet_get_string(NULL); 229 fatal("GSSAPI Error: \n%.400s",msg); 230 default: 231 packet_disconnect("Protocol error: didn't expect packet type %d", 232 type); 233 } 234 token_ptr = &recv_tok; 235 } else { 236 /* No data, and not complete */ 237 if (maj_status != GSS_S_COMPLETE) 238 fatal("Not complete, and no token output"); 239 } 240 } while (maj_status & GSS_S_CONTINUE_NEEDED); 241 242 /* 243 * We _must_ have received a COMPLETE message in reply from the 244 * server, which will have set dh_server_pub and msg_tok 245 */ 246 247 if (type != SSH2_MSG_KEXGSS_COMPLETE) 248 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); 249 250 /* Check f in range [1, p-1] */ 251 if (!dh_pub_is_valid(dh, dh_server_pub)) 252 packet_disconnect("bad server public DH value"); 253 254 /* compute K=f^x mod p */ 255 klen = DH_size(dh); 256 kbuf = xmalloc(klen); 257 kout = DH_compute_key(kbuf, dh_server_pub, dh); 258 if (kout < 0) 259 fatal("DH_compute_key: failed"); 260 261 shared_secret = BN_new(); 262 if (shared_secret == NULL) 263 fatal("kexgss_client: BN_new failed"); 264 265 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 266 fatal("kexdh_client: BN_bin2bn failed"); 267 268 memset(kbuf, 0, klen); 269 xfree(kbuf); 270 271 switch (kex->kex_type) { 272 case KEX_GSS_GRP1_SHA1: 273 case KEX_GSS_GRP14_SHA1: 274 kex_dh_hash( kex->client_version_string, 275 kex->server_version_string, 276 buffer_ptr(&kex->my), buffer_len(&kex->my), 277 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 278 (serverhostkey ? serverhostkey : empty), slen, 279 dh->pub_key, /* e */ 280 dh_server_pub, /* f */ 281 shared_secret, /* K */ 282 &hash, &hashlen 283 ); 284 break; 285 case KEX_GSS_GEX_SHA1: 286 kexgex_hash( 287 kex->evp_md, 288 kex->client_version_string, 289 kex->server_version_string, 290 buffer_ptr(&kex->my), buffer_len(&kex->my), 291 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 292 (serverhostkey ? serverhostkey : empty), slen, 293 min, nbits, max, 294 dh->p, dh->g, 295 dh->pub_key, 296 dh_server_pub, 297 shared_secret, 298 &hash, &hashlen 299 ); 300 break; 301 default: 302 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); 303 } 304 305 gssbuf.value = hash; 306 gssbuf.length = hashlen; 307 308 /* Verify that the hash matches the MIC we just got. */ 309 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) 310 packet_disconnect("Hash's MIC didn't verify"); 311 312 xfree(msg_tok.value); 313 314 DH_free(dh); 315 if (serverhostkey) 316 xfree(serverhostkey); 317 BN_clear_free(dh_server_pub); 318 319 /* save session id */ 320 if (kex->session_id == NULL) { 321 kex->session_id_len = hashlen; 322 kex->session_id = xmalloc(kex->session_id_len); 323 memcpy(kex->session_id, hash, kex->session_id_len); 324 } 325 326 if (kex->gss_deleg_creds) 327 ssh_gssapi_credentials_updated(ctxt); 328 329 if (gss_kex_context == NULL) 330 gss_kex_context = ctxt; 331 else 332 ssh_gssapi_delete_ctx(&ctxt); 333 334 kex_derive_keys(kex, hash, hashlen, shared_secret); 335 BN_clear_free(shared_secret); 336 kex_finish(kex); 337} 338 339#endif /* GSSAPI */ 340