summaryrefslogtreecommitdiff
path: root/gss-genr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gss-genr.c')
-rw-r--r--gss-genr.c176
1 files changed, 87 insertions, 89 deletions
diff --git a/gss-genr.c b/gss-genr.c
index dfaa708ea..42f942b58 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.6 2005/10/13 22:24:31 stevesk Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.17 2006/08/29 12:02:30 dtucker Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2006 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
@@ -28,10 +28,20 @@
28 28
29#ifdef GSSAPI 29#ifdef GSSAPI
30 30
31#include <sys/types.h>
32#include <sys/param.h>
33
34#include <stdarg.h>
35#include <string.h>
36#include <unistd.h>
37
31#include "xmalloc.h" 38#include "xmalloc.h"
32#include "bufaux.h" 39#include "buffer.h"
33#include "log.h" 40#include "log.h"
34#include "ssh2.h" 41#include "ssh2.h"
42#include "cipher.h"
43#include "key.h"
44#include "kex.h"
35#include <openssl/evp.h> 45#include <openssl/evp.h>
36 46
37#include "ssh-gss.h" 47#include "ssh-gss.h"
@@ -65,7 +75,6 @@ ssh_gssapi_oid_table_ok() {
65 * a key exchange with a bad mechanism 75 * a key exchange with a bad mechanism
66 */ 76 */
67 77
68
69char * 78char *
70ssh_gssapi_client_mechanisms(const char *host) { 79ssh_gssapi_client_mechanisms(const char *host) {
71 gss_OID_set gss_supported; 80 gss_OID_set gss_supported;
@@ -74,35 +83,36 @@ ssh_gssapi_client_mechanisms(const char *host) {
74 gss_indicate_mechs(&min_status, &gss_supported); 83 gss_indicate_mechs(&min_status, &gss_supported);
75 84
76 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, 85 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
77 (void *)host)); 86 host));
78} 87}
79 88
80char * 89char *
81ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, 90ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
82 void *data) { 91 const char *data) {
83 Buffer buf; 92 Buffer buf;
84 int i, oidpos, enclen; 93 size_t i;
94 int oidpos, enclen;
85 char *mechs, *encoded; 95 char *mechs, *encoded;
86 char digest[EVP_MAX_MD_SIZE]; 96 u_char digest[EVP_MAX_MD_SIZE];
87 char deroid[2]; 97 char deroid[2];
88 const EVP_MD *evp_md = EVP_md5(); 98 const EVP_MD *evp_md = EVP_md5();
89 EVP_MD_CTX md; 99 EVP_MD_CTX md;
90 100
91 if (gss_enc2oid != NULL) { 101 if (gss_enc2oid != NULL) {
92 for (i=0;gss_enc2oid[i].encoded!=NULL;i++) 102 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
93 xfree(gss_enc2oid[i].encoded); 103 xfree(gss_enc2oid[i].encoded);
94 xfree(gss_enc2oid); 104 xfree(gss_enc2oid);
95 } 105 }
96 106
97 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping)* 107 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
98 (gss_supported->count+1)); 108 (gss_supported->count + 1));
99 109
100 buffer_init(&buf); 110 buffer_init(&buf);
101 111
102 oidpos = 0; 112 oidpos = 0;
103 for (i = 0;i < gss_supported->count;i++) { 113 for (i = 0; i < gss_supported->count; i++) {
104 if (gss_supported->elements[i].length < 128 && 114 if (gss_supported->elements[i].length < 128 &&
105 (*check)(&(gss_supported->elements[i]), data)) { 115 (*check)(NULL, &(gss_supported->elements[i]), data)) {
106 116
107 deroid[0] = SSH_GSS_OIDTYPE; 117 deroid[0] = SSH_GSS_OIDTYPE;
108 deroid[1] = gss_supported->elements[i].length; 118 deroid[1] = gss_supported->elements[i].length;
@@ -114,19 +124,23 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
114 gss_supported->elements[i].length); 124 gss_supported->elements[i].length);
115 EVP_DigestFinal(&md, digest, NULL); 125 EVP_DigestFinal(&md, digest, NULL);
116 126
117 encoded = xmalloc(EVP_MD_size(evp_md)*2); 127 encoded = xmalloc(EVP_MD_size(evp_md) * 2);
118 enclen = __b64_ntop(digest, EVP_MD_size(evp_md), 128 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
119 encoded, EVP_MD_size(evp_md)*2); 129 encoded, EVP_MD_size(evp_md) * 2);
120 130
121 if (oidpos != 0) 131 if (oidpos != 0)
122 buffer_put_char(&buf, ','); 132 buffer_put_char(&buf, ',');
123 133
124 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, 134 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
125 sizeof(KEX_GSS_GEX_SHA1_ID)-1); 135 sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
126 buffer_append(&buf, encoded, enclen); 136 buffer_append(&buf, encoded, enclen);
127 buffer_put_char(&buf,','); 137 buffer_put_char(&buf, ',');
128 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, 138 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
129 sizeof(KEX_GSS_GRP1_SHA1_ID)-1); 139 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
140 buffer_append(&buf, encoded, enclen);
141 buffer_put_char(&buf, ',');
142 buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
143 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
130 buffer_append(&buf, encoded, enclen); 144 buffer_append(&buf, encoded, enclen);
131 145
132 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); 146 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
@@ -152,25 +166,26 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
152} 166}
153 167
154gss_OID 168gss_OID
155ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int *gex) { 169ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
156 int i = 0; 170 int i = 0;
157 171
158 if (strncmp(name, KEX_GSS_GRP1_SHA1_ID, 172 switch (kex_type) {
159 sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) { 173 case KEX_GSS_GRP1_SHA1:
160 name+=sizeof(KEX_GSS_GRP1_SHA1_ID)-1; 174 name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
161 *gex = 0; 175 break;
162 } else if (strncmp(name, KEX_GSS_GEX_SHA1_ID, 176 case KEX_GSS_GRP14_SHA1:
163 sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) { 177 name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
164 name+=sizeof(KEX_GSS_GEX_SHA1_ID)-1; 178 break;
165 *gex = 1; 179 case KEX_GSS_GEX_SHA1:
166 } else { 180 name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
167 return NULL; 181 break;
182 default:
183 return GSS_C_NO_OID;
168 } 184 }
169 185
170 while (gss_enc2oid[i].encoded != NULL && 186 while (gss_enc2oid[i].encoded != NULL &&
171 strcmp(name, gss_enc2oid[i].encoded) != 0) { 187 strcmp(name, gss_enc2oid[i].encoded) != 0)
172 i++; 188 i++;
173 }
174 189
175 if (gss_enc2oid[i].oid != NULL && ctx != NULL) 190 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
176 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); 191 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
@@ -212,7 +227,11 @@ ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
212void 227void
213ssh_gssapi_error(Gssctxt *ctxt) 228ssh_gssapi_error(Gssctxt *ctxt)
214{ 229{
215 debug("%s", ssh_gssapi_last_error(ctxt, NULL, NULL)); 230 char *s;
231
232 s = ssh_gssapi_last_error(ctxt, NULL, NULL);
233 debug("%s", s);
234 xfree(s);
216} 235}
217 236
218char * 237char *
@@ -236,7 +255,7 @@ ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status,
236 /* The GSSAPI error */ 255 /* The GSSAPI error */
237 do { 256 do {
238 gss_display_status(&lmin, ctxt->major, 257 gss_display_status(&lmin, ctxt->major,
239 GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg); 258 GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg);
240 259
241 buffer_append(&b, msg.value, msg.length); 260 buffer_append(&b, msg.value, msg.length);
242 buffer_put_char(&b, '\n'); 261 buffer_put_char(&b, '\n');
@@ -247,7 +266,7 @@ ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status,
247 /* The mechanism specific error */ 266 /* The mechanism specific error */
248 do { 267 do {
249 gss_display_status(&lmin, ctxt->minor, 268 gss_display_status(&lmin, ctxt->minor,
250 GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg); 269 GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg);
251 270
252 buffer_append(&b, msg.value, msg.length); 271 buffer_append(&b, msg.value, msg.length);
253 buffer_put_char(&b, '\n'); 272 buffer_put_char(&b, '\n');
@@ -271,9 +290,7 @@ ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status,
271void 290void
272ssh_gssapi_build_ctx(Gssctxt **ctx) 291ssh_gssapi_build_ctx(Gssctxt **ctx)
273{ 292{
274 *ctx = xmalloc(sizeof (Gssctxt)); 293 *ctx = xcalloc(1, sizeof (Gssctxt));
275 (*ctx)->major = 0;
276 (*ctx)->minor = 0;
277 (*ctx)->context = GSS_C_NO_CONTEXT; 294 (*ctx)->context = GSS_C_NO_CONTEXT;
278 (*ctx)->name = GSS_C_NO_NAME; 295 (*ctx)->name = GSS_C_NO_NAME;
279 (*ctx)->oid = GSS_C_NO_OID; 296 (*ctx)->oid = GSS_C_NO_OID;
@@ -343,10 +360,11 @@ OM_uint32
343ssh_gssapi_import_name(Gssctxt *ctx, const char *host) 360ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
344{ 361{
345 gss_buffer_desc gssbuf; 362 gss_buffer_desc gssbuf;
363 char *val;
346 364
347 gssbuf.length = sizeof("host@") + strlen(host); 365 xasprintf(&val, "host@%s", host);
348 gssbuf.value = xmalloc(gssbuf.length); 366 gssbuf.value = val;
349 snprintf(gssbuf.value, gssbuf.length, "host@%s", host); 367 gssbuf.length = strlen(gssbuf.value);
350 368
351 if ((ctx->major = gss_import_name(&ctx->minor, 369 if ((ctx->major = gss_import_name(&ctx->minor,
352 &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) 370 &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
@@ -356,35 +374,6 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
356 return (ctx->major); 374 return (ctx->major);
357} 375}
358 376
359/* Acquire credentials for a server running on the current host.
360 * Requires that the context structure contains a valid OID
361 */
362
363/* Returns a GSSAPI error code */
364OM_uint32
365ssh_gssapi_acquire_cred(Gssctxt *ctx)
366{
367 OM_uint32 status;
368 char lname[MAXHOSTNAMELEN];
369 gss_OID_set oidset;
370
371 gss_create_empty_oid_set(&status, &oidset);
372 gss_add_oid_set_member(&status, ctx->oid, &oidset);
373
374 if (gethostname(lname, MAXHOSTNAMELEN))
375 return (-1);
376
377 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname)))
378 return (ctx->major);
379
380 if ((ctx->major = gss_acquire_cred(&ctx->minor,
381 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
382 ssh_gssapi_error(ctx);
383
384 gss_release_oid_set(&status, &oidset);
385 return (ctx->major);
386}
387
388OM_uint32 377OM_uint32
389ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 378ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
390{ 379{
@@ -423,28 +412,37 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
423 buffer_put_cstring(b, context); 412 buffer_put_cstring(b, context);
424} 413}
425 414
426OM_uint32 415int
427ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) 416ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
428{ 417{
429 if (*ctx) 418 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
430 ssh_gssapi_delete_ctx(ctx); 419 OM_uint32 major, minor;
420 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
421 Gssctxt *intctx = NULL;
422
423 if (ctx == NULL)
424 ctx = &intctx;
425
426 /* RFC 4462 says we MUST NOT do SPNEGO */
427 if (oid->length == spnego_oid.length &&
428 (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0))
429 return 0; /* false */
430
431 ssh_gssapi_build_ctx(ctx); 431 ssh_gssapi_build_ctx(ctx);
432 ssh_gssapi_set_oid(*ctx, oid); 432 ssh_gssapi_set_oid(*ctx, oid);
433 return (ssh_gssapi_acquire_cred(*ctx)); 433 major = ssh_gssapi_import_name(*ctx, host);
434} 434 if (!GSS_ERROR(major)) {
435 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
436 NULL);
437 gss_release_buffer(&minor, &token);
438 if ((*ctx)->context != GSS_C_NO_CONTEXT)
439 gss_delete_sec_context(&minor, &(*ctx)->context,
440 GSS_C_NO_BUFFER);
441 }
442
443 if (GSS_ERROR(major) || intctx != NULL)
444 ssh_gssapi_delete_ctx(ctx);
435 445
436int
437ssh_gssapi_check_mechanism(gss_OID oid, void *host) {
438 Gssctxt * ctx = NULL;
439 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
440 OM_uint32 major, minor;
441
442 ssh_gssapi_build_ctx(&ctx);
443 ssh_gssapi_set_oid(ctx, oid);
444 ssh_gssapi_import_name(ctx, host);
445 major = ssh_gssapi_init_ctx(ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
446 gss_release_buffer(&minor, &token);
447 ssh_gssapi_delete_ctx(&ctx);
448 return (!GSS_ERROR(major)); 446 return (!GSS_ERROR(major));
449} 447}
450 448