summaryrefslogtreecommitdiff
path: root/gss-genr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gss-genr.c')
-rw-r--r--gss-genr.c300
1 files changed, 296 insertions, 4 deletions
diff --git a/gss-genr.c b/gss-genr.c
index d56257b4a..763a63ffa 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.26 2018/07/10 09:13:30 djm Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.26 2018/07/10 09:13:30 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -41,12 +41,36 @@
41#include "sshbuf.h" 41#include "sshbuf.h"
42#include "log.h" 42#include "log.h"
43#include "ssh2.h" 43#include "ssh2.h"
44#include "cipher.h"
45#include "sshkey.h"
46#include "kex.h"
47#include "digest.h"
48#include "packet.h"
44 49
45#include "ssh-gss.h" 50#include "ssh-gss.h"
46 51
47extern u_char *session_id2; 52extern u_char *session_id2;
48extern u_int session_id2_len; 53extern u_int session_id2_len;
49 54
55typedef struct {
56 char *encoded;
57 gss_OID oid;
58} ssh_gss_kex_mapping;
59
60/*
61 * XXX - It would be nice to find a more elegant way of handling the
62 * XXX passing of the key exchange context to the userauth routines
63 */
64
65Gssctxt *gss_kex_context = NULL;
66
67static ssh_gss_kex_mapping *gss_enc2oid = NULL;
68
69int
70ssh_gssapi_oid_table_ok(void) {
71 return (gss_enc2oid != NULL);
72}
73
50/* sshbuf_get for gss_buffer_desc */ 74/* sshbuf_get for gss_buffer_desc */
51int 75int
52ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) 76ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
@@ -62,6 +86,162 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
62 return 0; 86 return 0;
63} 87}
64 88
89/* sshpkt_get of gss_buffer_desc */
90int
91ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *ssh, gss_buffer_desc *g)
92{
93 int r;
94 u_char *p;
95 size_t len;
96
97 if ((r = sshpkt_get_string(ssh, &p, &len)) != 0)
98 return r;
99 g->value = p;
100 g->length = len;
101 return 0;
102}
103
104/*
105 * Return a list of the gss-group1-sha1 mechanisms supported by this program
106 *
107 * We test mechanisms to ensure that we can use them, to avoid starting
108 * a key exchange with a bad mechanism
109 */
110
111char *
112ssh_gssapi_client_mechanisms(const char *host, const char *client,
113 const char *kex) {
114 gss_OID_set gss_supported = NULL;
115 OM_uint32 min_status;
116
117 if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
118 return NULL;
119
120 return ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
121 host, client, kex);
122}
123
124char *
125ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
126 const char *host, const char *client, const char *kex) {
127 struct sshbuf *buf = NULL;
128 size_t i;
129 int r = SSH_ERR_ALLOC_FAIL;
130 int oidpos, enclen;
131 char *mechs, *encoded;
132 u_char digest[SSH_DIGEST_MAX_LENGTH];
133 char deroid[2];
134 struct ssh_digest_ctx *md = NULL;
135 char *s, *cp, *p;
136
137 if (gss_enc2oid != NULL) {
138 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
139 free(gss_enc2oid[i].encoded);
140 free(gss_enc2oid);
141 }
142
143 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
144 (gss_supported->count + 1));
145
146 if ((buf = sshbuf_new()) == NULL)
147 fatal("%s: sshbuf_new failed", __func__);
148
149 oidpos = 0;
150 s = cp = xstrdup(kex);
151 for (i = 0; i < gss_supported->count; i++) {
152 if (gss_supported->elements[i].length < 128 &&
153 (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
154
155 deroid[0] = SSH_GSS_OIDTYPE;
156 deroid[1] = gss_supported->elements[i].length;
157
158 if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
159 (r = ssh_digest_update(md, deroid, 2)) != 0 ||
160 (r = ssh_digest_update(md,
161 gss_supported->elements[i].elements,
162 gss_supported->elements[i].length)) != 0 ||
163 (r = ssh_digest_final(md, digest, sizeof(digest))) != 0)
164 fatal("%s: digest failed: %s", __func__,
165 ssh_err(r));
166 ssh_digest_free(md);
167 md = NULL;
168
169 encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5)
170 * 2);
171 enclen = __b64_ntop(digest,
172 ssh_digest_bytes(SSH_DIGEST_MD5), encoded,
173 ssh_digest_bytes(SSH_DIGEST_MD5) * 2);
174
175 cp = strncpy(s, kex, strlen(kex));
176 for ((p = strsep(&cp, ",")); p && *p != '\0';
177 (p = strsep(&cp, ","))) {
178 if (sshbuf_len(buf) != 0 &&
179 (r = sshbuf_put_u8(buf, ',')) != 0)
180 fatal("%s: sshbuf_put_u8 error: %s",
181 __func__, ssh_err(r));
182 if ((r = sshbuf_put(buf, p, strlen(p))) != 0 ||
183 (r = sshbuf_put(buf, encoded, enclen)) != 0)
184 fatal("%s: sshbuf_put error: %s",
185 __func__, ssh_err(r));
186 }
187
188 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
189 gss_enc2oid[oidpos].encoded = encoded;
190 oidpos++;
191 }
192 }
193 free(s);
194 gss_enc2oid[oidpos].oid = NULL;
195 gss_enc2oid[oidpos].encoded = NULL;
196
197 if ((mechs = sshbuf_dup_string(buf)) == NULL)
198 fatal("%s: sshbuf_dup_string failed", __func__);
199
200 sshbuf_free(buf);
201
202 if (strlen(mechs) == 0) {
203 free(mechs);
204 mechs = NULL;
205 }
206
207 return (mechs);
208}
209
210gss_OID
211ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
212 int i = 0;
213
214#define SKIP_KEX_NAME(type) \
215 case type: \
216 if (strlen(name) < sizeof(type##_ID)) \
217 return GSS_C_NO_OID; \
218 name += sizeof(type##_ID) - 1; \
219 break;
220
221 switch (kex_type) {
222 SKIP_KEX_NAME(KEX_GSS_GRP1_SHA1)
223 SKIP_KEX_NAME(KEX_GSS_GRP14_SHA1)
224 SKIP_KEX_NAME(KEX_GSS_GRP14_SHA256)
225 SKIP_KEX_NAME(KEX_GSS_GRP16_SHA512)
226 SKIP_KEX_NAME(KEX_GSS_GEX_SHA1)
227 SKIP_KEX_NAME(KEX_GSS_NISTP256_SHA256)
228 SKIP_KEX_NAME(KEX_GSS_C25519_SHA256)
229 default:
230 return GSS_C_NO_OID;
231 }
232
233#undef SKIP_KEX_NAME
234
235 while (gss_enc2oid[i].encoded != NULL &&
236 strcmp(name, gss_enc2oid[i].encoded) != 0)
237 i++;
238
239 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
240 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
241
242 return gss_enc2oid[i].oid;
243}
244
65/* Check that the OID in a data stream matches that in the context */ 245/* Check that the OID in a data stream matches that in the context */
66int 246int
67ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 247ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
218 } 398 }
219 399
220 ctx->major = gss_init_sec_context(&ctx->minor, 400 ctx->major = gss_init_sec_context(&ctx->minor,
221 GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, 401 ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
222 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 402 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
223 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 403 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
224 404
@@ -248,8 +428,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
248} 428}
249 429
250OM_uint32 430OM_uint32
431ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
432{
433 gss_buffer_desc gssbuf;
434 gss_name_t gssname;
435 OM_uint32 status;
436 gss_OID_set oidset;
437
438 gssbuf.value = (void *) name;
439 gssbuf.length = strlen(gssbuf.value);
440
441 gss_create_empty_oid_set(&status, &oidset);
442 gss_add_oid_set_member(&status, ctx->oid, &oidset);
443
444 ctx->major = gss_import_name(&ctx->minor, &gssbuf,
445 GSS_C_NT_USER_NAME, &gssname);
446
447 if (!ctx->major)
448 ctx->major = gss_acquire_cred(&ctx->minor,
449 gssname, 0, oidset, GSS_C_INITIATE,
450 &ctx->client_creds, NULL, NULL);
451
452 gss_release_name(&status, &gssname);
453 gss_release_oid_set(&status, &oidset);
454
455 if (ctx->major)
456 ssh_gssapi_error(ctx);
457
458 return(ctx->major);
459}
460
461OM_uint32
251ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 462ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
252{ 463{
464 if (ctx == NULL)
465 return -1;
466
253 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 467 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
254 GSS_C_QOP_DEFAULT, buffer, hash))) 468 GSS_C_QOP_DEFAULT, buffer, hash)))
255 ssh_gssapi_error(ctx); 469 ssh_gssapi_error(ctx);
@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
257 return (ctx->major); 471 return (ctx->major);
258} 472}
259 473
474/* Priviledged when used by server */
475OM_uint32
476ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
477{
478 if (ctx == NULL)
479 return -1;
480
481 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
482 gssbuf, gssmic, NULL);
483
484 return (ctx->major);
485}
486
260void 487void
261ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, 488ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
262 const char *context) 489 const char *context)
@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
273} 500}
274 501
275int 502int
276ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 503ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
504 const char *client)
277{ 505{
278 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 506 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
279 OM_uint32 major, minor; 507 OM_uint32 major, minor;
280 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 508 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
509 Gssctxt *intctx = NULL;
510
511 if (ctx == NULL)
512 ctx = &intctx;
281 513
282 /* RFC 4462 says we MUST NOT do SPNEGO */ 514 /* RFC 4462 says we MUST NOT do SPNEGO */
283 if (oid->length == spnego_oid.length && 515 if (oid->length == spnego_oid.length &&
@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
287 ssh_gssapi_build_ctx(ctx); 519 ssh_gssapi_build_ctx(ctx);
288 ssh_gssapi_set_oid(*ctx, oid); 520 ssh_gssapi_set_oid(*ctx, oid);
289 major = ssh_gssapi_import_name(*ctx, host); 521 major = ssh_gssapi_import_name(*ctx, host);
522
523 if (!GSS_ERROR(major) && client)
524 major = ssh_gssapi_client_identity(*ctx, client);
525
290 if (!GSS_ERROR(major)) { 526 if (!GSS_ERROR(major)) {
291 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 527 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
292 NULL); 528 NULL);
@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
296 GSS_C_NO_BUFFER); 532 GSS_C_NO_BUFFER);
297 } 533 }
298 534
299 if (GSS_ERROR(major)) 535 if (GSS_ERROR(major) || intctx != NULL)
300 ssh_gssapi_delete_ctx(ctx); 536 ssh_gssapi_delete_ctx(ctx);
301 537
302 return (!GSS_ERROR(major)); 538 return (!GSS_ERROR(major));
303} 539}
304 540
541int
542ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
543 static gss_name_t saved_name = GSS_C_NO_NAME;
544 static OM_uint32 saved_lifetime = 0;
545 static gss_OID saved_mech = GSS_C_NO_OID;
546 static gss_name_t name;
547 static OM_uint32 last_call = 0;
548 OM_uint32 lifetime, now, major, minor;
549 int equal;
550
551 now = time(NULL);
552
553 if (ctxt) {
554 debug("Rekey has happened - updating saved versions");
555
556 if (saved_name != GSS_C_NO_NAME)
557 gss_release_name(&minor, &saved_name);
558
559 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
560 &saved_name, &saved_lifetime, NULL, NULL);
561
562 if (!GSS_ERROR(major)) {
563 saved_mech = ctxt->oid;
564 saved_lifetime+= now;
565 } else {
566 /* Handle the error */
567 }
568 return 0;
569 }
570
571 if (now - last_call < 10)
572 return 0;
573
574 last_call = now;
575
576 if (saved_mech == GSS_C_NO_OID)
577 return 0;
578
579 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
580 &name, &lifetime, NULL, NULL);
581 if (major == GSS_S_CREDENTIALS_EXPIRED)
582 return 0;
583 else if (GSS_ERROR(major))
584 return 0;
585
586 major = gss_compare_name(&minor, saved_name, name, &equal);
587 gss_release_name(&minor, &name);
588 if (GSS_ERROR(major))
589 return 0;
590
591 if (equal && (saved_lifetime < lifetime + now - 10))
592 return 1;
593
594 return 0;
595}
596
305#endif /* GSSAPI */ 597#endif /* GSSAPI */