Annotation of src/usr.bin/ssh/gss-genr.c, Revision 1.27
1.27 ! djm 1: /* $OpenBSD: gss-genr.c,v 1.26 2018/07/10 09:13:30 djm Exp $ */
1.1 markus 2:
3: /*
1.19 dtucker 4: * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
1.1 markus 5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #ifdef GSSAPI
1.12 stevesk 28:
1.11 stevesk 29:
1.20 dtucker 30: #include <stdarg.h>
1.11 stevesk 31: #include <string.h>
1.23 deraadt 32: #include <limits.h>
1.1 markus 33:
34: #include "xmalloc.h"
1.25 markus 35: #include "ssherr.h"
36: #include "sshbuf.h"
1.1 markus 37: #include "log.h"
1.2 markus 38: #include "ssh2.h"
1.1 markus 39:
40: #include "ssh-gss.h"
41:
1.2 markus 42: extern u_char *session_id2;
43: extern u_int session_id2_len;
1.26 djm 44:
45: /* sshbuf_get for gss_buffer_desc */
46: int
47: ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
48: {
49: int r;
50: u_char *p;
51: size_t len;
52:
53: if ((r = sshbuf_get_string(b, &p, &len)) != 0)
54: return r;
55: g->value = p;
56: g->length = len;
57: return 0;
58: }
1.1 markus 59:
60: /* Check that the OID in a data stream matches that in the context */
61: int
62: ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
63: {
64: return (ctx != NULL && ctx->oid != GSS_C_NO_OID &&
65: ctx->oid->length == len &&
66: memcmp(ctx->oid->elements, data, len) == 0);
67: }
68:
69: /* Set the contexts OID from a data stream */
70: void
71: ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len)
72: {
73: if (ctx->oid != GSS_C_NO_OID) {
1.21 djm 74: free(ctx->oid->elements);
75: free(ctx->oid);
1.1 markus 76: }
1.22 djm 77: ctx->oid = xcalloc(1, sizeof(gss_OID_desc));
1.1 markus 78: ctx->oid->length = len;
79: ctx->oid->elements = xmalloc(len);
80: memcpy(ctx->oid->elements, data, len);
81: }
82:
83: /* Set the contexts OID */
84: void
85: ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
86: {
87: ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length);
88: }
89:
90: /* All this effort to report an error ... */
91: void
92: ssh_gssapi_error(Gssctxt *ctxt)
93: {
1.7 djm 94: char *s;
95:
96: s = ssh_gssapi_last_error(ctxt, NULL, NULL);
97: debug("%s", s);
1.21 djm 98: free(s);
1.1 markus 99: }
100:
101: char *
1.4 djm 102: ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status,
103: OM_uint32 *minor_status)
1.1 markus 104: {
105: OM_uint32 lmin;
106: gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
107: OM_uint32 ctx;
1.25 markus 108: struct sshbuf *b;
1.1 markus 109: char *ret;
1.25 markus 110: int r;
1.1 markus 111:
1.25 markus 112: if ((b = sshbuf_new()) == NULL)
1.27 ! djm 113: fatal_f("sshbuf_new failed");
1.1 markus 114:
115: if (major_status != NULL)
116: *major_status = ctxt->major;
117: if (minor_status != NULL)
118: *minor_status = ctxt->minor;
119:
120: ctx = 0;
121: /* The GSSAPI error */
122: do {
123: gss_display_status(&lmin, ctxt->major,
1.19 dtucker 124: GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg);
1.1 markus 125:
1.25 markus 126: if ((r = sshbuf_put(b, msg.value, msg.length)) != 0 ||
127: (r = sshbuf_put_u8(b, '\n')) != 0)
1.27 ! djm 128: fatal_fr(r, "assemble GSS_CODE");
1.1 markus 129:
130: gss_release_buffer(&lmin, &msg);
131: } while (ctx != 0);
132:
133: /* The mechanism specific error */
134: do {
135: gss_display_status(&lmin, ctxt->minor,
1.19 dtucker 136: GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg);
1.1 markus 137:
1.25 markus 138: if ((r = sshbuf_put(b, msg.value, msg.length)) != 0 ||
139: (r = sshbuf_put_u8(b, '\n')) != 0)
1.27 ! djm 140: fatal_fr(r, "assemble MECH_CODE");
1.1 markus 141:
142: gss_release_buffer(&lmin, &msg);
143: } while (ctx != 0);
144:
1.25 markus 145: if ((r = sshbuf_put_u8(b, '\n')) != 0)
1.27 ! djm 146: fatal_fr(r, "assemble newline");
1.25 markus 147: ret = xstrdup((const char *)sshbuf_ptr(b));
148: sshbuf_free(b);
1.1 markus 149: return (ret);
150: }
151:
152: /*
153: * Initialise our GSSAPI context. We use this opaque structure to contain all
154: * of the data which both the client and server need to persist across
155: * {accept,init}_sec_context calls, so that when we do it from the userauth
156: * stuff life is a little easier
157: */
158: void
159: ssh_gssapi_build_ctx(Gssctxt **ctx)
160: {
1.8 djm 161: *ctx = xcalloc(1, sizeof (Gssctxt));
1.1 markus 162: (*ctx)->context = GSS_C_NO_CONTEXT;
163: (*ctx)->name = GSS_C_NO_NAME;
164: (*ctx)->oid = GSS_C_NO_OID;
165: (*ctx)->creds = GSS_C_NO_CREDENTIAL;
166: (*ctx)->client = GSS_C_NO_NAME;
167: (*ctx)->client_creds = GSS_C_NO_CREDENTIAL;
168: }
169:
170: /* Delete our context, providing it has been built correctly */
171: void
172: ssh_gssapi_delete_ctx(Gssctxt **ctx)
173: {
174: OM_uint32 ms;
175:
176: if ((*ctx) == NULL)
177: return;
178: if ((*ctx)->context != GSS_C_NO_CONTEXT)
179: gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER);
180: if ((*ctx)->name != GSS_C_NO_NAME)
181: gss_release_name(&ms, &(*ctx)->name);
182: if ((*ctx)->oid != GSS_C_NO_OID) {
1.21 djm 183: free((*ctx)->oid->elements);
184: free((*ctx)->oid);
1.1 markus 185: (*ctx)->oid = GSS_C_NO_OID;
186: }
187: if ((*ctx)->creds != GSS_C_NO_CREDENTIAL)
188: gss_release_cred(&ms, &(*ctx)->creds);
189: if ((*ctx)->client != GSS_C_NO_NAME)
190: gss_release_name(&ms, &(*ctx)->client);
191: if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
192: gss_release_cred(&ms, &(*ctx)->client_creds);
193:
1.21 djm 194: free(*ctx);
1.1 markus 195: *ctx = NULL;
196: }
197:
198: /*
199: * Wrapper to init_sec_context
200: * Requires that the context contains:
201: * oid
202: * server name (from ssh_gssapi_import_name)
203: */
204: OM_uint32
205: ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
206: gss_buffer_desc* send_tok, OM_uint32 *flags)
207: {
208: int deleg_flag = 0;
209:
210: if (deleg_creds) {
211: deleg_flag = GSS_C_DELEG_FLAG;
212: debug("Delegating credentials");
213: }
214:
215: ctx->major = gss_init_sec_context(&ctx->minor,
216: GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
217: GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
218: 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
219:
220: if (GSS_ERROR(ctx->major))
221: ssh_gssapi_error(ctx);
222:
223: return (ctx->major);
224: }
225:
226: /* Create a service name for the given host */
227: OM_uint32
228: ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
229: {
230: gss_buffer_desc gssbuf;
1.10 djm 231: char *val;
1.1 markus 232:
1.10 djm 233: xasprintf(&val, "host@%s", host);
234: gssbuf.value = val;
235: gssbuf.length = strlen(gssbuf.value);
1.1 markus 236:
237: if ((ctx->major = gss_import_name(&ctx->minor,
238: &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
239: ssh_gssapi_error(ctx);
240:
1.21 djm 241: free(gssbuf.value);
1.1 markus 242: return (ctx->major);
243: }
244:
1.2 markus 245: OM_uint32
246: ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
247: {
248: if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
249: GSS_C_QOP_DEFAULT, buffer, hash)))
250: ssh_gssapi_error(ctx);
1.3 djm 251:
1.2 markus 252: return (ctx->major);
253: }
254:
255: void
1.25 markus 256: ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
1.3 djm 257: const char *context)
258: {
1.25 markus 259: int r;
260:
261: sshbuf_reset(b);
262: if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
263: (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
264: (r = sshbuf_put_cstring(b, user)) != 0 ||
265: (r = sshbuf_put_cstring(b, service)) != 0 ||
266: (r = sshbuf_put_cstring(b, context)) != 0)
1.27 ! djm 267: fatal_fr(r, "assemble buildmic");
1.14 djm 268: }
269:
270: int
1.15 djm 271: ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
1.14 djm 272: {
273: gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
274: OM_uint32 major, minor;
275: gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
276:
277: /* RFC 4462 says we MUST NOT do SPNEGO */
278: if (oid->length == spnego_oid.length &&
279: (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0))
1.16 djm 280: return 0; /* false */
1.14 djm 281:
282: ssh_gssapi_build_ctx(ctx);
283: ssh_gssapi_set_oid(*ctx, oid);
284: major = ssh_gssapi_import_name(*ctx, host);
285: if (!GSS_ERROR(major)) {
286: major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
287: NULL);
288: gss_release_buffer(&minor, &token);
1.17 dtucker 289: if ((*ctx)->context != GSS_C_NO_CONTEXT)
290: gss_delete_sec_context(&minor, &(*ctx)->context,
291: GSS_C_NO_BUFFER);
1.14 djm 292: }
293:
294: if (GSS_ERROR(major))
295: ssh_gssapi_delete_ctx(ctx);
296:
297: return (!GSS_ERROR(major));
1.1 markus 298: }
299:
300: #endif /* GSSAPI */