diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/ssh/libssh/common/kexgsss.c | |
download | illumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/ssh/libssh/common/kexgsss.c')
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/kexgsss.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/usr/src/cmd/ssh/libssh/common/kexgsss.c b/usr/src/cmd/ssh/libssh/common/kexgsss.c new file mode 100644 index 0000000000..d777874feb --- /dev/null +++ b/usr/src/cmd/ssh/libssh/common/kexgsss.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "includes.h" + +#ifdef GSSAPI + +#include <openssl/crypto.h> +#include <openssl/bn.h> + +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "compat.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "ssh-gss.h" +#include "monitor_wrap.h" + +Gssctxt *xxx_gssctxt; + +static void kex_gss_send_error(Gssctxt *ctxt); + +void +kexgss_server(Kex *kex) +{ + OM_uint32 maj_status, min_status; + gss_buffer_desc gssbuf, send_tok, recv_tok, msg_tok; + Gssctxt *ctxt = NULL; + unsigned int klen, kout; + unsigned int sbloblen = 0; + unsigned char *kbuf, *hash; + unsigned char *server_host_key_blob = NULL; + DH *dh; + Key *server_host_key = NULL; + BIGNUM *shared_secret = NULL; + BIGNUM *dh_client_pub = NULL; + int type =0; + u_int slen; + gss_OID oid; + + /* + * Load host key to advertise in a SSH_MSG_KEXGSS_HOSTKEY packet + * -- unlike KEX_DH/KEX_GEX no host key, no problem since it's + * the GSS-API that provides for server host authentication. + */ + if (kex->load_host_key != NULL && + !(datafellows & SSH_BUG_GSSKEX_HOSTKEY)) + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key != NULL) + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + + /* Initialise GSSAPI */ + + ssh_gssapi_oid_of_kexname(kex->name, &oid); + if (oid == GSS_C_NULL_OID) { + fatal("Couldn't match the negotiated GSS key exchange"); + } + + ssh_gssapi_build_ctx(&ctxt, 0, oid); + + xxx_gssctxt = ctxt; + + do { + debug("Wait SSH2_MSG_GSSAPI_INIT"); + type = packet_read(); + switch(type) { + case SSH2_MSG_KEXGSS_INIT: + if (dh_client_pub!=NULL) + fatal("Received KEXGSS_INIT after initialising"); + recv_tok.value=packet_get_string(&slen); + recv_tok.length=slen; /* int vs. size_t */ + + dh_client_pub = BN_new(); + + if (dh_client_pub == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub); + + /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ + if (sbloblen) { + packet_start(SSH2_MSG_KEXGSS_HOSTKEY); + packet_put_string(server_host_key_blob, sbloblen); + packet_send(); + packet_write_wait(); + } + break; + case SSH2_MSG_KEXGSS_CONTINUE: + recv_tok.value=packet_get_string(&slen); + recv_tok.length=slen; /* int vs. size_t */ + break; + default: + packet_disconnect("Protocol error: didn't expect packet type %d", + type); + } + + maj_status=PRIVSEP(ssh_gssapi_accept_ctx(ctxt,&recv_tok, + &send_tok)); + + xfree(recv_tok.value); /* We allocated this, not gss */ + + if (dh_client_pub == NULL) + fatal("No client public key"); + + if (maj_status == GSS_S_CONTINUE_NEEDED) { + debug("Sending GSSAPI_CONTINUE"); + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value,send_tok.length); + packet_send(); + packet_write_wait(); + (void) gss_release_buffer(&min_status, &send_tok); + } + } while (maj_status == GSS_S_CONTINUE_NEEDED); + + if (GSS_ERROR(maj_status)) { + kex_gss_send_error(ctxt); + if (send_tok.length>0) { + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value,send_tok.length); + packet_send(); + packet_write_wait(); + (void) gss_release_buffer(&min_status, &send_tok); + } + fatal("accept_ctx died"); + } + + debug("gss_complete"); + if (!(ctxt->flags & GSS_C_MUTUAL_FLAG)) + fatal("Mutual authentication flag wasn't set"); + + if (!(ctxt->flags & GSS_C_INTEG_FLAG)) + fatal("Integrity flag wasn't set"); + + dh = dh_new_group1(); + dh_gen_key(dh, kex->we_need * 8); + + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); + + shared_secret = BN_new(); + BN_bin2bn(kbuf, kout, shared_secret); + (void) memset(kbuf, 0, klen); + xfree(kbuf); + + /* The GSSAPI hash is identical to the Diffie Helman one */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + server_host_key_blob, sbloblen, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_free(dh_client_pub); + + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + (void) memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* Should fix kex_dh_hash to output hash length */ + gssbuf.length = 20; /* yes, it's always 20 (SHA-1) */ + gssbuf.value = hash; /* and it's static constant storage */ + + if (GSS_ERROR(ssh_gssapi_get_mic(ctxt,&gssbuf,&msg_tok))) { + kex_gss_send_error(ctxt); + fatal("Couldn't get MIC"); + } + + packet_start(SSH2_MSG_KEXGSS_COMPLETE); + packet_put_bignum2(dh->pub_key); + packet_put_string((char *)msg_tok.value,msg_tok.length); + (void) gss_release_buffer(&min_status, &msg_tok); + + if (send_tok.length != 0) { + packet_put_char(1); /* true */ + packet_put_string((char *)send_tok.value,send_tok.length); + (void) gss_release_buffer(&min_status, &send_tok); + } else { + packet_put_char(0); /* false */ + } + packet_send(); + packet_write_wait(); + + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} + +static void +kex_gss_send_error(Gssctxt *ctxt) { + char *errstr; + OM_uint32 maj,min; + + errstr = ssh_gssapi_last_error(ctxt,&maj,&min); + if (errstr) { + packet_start(SSH2_MSG_KEXGSS_ERROR); + packet_put_int(maj); + packet_put_int(min); + packet_put_cstring(errstr); + packet_put_cstring(""); + packet_send(); + packet_write_wait(); + /* XXX - We should probably log the error locally here */ + xfree(errstr); + } +} +#endif /* GSSAPI */ |