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 <string.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 "xmalloc.h" 40#include "buffer.h" 41#include "ssh2.h" 42#include "key.h" 43#include "cipher.h" 44#include "kex.h" 45#include "log.h" 46#include "packet.h" 47#include "dh.h" 48#include "ssh-gss.h" 49#include "monitor_wrap.h" 50#include "servconf.h" 51 52extern ServerOptions options; 53 54void 55kexgss_server(Kex *kex) 56{ 57 OM_uint32 maj_status, min_status; 58 59 /* 60 * Some GSSAPI implementations use the input value of ret_flags (an 61 * output variable) as a means of triggering mechanism specific 62 * features. Initializing it to zero avoids inadvertently 63 * activating this non-standard behaviour. 64 */ 65 66 OM_uint32 ret_flags = 0; 67 gss_buffer_desc gssbuf, recv_tok, msg_tok; 68 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 69 Gssctxt *ctxt = NULL; 70 u_int slen, klen, kout, hashlen; 71 u_char *kbuf, *hash; 72 DH *dh; 73 int min = -1, max = -1, nbits = -1; 74 BIGNUM *shared_secret = NULL; 75 BIGNUM *dh_client_pub = NULL; 76 int type = 0; 77 gss_OID oid; 78 char *mechs; 79 80 /* Initialise GSSAPI */ 81 82 /* If we're rekeying, privsep means that some of the private structures 83 * in the GSSAPI code are no longer available. This kludges them back 84 * into life 85 */ 86 if (!ssh_gssapi_oid_table_ok()) 87 if ((mechs = ssh_gssapi_server_mechanisms())) 88 xfree(mechs); 89 90 debug2("%s: Identifying %s", __func__, kex->name); 91 oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); 92 if (oid == GSS_C_NO_OID) 93 fatal("Unknown gssapi mechanism"); 94 95 debug2("%s: Acquiring credentials", __func__); 96 97 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) 98 fatal("Unable to acquire credentials for the server"); 99 100 switch (kex->kex_type) { 101 case KEX_GSS_GRP1_SHA1: 102 dh = dh_new_group1(); 103 break; 104 case KEX_GSS_GRP14_SHA1: 105 dh = dh_new_group14(); 106 break; 107 case KEX_GSS_GEX_SHA1: 108 debug("Doing group exchange"); 109 packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); 110 min = packet_get_int(); 111 nbits = packet_get_int(); 112 max = packet_get_int(); 113 min = MAX(DH_GRP_MIN, min); 114 max = MIN(DH_GRP_MAX, max); 115 packet_check_eom(); 116 if (max < min || nbits < min || max < nbits) 117 fatal("GSS_GEX, bad parameters: %d !< %d !< %d", 118 min, nbits, max); 119 dh = PRIVSEP(choose_dh(min, nbits, max)); 120 if (dh == NULL) 121 packet_disconnect("Protocol error: no matching group found"); 122 123 packet_start(SSH2_MSG_KEXGSS_GROUP); 124 packet_put_bignum2(dh->p); 125 packet_put_bignum2(dh->g); 126 packet_send(); 127 128 packet_write_wait(); 129 break; 130 default: 131 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); 132 } 133 134 dh_gen_key(dh, kex->we_need * 8); 135 136 do { 137 debug("Wait SSH2_MSG_GSSAPI_INIT"); 138 type = packet_read(); 139 switch(type) { 140 case SSH2_MSG_KEXGSS_INIT: 141 if (dh_client_pub != NULL) 142 fatal("Received KEXGSS_INIT after initialising"); 143 recv_tok.value = packet_get_string(&slen); 144 recv_tok.length = slen; 145 146 if ((dh_client_pub = BN_new()) == NULL) 147 fatal("dh_client_pub == NULL"); 148 149 packet_get_bignum2(dh_client_pub); 150 151 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ 152 break; 153 case SSH2_MSG_KEXGSS_CONTINUE: 154 recv_tok.value = packet_get_string(&slen); 155 recv_tok.length = slen; 156 break; 157 default: 158 packet_disconnect( 159 "Protocol error: didn't expect packet type %d", 160 type); 161 } 162 163 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, 164 &send_tok, &ret_flags)); 165 166 xfree(recv_tok.value); 167 168 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) 169 fatal("Zero length token output when incomplete"); 170 171 if (dh_client_pub == NULL) 172 fatal("No client public key"); 173 174 if (maj_status & GSS_S_CONTINUE_NEEDED) { 175 debug("Sending GSSAPI_CONTINUE"); 176 packet_start(SSH2_MSG_KEXGSS_CONTINUE); 177 packet_put_string(send_tok.value, send_tok.length); 178 packet_send(); 179 gss_release_buffer(&min_status, &send_tok); 180 } 181 } while (maj_status & GSS_S_CONTINUE_NEEDED); 182 183 if (GSS_ERROR(maj_status)) { 184 if (send_tok.length > 0) { 185 packet_start(SSH2_MSG_KEXGSS_CONTINUE); 186 packet_put_string(send_tok.value, send_tok.length); 187 packet_send(); 188 } 189 fatal("accept_ctx died"); 190 } 191 192 if (!(ret_flags & GSS_C_MUTUAL_FLAG)) 193 fatal("Mutual Authentication flag wasn't set"); 194 195 if (!(ret_flags & GSS_C_INTEG_FLAG)) 196 fatal("Integrity flag wasn't set"); 197 198 if (!dh_pub_is_valid(dh, dh_client_pub)) 199 packet_disconnect("bad client public DH value"); 200 201 klen = DH_size(dh); 202 kbuf = xmalloc(klen); 203 kout = DH_compute_key(kbuf, dh_client_pub, dh); 204 if (kout < 0) 205 fatal("DH_compute_key: failed"); 206 207 shared_secret = BN_new(); 208 if (shared_secret == NULL) 209 fatal("kexgss_server: BN_new failed"); 210 211 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 212 fatal("kexgss_server: BN_bin2bn failed"); 213 214 memset(kbuf, 0, klen); 215 xfree(kbuf); 216 217 switch (kex->kex_type) { 218 case KEX_GSS_GRP1_SHA1: 219 case KEX_GSS_GRP14_SHA1: 220 kex_dh_hash( 221 kex->client_version_string, kex->server_version_string, 222 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 223 buffer_ptr(&kex->my), buffer_len(&kex->my), 224 NULL, 0, /* Change this if we start sending host keys */ 225 dh_client_pub, dh->pub_key, shared_secret, 226 &hash, &hashlen 227 ); 228 break; 229 case KEX_GSS_GEX_SHA1: 230 kexgex_hash( 231 kex->evp_md, 232 kex->client_version_string, kex->server_version_string, 233 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 234 buffer_ptr(&kex->my), buffer_len(&kex->my), 235 NULL, 0, 236 min, nbits, max, 237 dh->p, dh->g, 238 dh_client_pub, 239 dh->pub_key, 240 shared_secret, 241 &hash, &hashlen 242 ); 243 break; 244 default: 245 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); 246 } 247 248 BN_clear_free(dh_client_pub); 249 250 if (kex->session_id == NULL) { 251 kex->session_id_len = hashlen; 252 kex->session_id = xmalloc(kex->session_id_len); 253 memcpy(kex->session_id, hash, kex->session_id_len); 254 } 255 256 gssbuf.value = hash; 257 gssbuf.length = hashlen; 258 259 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) 260 fatal("Couldn't get MIC"); 261 262 packet_start(SSH2_MSG_KEXGSS_COMPLETE); 263 packet_put_bignum2(dh->pub_key); 264 packet_put_string(msg_tok.value,msg_tok.length); 265 266 if (send_tok.length != 0) { 267 packet_put_char(1); /* true */ 268 packet_put_string(send_tok.value, send_tok.length); 269 } else { 270 packet_put_char(0); /* false */ 271 } 272 packet_send(); 273 274 gss_release_buffer(&min_status, &send_tok); 275 gss_release_buffer(&min_status, &msg_tok); 276 277 if (gss_kex_context == NULL) 278 gss_kex_context = ctxt; 279 else 280 ssh_gssapi_delete_ctx(&ctxt); 281 282 DH_free(dh); 283 284 kex_derive_keys(kex, hash, hashlen, shared_secret); 285 BN_clear_free(shared_secret); 286 kex_finish(kex); 287 288 /* If this was a rekey, then save out any delegated credentials we 289 * just exchanged. */ 290 if (options.gss_store_rekey) 291 ssh_gssapi_rekey_creds(); 292} 293#endif /* GSSAPI */ 294