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