1*bc5531deSDag-Erling Smørgrav /* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */ 2d95e11bfSDag-Erling Smørgrav 3d95e11bfSDag-Erling Smørgrav /* 4d4af9e69SDag-Erling Smørgrav * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. 5d95e11bfSDag-Erling Smørgrav * 6d95e11bfSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 7d95e11bfSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 8d95e11bfSDag-Erling Smørgrav * are met: 9d95e11bfSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 10d95e11bfSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 11d95e11bfSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 12d95e11bfSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 13d95e11bfSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 14d95e11bfSDag-Erling Smørgrav * 15d95e11bfSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 16d95e11bfSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17d95e11bfSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18d95e11bfSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19d95e11bfSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20d95e11bfSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21d95e11bfSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22d95e11bfSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23d95e11bfSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24d95e11bfSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25d95e11bfSDag-Erling Smørgrav */ 26d95e11bfSDag-Erling Smørgrav 27d95e11bfSDag-Erling Smørgrav #include "includes.h" 28d95e11bfSDag-Erling Smørgrav 29d95e11bfSDag-Erling Smørgrav #ifdef GSSAPI 30d95e11bfSDag-Erling Smørgrav 31761efaa7SDag-Erling Smørgrav #include <sys/types.h> 32761efaa7SDag-Erling Smørgrav #include <sys/param.h> 33761efaa7SDag-Erling Smørgrav 34*bc5531deSDag-Erling Smørgrav #include <limits.h> 35761efaa7SDag-Erling Smørgrav #include <stdarg.h> 36761efaa7SDag-Erling Smørgrav #include <string.h> 37761efaa7SDag-Erling Smørgrav #include <unistd.h> 38761efaa7SDag-Erling Smørgrav 39d95e11bfSDag-Erling Smørgrav #include "xmalloc.h" 40761efaa7SDag-Erling Smørgrav #include "buffer.h" 41d95e11bfSDag-Erling Smørgrav #include "log.h" 42efcad6b7SDag-Erling Smørgrav #include "ssh2.h" 43d95e11bfSDag-Erling Smørgrav 44d95e11bfSDag-Erling Smørgrav #include "ssh-gss.h" 45d95e11bfSDag-Erling Smørgrav 46efcad6b7SDag-Erling Smørgrav extern u_char *session_id2; 47efcad6b7SDag-Erling Smørgrav extern u_int session_id2_len; 48d95e11bfSDag-Erling Smørgrav 49d95e11bfSDag-Erling Smørgrav /* Check that the OID in a data stream matches that in the context */ 50d95e11bfSDag-Erling Smørgrav int 51d95e11bfSDag-Erling Smørgrav ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 52d95e11bfSDag-Erling Smørgrav { 53d95e11bfSDag-Erling Smørgrav return (ctx != NULL && ctx->oid != GSS_C_NO_OID && 54d95e11bfSDag-Erling Smørgrav ctx->oid->length == len && 55d95e11bfSDag-Erling Smørgrav memcmp(ctx->oid->elements, data, len) == 0); 56d95e11bfSDag-Erling Smørgrav } 57d95e11bfSDag-Erling Smørgrav 58d95e11bfSDag-Erling Smørgrav /* Set the contexts OID from a data stream */ 59d95e11bfSDag-Erling Smørgrav void 60d95e11bfSDag-Erling Smørgrav ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) 61d95e11bfSDag-Erling Smørgrav { 62d95e11bfSDag-Erling Smørgrav if (ctx->oid != GSS_C_NO_OID) { 63e4a9863fSDag-Erling Smørgrav free(ctx->oid->elements); 64e4a9863fSDag-Erling Smørgrav free(ctx->oid); 65d95e11bfSDag-Erling Smørgrav } 660a37d4a3SXin LI ctx->oid = xcalloc(1, sizeof(gss_OID_desc)); 67d95e11bfSDag-Erling Smørgrav ctx->oid->length = len; 68d95e11bfSDag-Erling Smørgrav ctx->oid->elements = xmalloc(len); 69d95e11bfSDag-Erling Smørgrav memcpy(ctx->oid->elements, data, len); 70d95e11bfSDag-Erling Smørgrav } 71d95e11bfSDag-Erling Smørgrav 72d95e11bfSDag-Erling Smørgrav /* Set the contexts OID */ 73d95e11bfSDag-Erling Smørgrav void 74d95e11bfSDag-Erling Smørgrav ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) 75d95e11bfSDag-Erling Smørgrav { 76d95e11bfSDag-Erling Smørgrav ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length); 77d95e11bfSDag-Erling Smørgrav } 78d95e11bfSDag-Erling Smørgrav 79d95e11bfSDag-Erling Smørgrav /* All this effort to report an error ... */ 80d95e11bfSDag-Erling Smørgrav void 81d95e11bfSDag-Erling Smørgrav ssh_gssapi_error(Gssctxt *ctxt) 82d95e11bfSDag-Erling Smørgrav { 83761efaa7SDag-Erling Smørgrav char *s; 84761efaa7SDag-Erling Smørgrav 85761efaa7SDag-Erling Smørgrav s = ssh_gssapi_last_error(ctxt, NULL, NULL); 86761efaa7SDag-Erling Smørgrav debug("%s", s); 87e4a9863fSDag-Erling Smørgrav free(s); 88d95e11bfSDag-Erling Smørgrav } 89d95e11bfSDag-Erling Smørgrav 90d95e11bfSDag-Erling Smørgrav char * 91043840dfSDag-Erling Smørgrav ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status, 92043840dfSDag-Erling Smørgrav OM_uint32 *minor_status) 93d95e11bfSDag-Erling Smørgrav { 94d95e11bfSDag-Erling Smørgrav OM_uint32 lmin; 95d95e11bfSDag-Erling Smørgrav gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; 96d95e11bfSDag-Erling Smørgrav OM_uint32 ctx; 97d95e11bfSDag-Erling Smørgrav Buffer b; 98d95e11bfSDag-Erling Smørgrav char *ret; 99d95e11bfSDag-Erling Smørgrav 100d95e11bfSDag-Erling Smørgrav buffer_init(&b); 101d95e11bfSDag-Erling Smørgrav 102d95e11bfSDag-Erling Smørgrav if (major_status != NULL) 103d95e11bfSDag-Erling Smørgrav *major_status = ctxt->major; 104d95e11bfSDag-Erling Smørgrav if (minor_status != NULL) 105d95e11bfSDag-Erling Smørgrav *minor_status = ctxt->minor; 106d95e11bfSDag-Erling Smørgrav 107d95e11bfSDag-Erling Smørgrav ctx = 0; 108d95e11bfSDag-Erling Smørgrav /* The GSSAPI error */ 109d95e11bfSDag-Erling Smørgrav do { 110d95e11bfSDag-Erling Smørgrav gss_display_status(&lmin, ctxt->major, 111d4af9e69SDag-Erling Smørgrav GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg); 112d95e11bfSDag-Erling Smørgrav 113d95e11bfSDag-Erling Smørgrav buffer_append(&b, msg.value, msg.length); 114d95e11bfSDag-Erling Smørgrav buffer_put_char(&b, '\n'); 115d95e11bfSDag-Erling Smørgrav 116d95e11bfSDag-Erling Smørgrav gss_release_buffer(&lmin, &msg); 117d95e11bfSDag-Erling Smørgrav } while (ctx != 0); 118d95e11bfSDag-Erling Smørgrav 119d95e11bfSDag-Erling Smørgrav /* The mechanism specific error */ 120d95e11bfSDag-Erling Smørgrav do { 121d95e11bfSDag-Erling Smørgrav gss_display_status(&lmin, ctxt->minor, 122d4af9e69SDag-Erling Smørgrav GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg); 123d95e11bfSDag-Erling Smørgrav 124d95e11bfSDag-Erling Smørgrav buffer_append(&b, msg.value, msg.length); 125d95e11bfSDag-Erling Smørgrav buffer_put_char(&b, '\n'); 126d95e11bfSDag-Erling Smørgrav 127d95e11bfSDag-Erling Smørgrav gss_release_buffer(&lmin, &msg); 128d95e11bfSDag-Erling Smørgrav } while (ctx != 0); 129d95e11bfSDag-Erling Smørgrav 130d95e11bfSDag-Erling Smørgrav buffer_put_char(&b, '\0'); 131d95e11bfSDag-Erling Smørgrav ret = xmalloc(buffer_len(&b)); 132d95e11bfSDag-Erling Smørgrav buffer_get(&b, ret, buffer_len(&b)); 133d95e11bfSDag-Erling Smørgrav buffer_free(&b); 134d95e11bfSDag-Erling Smørgrav return (ret); 135d95e11bfSDag-Erling Smørgrav } 136d95e11bfSDag-Erling Smørgrav 137d95e11bfSDag-Erling Smørgrav /* 138d95e11bfSDag-Erling Smørgrav * Initialise our GSSAPI context. We use this opaque structure to contain all 139d95e11bfSDag-Erling Smørgrav * of the data which both the client and server need to persist across 140d95e11bfSDag-Erling Smørgrav * {accept,init}_sec_context calls, so that when we do it from the userauth 141d95e11bfSDag-Erling Smørgrav * stuff life is a little easier 142d95e11bfSDag-Erling Smørgrav */ 143d95e11bfSDag-Erling Smørgrav void 144d95e11bfSDag-Erling Smørgrav ssh_gssapi_build_ctx(Gssctxt **ctx) 145d95e11bfSDag-Erling Smørgrav { 146761efaa7SDag-Erling Smørgrav *ctx = xcalloc(1, sizeof (Gssctxt)); 147d95e11bfSDag-Erling Smørgrav (*ctx)->context = GSS_C_NO_CONTEXT; 148d95e11bfSDag-Erling Smørgrav (*ctx)->name = GSS_C_NO_NAME; 149d95e11bfSDag-Erling Smørgrav (*ctx)->oid = GSS_C_NO_OID; 150d95e11bfSDag-Erling Smørgrav (*ctx)->creds = GSS_C_NO_CREDENTIAL; 151d95e11bfSDag-Erling Smørgrav (*ctx)->client = GSS_C_NO_NAME; 152d95e11bfSDag-Erling Smørgrav (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; 153d95e11bfSDag-Erling Smørgrav } 154d95e11bfSDag-Erling Smørgrav 155d95e11bfSDag-Erling Smørgrav /* Delete our context, providing it has been built correctly */ 156d95e11bfSDag-Erling Smørgrav void 157d95e11bfSDag-Erling Smørgrav ssh_gssapi_delete_ctx(Gssctxt **ctx) 158d95e11bfSDag-Erling Smørgrav { 159d95e11bfSDag-Erling Smørgrav OM_uint32 ms; 160d95e11bfSDag-Erling Smørgrav 161d95e11bfSDag-Erling Smørgrav if ((*ctx) == NULL) 162d95e11bfSDag-Erling Smørgrav return; 163d95e11bfSDag-Erling Smørgrav if ((*ctx)->context != GSS_C_NO_CONTEXT) 164d95e11bfSDag-Erling Smørgrav gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER); 165d95e11bfSDag-Erling Smørgrav if ((*ctx)->name != GSS_C_NO_NAME) 166d95e11bfSDag-Erling Smørgrav gss_release_name(&ms, &(*ctx)->name); 167d95e11bfSDag-Erling Smørgrav if ((*ctx)->oid != GSS_C_NO_OID) { 168e4a9863fSDag-Erling Smørgrav free((*ctx)->oid->elements); 169e4a9863fSDag-Erling Smørgrav free((*ctx)->oid); 170d95e11bfSDag-Erling Smørgrav (*ctx)->oid = GSS_C_NO_OID; 171d95e11bfSDag-Erling Smørgrav } 172d95e11bfSDag-Erling Smørgrav if ((*ctx)->creds != GSS_C_NO_CREDENTIAL) 173d95e11bfSDag-Erling Smørgrav gss_release_cred(&ms, &(*ctx)->creds); 174d95e11bfSDag-Erling Smørgrav if ((*ctx)->client != GSS_C_NO_NAME) 175d95e11bfSDag-Erling Smørgrav gss_release_name(&ms, &(*ctx)->client); 176d95e11bfSDag-Erling Smørgrav if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) 177d95e11bfSDag-Erling Smørgrav gss_release_cred(&ms, &(*ctx)->client_creds); 178d95e11bfSDag-Erling Smørgrav 179e4a9863fSDag-Erling Smørgrav free(*ctx); 180d95e11bfSDag-Erling Smørgrav *ctx = NULL; 181d95e11bfSDag-Erling Smørgrav } 182d95e11bfSDag-Erling Smørgrav 183d95e11bfSDag-Erling Smørgrav /* 184d95e11bfSDag-Erling Smørgrav * Wrapper to init_sec_context 185d95e11bfSDag-Erling Smørgrav * Requires that the context contains: 186d95e11bfSDag-Erling Smørgrav * oid 187d95e11bfSDag-Erling Smørgrav * server name (from ssh_gssapi_import_name) 188d95e11bfSDag-Erling Smørgrav */ 189d95e11bfSDag-Erling Smørgrav OM_uint32 190d95e11bfSDag-Erling Smørgrav ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, 191d95e11bfSDag-Erling Smørgrav gss_buffer_desc* send_tok, OM_uint32 *flags) 192d95e11bfSDag-Erling Smørgrav { 193d95e11bfSDag-Erling Smørgrav int deleg_flag = 0; 194d95e11bfSDag-Erling Smørgrav 195d95e11bfSDag-Erling Smørgrav if (deleg_creds) { 196d95e11bfSDag-Erling Smørgrav deleg_flag = GSS_C_DELEG_FLAG; 197d95e11bfSDag-Erling Smørgrav debug("Delegating credentials"); 198d95e11bfSDag-Erling Smørgrav } 199d95e11bfSDag-Erling Smørgrav 200d95e11bfSDag-Erling Smørgrav ctx->major = gss_init_sec_context(&ctx->minor, 201d95e11bfSDag-Erling Smørgrav GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, 202d95e11bfSDag-Erling Smørgrav GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 203d95e11bfSDag-Erling Smørgrav 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 204d95e11bfSDag-Erling Smørgrav 205d95e11bfSDag-Erling Smørgrav if (GSS_ERROR(ctx->major)) 206d95e11bfSDag-Erling Smørgrav ssh_gssapi_error(ctx); 207d95e11bfSDag-Erling Smørgrav 208d95e11bfSDag-Erling Smørgrav return (ctx->major); 209d95e11bfSDag-Erling Smørgrav } 210d95e11bfSDag-Erling Smørgrav 211d95e11bfSDag-Erling Smørgrav /* Create a service name for the given host */ 212d95e11bfSDag-Erling Smørgrav OM_uint32 213d95e11bfSDag-Erling Smørgrav ssh_gssapi_import_name(Gssctxt *ctx, const char *host) 214d95e11bfSDag-Erling Smørgrav { 215d95e11bfSDag-Erling Smørgrav gss_buffer_desc gssbuf; 216761efaa7SDag-Erling Smørgrav char *val; 217d95e11bfSDag-Erling Smørgrav 218761efaa7SDag-Erling Smørgrav xasprintf(&val, "host@%s", host); 219761efaa7SDag-Erling Smørgrav gssbuf.value = val; 220761efaa7SDag-Erling Smørgrav gssbuf.length = strlen(gssbuf.value); 221d95e11bfSDag-Erling Smørgrav 222d95e11bfSDag-Erling Smørgrav if ((ctx->major = gss_import_name(&ctx->minor, 223d95e11bfSDag-Erling Smørgrav &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) 224d95e11bfSDag-Erling Smørgrav ssh_gssapi_error(ctx); 225d95e11bfSDag-Erling Smørgrav 226e4a9863fSDag-Erling Smørgrav free(gssbuf.value); 227d95e11bfSDag-Erling Smørgrav return (ctx->major); 228d95e11bfSDag-Erling Smørgrav } 229d95e11bfSDag-Erling Smørgrav 230d95e11bfSDag-Erling Smørgrav OM_uint32 231efcad6b7SDag-Erling Smørgrav ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 232efcad6b7SDag-Erling Smørgrav { 233efcad6b7SDag-Erling Smørgrav if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 234efcad6b7SDag-Erling Smørgrav GSS_C_QOP_DEFAULT, buffer, hash))) 235efcad6b7SDag-Erling Smørgrav ssh_gssapi_error(ctx); 236efcad6b7SDag-Erling Smørgrav 237efcad6b7SDag-Erling Smørgrav return (ctx->major); 238efcad6b7SDag-Erling Smørgrav } 239efcad6b7SDag-Erling Smørgrav 240efcad6b7SDag-Erling Smørgrav void 241efcad6b7SDag-Erling Smørgrav ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 242efcad6b7SDag-Erling Smørgrav const char *context) 243efcad6b7SDag-Erling Smørgrav { 244efcad6b7SDag-Erling Smørgrav buffer_init(b); 245efcad6b7SDag-Erling Smørgrav buffer_put_string(b, session_id2, session_id2_len); 246efcad6b7SDag-Erling Smørgrav buffer_put_char(b, SSH2_MSG_USERAUTH_REQUEST); 247efcad6b7SDag-Erling Smørgrav buffer_put_cstring(b, user); 248efcad6b7SDag-Erling Smørgrav buffer_put_cstring(b, service); 249efcad6b7SDag-Erling Smørgrav buffer_put_cstring(b, context); 250efcad6b7SDag-Erling Smørgrav } 251efcad6b7SDag-Erling Smørgrav 252761efaa7SDag-Erling Smørgrav int 253761efaa7SDag-Erling Smørgrav ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 254761efaa7SDag-Erling Smørgrav { 255761efaa7SDag-Erling Smørgrav gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 256761efaa7SDag-Erling Smørgrav OM_uint32 major, minor; 257761efaa7SDag-Erling Smørgrav gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 258761efaa7SDag-Erling Smørgrav 259761efaa7SDag-Erling Smørgrav /* RFC 4462 says we MUST NOT do SPNEGO */ 260761efaa7SDag-Erling Smørgrav if (oid->length == spnego_oid.length && 261761efaa7SDag-Erling Smørgrav (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0)) 262761efaa7SDag-Erling Smørgrav return 0; /* false */ 263761efaa7SDag-Erling Smørgrav 264761efaa7SDag-Erling Smørgrav ssh_gssapi_build_ctx(ctx); 265761efaa7SDag-Erling Smørgrav ssh_gssapi_set_oid(*ctx, oid); 266761efaa7SDag-Erling Smørgrav major = ssh_gssapi_import_name(*ctx, host); 267761efaa7SDag-Erling Smørgrav if (!GSS_ERROR(major)) { 268761efaa7SDag-Erling Smørgrav major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 269761efaa7SDag-Erling Smørgrav NULL); 270761efaa7SDag-Erling Smørgrav gss_release_buffer(&minor, &token); 271761efaa7SDag-Erling Smørgrav if ((*ctx)->context != GSS_C_NO_CONTEXT) 272761efaa7SDag-Erling Smørgrav gss_delete_sec_context(&minor, &(*ctx)->context, 273761efaa7SDag-Erling Smørgrav GSS_C_NO_BUFFER); 274761efaa7SDag-Erling Smørgrav } 275761efaa7SDag-Erling Smørgrav 276761efaa7SDag-Erling Smørgrav if (GSS_ERROR(major)) 277761efaa7SDag-Erling Smørgrav ssh_gssapi_delete_ctx(ctx); 278761efaa7SDag-Erling Smørgrav 279761efaa7SDag-Erling Smørgrav return (!GSS_ERROR(major)); 280761efaa7SDag-Erling Smørgrav } 281761efaa7SDag-Erling Smørgrav 282d95e11bfSDag-Erling Smørgrav #endif /* GSSAPI */ 283