summaryrefslogtreecommitdiff
path: root/gss-genr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gss-genr.c')
-rw-r--r--gss-genr.c275
1 files changed, 271 insertions, 4 deletions
diff --git a/gss-genr.c b/gss-genr.c
index d617d600a..b4eca3feb 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt 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,167 @@
41#include "buffer.h" 41#include "buffer.h"
42#include "log.h" 42#include "log.h"
43#include "ssh2.h" 43#include "ssh2.h"
44#include "cipher.h"
45#include "key.h"
46#include "kex.h"
47#include <openssl/evp.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
73/*
74 * Return a list of the gss-group1-sha1 mechanisms supported by this program
75 *
76 * We test mechanisms to ensure that we can use them, to avoid starting
77 * a key exchange with a bad mechanism
78 */
79
80char *
81ssh_gssapi_client_mechanisms(const char *host, const char *client) {
82 gss_OID_set gss_supported;
83 OM_uint32 min_status;
84
85 if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
86 return NULL;
87
88 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
89 host, client));
90}
91
92char *
93ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
94 const char *host, const char *client) {
95 Buffer buf;
96 size_t i;
97 int oidpos, enclen;
98 char *mechs, *encoded;
99 u_char digest[EVP_MAX_MD_SIZE];
100 char deroid[2];
101 const EVP_MD *evp_md = EVP_md5();
102 EVP_MD_CTX md;
103
104 if (gss_enc2oid != NULL) {
105 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
106 free(gss_enc2oid[i].encoded);
107 free(gss_enc2oid);
108 }
109
110 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
111 (gss_supported->count + 1));
112
113 buffer_init(&buf);
114
115 oidpos = 0;
116 for (i = 0; i < gss_supported->count; i++) {
117 if (gss_supported->elements[i].length < 128 &&
118 (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
119
120 deroid[0] = SSH_GSS_OIDTYPE;
121 deroid[1] = gss_supported->elements[i].length;
122
123 EVP_DigestInit(&md, evp_md);
124 EVP_DigestUpdate(&md, deroid, 2);
125 EVP_DigestUpdate(&md,
126 gss_supported->elements[i].elements,
127 gss_supported->elements[i].length);
128 EVP_DigestFinal(&md, digest, NULL);
129
130 encoded = xmalloc(EVP_MD_size(evp_md) * 2);
131 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
132 encoded, EVP_MD_size(evp_md) * 2);
133
134 if (oidpos != 0)
135 buffer_put_char(&buf, ',');
136
137 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
138 sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
139 buffer_append(&buf, encoded, enclen);
140 buffer_put_char(&buf, ',');
141 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
142 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
143 buffer_append(&buf, encoded, enclen);
144 buffer_put_char(&buf, ',');
145 buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
146 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
147 buffer_append(&buf, encoded, enclen);
148
149 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
150 gss_enc2oid[oidpos].encoded = encoded;
151 oidpos++;
152 }
153 }
154 gss_enc2oid[oidpos].oid = NULL;
155 gss_enc2oid[oidpos].encoded = NULL;
156
157 buffer_put_char(&buf, '\0');
158
159 mechs = xmalloc(buffer_len(&buf));
160 buffer_get(&buf, mechs, buffer_len(&buf));
161 buffer_free(&buf);
162
163 if (strlen(mechs) == 0) {
164 free(mechs);
165 mechs = NULL;
166 }
167
168 return (mechs);
169}
170
171gss_OID
172ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
173 int i = 0;
174
175 switch (kex_type) {
176 case KEX_GSS_GRP1_SHA1:
177 if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
178 return GSS_C_NO_OID;
179 name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
180 break;
181 case KEX_GSS_GRP14_SHA1:
182 if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
183 return GSS_C_NO_OID;
184 name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
185 break;
186 case KEX_GSS_GEX_SHA1:
187 if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
188 return GSS_C_NO_OID;
189 name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
190 break;
191 default:
192 return GSS_C_NO_OID;
193 }
194
195 while (gss_enc2oid[i].encoded != NULL &&
196 strcmp(name, gss_enc2oid[i].encoded) != 0)
197 i++;
198
199 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
200 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
201
202 return gss_enc2oid[i].oid;
203}
204
50/* Check that the OID in a data stream matches that in the context */ 205/* Check that the OID in a data stream matches that in the context */
51int 206int
52ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 207ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -199,7 +354,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
199 } 354 }
200 355
201 ctx->major = gss_init_sec_context(&ctx->minor, 356 ctx->major = gss_init_sec_context(&ctx->minor,
202 GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, 357 ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
203 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 358 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
204 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 359 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
205 360
@@ -229,8 +384,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
229} 384}
230 385
231OM_uint32 386OM_uint32
387ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
388{
389 gss_buffer_desc gssbuf;
390 gss_name_t gssname;
391 OM_uint32 status;
392 gss_OID_set oidset;
393
394 gssbuf.value = (void *) name;
395 gssbuf.length = strlen(gssbuf.value);
396
397 gss_create_empty_oid_set(&status, &oidset);
398 gss_add_oid_set_member(&status, ctx->oid, &oidset);
399
400 ctx->major = gss_import_name(&ctx->minor, &gssbuf,
401 GSS_C_NT_USER_NAME, &gssname);
402
403 if (!ctx->major)
404 ctx->major = gss_acquire_cred(&ctx->minor,
405 gssname, 0, oidset, GSS_C_INITIATE,
406 &ctx->client_creds, NULL, NULL);
407
408 gss_release_name(&status, &gssname);
409 gss_release_oid_set(&status, &oidset);
410
411 if (ctx->major)
412 ssh_gssapi_error(ctx);
413
414 return(ctx->major);
415}
416
417OM_uint32
232ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 418ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
233{ 419{
420 if (ctx == NULL)
421 return -1;
422
234 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 423 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
235 GSS_C_QOP_DEFAULT, buffer, hash))) 424 GSS_C_QOP_DEFAULT, buffer, hash)))
236 ssh_gssapi_error(ctx); 425 ssh_gssapi_error(ctx);
@@ -238,6 +427,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
238 return (ctx->major); 427 return (ctx->major);
239} 428}
240 429
430/* Priviledged when used by server */
431OM_uint32
432ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
433{
434 if (ctx == NULL)
435 return -1;
436
437 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
438 gssbuf, gssmic, NULL);
439
440 return (ctx->major);
441}
442
241void 443void
242ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 444ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
243 const char *context) 445 const char *context)
@@ -251,11 +453,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
251} 453}
252 454
253int 455int
254ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 456ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
457 const char *client)
255{ 458{
256 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 459 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
257 OM_uint32 major, minor; 460 OM_uint32 major, minor;
258 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 461 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
462 Gssctxt *intctx = NULL;
463
464 if (ctx == NULL)
465 ctx = &intctx;
259 466
260 /* RFC 4462 says we MUST NOT do SPNEGO */ 467 /* RFC 4462 says we MUST NOT do SPNEGO */
261 if (oid->length == spnego_oid.length && 468 if (oid->length == spnego_oid.length &&
@@ -265,6 +472,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
265 ssh_gssapi_build_ctx(ctx); 472 ssh_gssapi_build_ctx(ctx);
266 ssh_gssapi_set_oid(*ctx, oid); 473 ssh_gssapi_set_oid(*ctx, oid);
267 major = ssh_gssapi_import_name(*ctx, host); 474 major = ssh_gssapi_import_name(*ctx, host);
475
476 if (!GSS_ERROR(major) && client)
477 major = ssh_gssapi_client_identity(*ctx, client);
478
268 if (!GSS_ERROR(major)) { 479 if (!GSS_ERROR(major)) {
269 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 480 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
270 NULL); 481 NULL);
@@ -274,10 +485,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
274 GSS_C_NO_BUFFER); 485 GSS_C_NO_BUFFER);
275 } 486 }
276 487
277 if (GSS_ERROR(major)) 488 if (GSS_ERROR(major) || intctx != NULL)
278 ssh_gssapi_delete_ctx(ctx); 489 ssh_gssapi_delete_ctx(ctx);
279 490
280 return (!GSS_ERROR(major)); 491 return (!GSS_ERROR(major));
281} 492}
282 493
494int
495ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
496 static gss_name_t saved_name = GSS_C_NO_NAME;
497 static OM_uint32 saved_lifetime = 0;
498 static gss_OID saved_mech = GSS_C_NO_OID;
499 static gss_name_t name;
500 static OM_uint32 last_call = 0;
501 OM_uint32 lifetime, now, major, minor;
502 int equal;
503
504 now = time(NULL);
505
506 if (ctxt) {
507 debug("Rekey has happened - updating saved versions");
508
509 if (saved_name != GSS_C_NO_NAME)
510 gss_release_name(&minor, &saved_name);
511
512 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
513 &saved_name, &saved_lifetime, NULL, NULL);
514
515 if (!GSS_ERROR(major)) {
516 saved_mech = ctxt->oid;
517 saved_lifetime+= now;
518 } else {
519 /* Handle the error */
520 }
521 return 0;
522 }
523
524 if (now - last_call < 10)
525 return 0;
526
527 last_call = now;
528
529 if (saved_mech == GSS_C_NO_OID)
530 return 0;
531
532 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
533 &name, &lifetime, NULL, NULL);
534 if (major == GSS_S_CREDENTIALS_EXPIRED)
535 return 0;
536 else if (GSS_ERROR(major))
537 return 0;
538
539 major = gss_compare_name(&minor, saved_name, name, &equal);
540 gss_release_name(&minor, &name);
541 if (GSS_ERROR(major))
542 return 0;
543
544 if (equal && (saved_lifetime < lifetime + now - 10))
545 return 1;
546
547 return 0;
548}
549
283#endif /* GSSAPI */ 550#endif /* GSSAPI */