summaryrefslogtreecommitdiff
path: root/gss-genr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gss-genr.c')
-rw-r--r--gss-genr.c280
1 files changed, 276 insertions, 4 deletions
diff --git a/gss-genr.c b/gss-genr.c
index d56257b4a..491e62cee 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
@@ -39,14 +39,37 @@
39#include "xmalloc.h" 39#include "xmalloc.h"
40#include "ssherr.h" 40#include "ssherr.h"
41#include "sshbuf.h" 41#include "sshbuf.h"
42#include "sshkey.h"
42#include "log.h" 43#include "log.h"
43#include "ssh2.h" 44#include "ssh2.h"
45#include "cipher.h"
46#include "kex.h"
47#include "digest.h"
44 48
45#include "ssh-gss.h" 49#include "ssh-gss.h"
46 50
47extern u_char *session_id2; 51extern u_char *session_id2;
48extern u_int session_id2_len; 52extern u_int session_id2_len;
49 53
54typedef struct {
55 char *encoded;
56 gss_OID oid;
57} ssh_gss_kex_mapping;
58
59/*
60 * XXX - It would be nice to find a more elegant way of handling the
61 * XXX passing of the key exchange context to the userauth routines
62 */
63
64Gssctxt *gss_kex_context = NULL;
65
66static ssh_gss_kex_mapping *gss_enc2oid = NULL;
67
68int
69ssh_gssapi_oid_table_ok(void) {
70 return (gss_enc2oid != NULL);
71}
72
50/* sshbuf_get for gss_buffer_desc */ 73/* sshbuf_get for gss_buffer_desc */
51int 74int
52ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) 75ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
@@ -62,6 +85,143 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
62 return 0; 85 return 0;
63} 86}
64 87
88/*
89 * Return a list of the gss-group1-sha1 mechanisms supported by this program
90 *
91 * We test mechanisms to ensure that we can use them, to avoid starting
92 * a key exchange with a bad mechanism
93 */
94
95char *
96ssh_gssapi_client_mechanisms(const char *host, const char *client) {
97 gss_OID_set gss_supported;
98 OM_uint32 min_status;
99
100 if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
101 return NULL;
102
103 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
104 host, client));
105}
106
107char *
108ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
109 const char *host, const char *client) {
110 struct sshbuf *buf;
111 size_t i;
112 int r, oidpos, enclen;
113 char *mechs, *encoded;
114 u_char digest[SSH_DIGEST_MAX_LENGTH];
115 char deroid[2];
116 struct ssh_digest_ctx *md;
117
118 if (gss_enc2oid != NULL) {
119 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
120 free(gss_enc2oid[i].encoded);
121 free(gss_enc2oid);
122 }
123
124 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
125 (gss_supported->count + 1));
126
127 if ((buf = sshbuf_new()) == NULL)
128 fatal("%s: sshbuf_new failed", __func__);
129
130 oidpos = 0;
131 for (i = 0; i < gss_supported->count; i++) {
132 if (gss_supported->elements[i].length < 128 &&
133 (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
134
135 deroid[0] = SSH_GSS_OIDTYPE;
136 deroid[1] = gss_supported->elements[i].length;
137
138 if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
139 ssh_digest_update(md, deroid, 2) != 0 ||
140 ssh_digest_update(md,
141 gss_supported->elements[i].elements,
142 gss_supported->elements[i].length) != 0 ||
143 ssh_digest_final(md, digest, sizeof(digest)) != 0)
144 fatal("%s: digest failed", __func__);
145
146 encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5)
147 * 2);
148 enclen = __b64_ntop(digest,
149 ssh_digest_bytes(SSH_DIGEST_MD5), encoded,
150 ssh_digest_bytes(SSH_DIGEST_MD5) * 2);
151
152 if (oidpos != 0) {
153 if ((r = sshbuf_put_u8(buf, ',')) != 0)
154 fatal("%s: buffer error: %s",
155 __func__, ssh_err(r));
156 }
157
158 if ((r = sshbuf_put(buf, KEX_GSS_GEX_SHA1_ID,
159 sizeof(KEX_GSS_GEX_SHA1_ID) - 1)) != 0 ||
160 (r = sshbuf_put(buf, encoded, enclen)) != 0 ||
161 (r = sshbuf_put_u8(buf, ',')) != 0 ||
162 (r = sshbuf_put(buf, KEX_GSS_GRP1_SHA1_ID,
163 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1)) != 0 ||
164 (r = sshbuf_put(buf, encoded, enclen)) != 0 ||
165 (r = sshbuf_put_u8(buf, ',')) != 0 ||
166 (r = sshbuf_put(buf, KEX_GSS_GRP14_SHA1_ID,
167 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1)) != 0 ||
168 (r = sshbuf_put(buf, encoded, enclen)) != 0)
169 fatal("%s: buffer error: %s",
170 __func__, ssh_err(r));
171
172 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
173 gss_enc2oid[oidpos].encoded = encoded;
174 oidpos++;
175 }
176 }
177 gss_enc2oid[oidpos].oid = NULL;
178 gss_enc2oid[oidpos].encoded = NULL;
179
180 if ((mechs = sshbuf_dup_string(buf)) == NULL)
181 fatal("%s: sshbuf_dup_string failed", __func__);
182
183 if (strlen(mechs) == 0) {
184 free(mechs);
185 mechs = NULL;
186 }
187
188 return (mechs);
189}
190
191gss_OID
192ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
193 int i = 0;
194
195 switch (kex_type) {
196 case KEX_GSS_GRP1_SHA1:
197 if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
198 return GSS_C_NO_OID;
199 name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
200 break;
201 case KEX_GSS_GRP14_SHA1:
202 if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
203 return GSS_C_NO_OID;
204 name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
205 break;
206 case KEX_GSS_GEX_SHA1:
207 if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
208 return GSS_C_NO_OID;
209 name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
210 break;
211 default:
212 return GSS_C_NO_OID;
213 }
214
215 while (gss_enc2oid[i].encoded != NULL &&
216 strcmp(name, gss_enc2oid[i].encoded) != 0)
217 i++;
218
219 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
220 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
221
222 return gss_enc2oid[i].oid;
223}
224
65/* Check that the OID in a data stream matches that in the context */ 225/* Check that the OID in a data stream matches that in the context */
66int 226int
67ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 227ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -218,7 +378,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
218 } 378 }
219 379
220 ctx->major = gss_init_sec_context(&ctx->minor, 380 ctx->major = gss_init_sec_context(&ctx->minor,
221 GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, 381 ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
222 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 382 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
223 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 383 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
224 384
@@ -248,8 +408,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
248} 408}
249 409
250OM_uint32 410OM_uint32
411ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
412{
413 gss_buffer_desc gssbuf;
414 gss_name_t gssname;
415 OM_uint32 status;
416 gss_OID_set oidset;
417
418 gssbuf.value = (void *) name;
419 gssbuf.length = strlen(gssbuf.value);
420
421 gss_create_empty_oid_set(&status, &oidset);
422 gss_add_oid_set_member(&status, ctx->oid, &oidset);
423
424 ctx->major = gss_import_name(&ctx->minor, &gssbuf,
425 GSS_C_NT_USER_NAME, &gssname);
426
427 if (!ctx->major)
428 ctx->major = gss_acquire_cred(&ctx->minor,
429 gssname, 0, oidset, GSS_C_INITIATE,
430 &ctx->client_creds, NULL, NULL);
431
432 gss_release_name(&status, &gssname);
433 gss_release_oid_set(&status, &oidset);
434
435 if (ctx->major)
436 ssh_gssapi_error(ctx);
437
438 return(ctx->major);
439}
440
441OM_uint32
251ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 442ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
252{ 443{
444 if (ctx == NULL)
445 return -1;
446
253 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 447 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
254 GSS_C_QOP_DEFAULT, buffer, hash))) 448 GSS_C_QOP_DEFAULT, buffer, hash)))
255 ssh_gssapi_error(ctx); 449 ssh_gssapi_error(ctx);
@@ -257,6 +451,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
257 return (ctx->major); 451 return (ctx->major);
258} 452}
259 453
454/* Priviledged when used by server */
455OM_uint32
456ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
457{
458 if (ctx == NULL)
459 return -1;
460
461 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
462 gssbuf, gssmic, NULL);
463
464 return (ctx->major);
465}
466
260void 467void
261ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, 468ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
262 const char *context) 469 const char *context)
@@ -273,11 +480,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
273} 480}
274 481
275int 482int
276ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 483ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
484 const char *client)
277{ 485{
278 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 486 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
279 OM_uint32 major, minor; 487 OM_uint32 major, minor;
280 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 488 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
489 Gssctxt *intctx = NULL;
490
491 if (ctx == NULL)
492 ctx = &intctx;
281 493
282 /* RFC 4462 says we MUST NOT do SPNEGO */ 494 /* RFC 4462 says we MUST NOT do SPNEGO */
283 if (oid->length == spnego_oid.length && 495 if (oid->length == spnego_oid.length &&
@@ -287,6 +499,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
287 ssh_gssapi_build_ctx(ctx); 499 ssh_gssapi_build_ctx(ctx);
288 ssh_gssapi_set_oid(*ctx, oid); 500 ssh_gssapi_set_oid(*ctx, oid);
289 major = ssh_gssapi_import_name(*ctx, host); 501 major = ssh_gssapi_import_name(*ctx, host);
502
503 if (!GSS_ERROR(major) && client)
504 major = ssh_gssapi_client_identity(*ctx, client);
505
290 if (!GSS_ERROR(major)) { 506 if (!GSS_ERROR(major)) {
291 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 507 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
292 NULL); 508 NULL);
@@ -296,10 +512,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
296 GSS_C_NO_BUFFER); 512 GSS_C_NO_BUFFER);
297 } 513 }
298 514
299 if (GSS_ERROR(major)) 515 if (GSS_ERROR(major) || intctx != NULL)
300 ssh_gssapi_delete_ctx(ctx); 516 ssh_gssapi_delete_ctx(ctx);
301 517
302 return (!GSS_ERROR(major)); 518 return (!GSS_ERROR(major));
303} 519}
304 520
521int
522ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
523 static gss_name_t saved_name = GSS_C_NO_NAME;
524 static OM_uint32 saved_lifetime = 0;
525 static gss_OID saved_mech = GSS_C_NO_OID;
526 static gss_name_t name;
527 static OM_uint32 last_call = 0;
528 OM_uint32 lifetime, now, major, minor;
529 int equal;
530
531 now = time(NULL);
532
533 if (ctxt) {
534 debug("Rekey has happened - updating saved versions");
535
536 if (saved_name != GSS_C_NO_NAME)
537 gss_release_name(&minor, &saved_name);
538
539 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
540 &saved_name, &saved_lifetime, NULL, NULL);
541
542 if (!GSS_ERROR(major)) {
543 saved_mech = ctxt->oid;
544 saved_lifetime+= now;
545 } else {
546 /* Handle the error */
547 }
548 return 0;
549 }
550
551 if (now - last_call < 10)
552 return 0;
553
554 last_call = now;
555
556 if (saved_mech == GSS_C_NO_OID)
557 return 0;
558
559 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
560 &name, &lifetime, NULL, NULL);
561 if (major == GSS_S_CREDENTIALS_EXPIRED)
562 return 0;
563 else if (GSS_ERROR(major))
564 return 0;
565
566 major = gss_compare_name(&minor, saved_name, name, &equal);
567 gss_release_name(&minor, &name);
568 if (GSS_ERROR(major))
569 return 0;
570
571 if (equal && (saved_lifetime < lifetime + now - 10))
572 return 1;
573
574 return 0;
575}
576
305#endif /* GSSAPI */ 577#endif /* GSSAPI */