diff options
Diffstat (limited to 'gss-genr.c')
-rw-r--r-- | gss-genr.c | 170 |
1 files changed, 169 insertions, 1 deletions
diff --git a/gss-genr.c b/gss-genr.c index e9190575d..822a08212 100644 --- a/gss-genr.c +++ b/gss-genr.c | |||
@@ -39,12 +39,160 @@ | |||
39 | #include "buffer.h" | 39 | #include "buffer.h" |
40 | #include "log.h" | 40 | #include "log.h" |
41 | #include "ssh2.h" | 41 | #include "ssh2.h" |
42 | #include "cipher.h" | ||
43 | #include "key.h" | ||
44 | #include "kex.h" | ||
45 | #include <openssl/evp.h> | ||
42 | 46 | ||
43 | #include "ssh-gss.h" | 47 | #include "ssh-gss.h" |
44 | 48 | ||
45 | extern u_char *session_id2; | 49 | extern u_char *session_id2; |
46 | extern u_int session_id2_len; | 50 | extern u_int session_id2_len; |
47 | 51 | ||
52 | typedef struct { | ||
53 | char *encoded; | ||
54 | gss_OID oid; | ||
55 | } ssh_gss_kex_mapping; | ||
56 | |||
57 | /* | ||
58 | * XXX - It would be nice to find a more elegant way of handling the | ||
59 | * XXX passing of the key exchange context to the userauth routines | ||
60 | */ | ||
61 | |||
62 | Gssctxt *gss_kex_context = NULL; | ||
63 | |||
64 | static ssh_gss_kex_mapping *gss_enc2oid = NULL; | ||
65 | |||
66 | int | ||
67 | ssh_gssapi_oid_table_ok() { | ||
68 | return (gss_enc2oid != NULL); | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Return a list of the gss-group1-sha1 mechanisms supported by this program | ||
73 | * | ||
74 | * We test mechanisms to ensure that we can use them, to avoid starting | ||
75 | * a key exchange with a bad mechanism | ||
76 | */ | ||
77 | |||
78 | char * | ||
79 | ssh_gssapi_client_mechanisms(const char *host) { | ||
80 | gss_OID_set gss_supported; | ||
81 | OM_uint32 min_status; | ||
82 | |||
83 | gss_indicate_mechs(&min_status, &gss_supported); | ||
84 | |||
85 | return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, | ||
86 | host)); | ||
87 | } | ||
88 | |||
89 | char * | ||
90 | ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | ||
91 | const char *data) { | ||
92 | Buffer buf; | ||
93 | size_t i; | ||
94 | int oidpos, enclen; | ||
95 | char *mechs, *encoded; | ||
96 | u_char digest[EVP_MAX_MD_SIZE]; | ||
97 | char deroid[2]; | ||
98 | const EVP_MD *evp_md = EVP_md5(); | ||
99 | EVP_MD_CTX md; | ||
100 | |||
101 | if (gss_enc2oid != NULL) { | ||
102 | for (i = 0; gss_enc2oid[i].encoded != NULL; i++) | ||
103 | xfree(gss_enc2oid[i].encoded); | ||
104 | xfree(gss_enc2oid); | ||
105 | } | ||
106 | |||
107 | gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * | ||
108 | (gss_supported->count + 1)); | ||
109 | |||
110 | buffer_init(&buf); | ||
111 | |||
112 | oidpos = 0; | ||
113 | for (i = 0; i < gss_supported->count; i++) { | ||
114 | if (gss_supported->elements[i].length < 128 && | ||
115 | (*check)(NULL, &(gss_supported->elements[i]), data)) { | ||
116 | |||
117 | deroid[0] = SSH_GSS_OIDTYPE; | ||
118 | deroid[1] = gss_supported->elements[i].length; | ||
119 | |||
120 | EVP_DigestInit(&md, evp_md); | ||
121 | EVP_DigestUpdate(&md, deroid, 2); | ||
122 | EVP_DigestUpdate(&md, | ||
123 | gss_supported->elements[i].elements, | ||
124 | gss_supported->elements[i].length); | ||
125 | EVP_DigestFinal(&md, digest, NULL); | ||
126 | |||
127 | encoded = xmalloc(EVP_MD_size(evp_md) * 2); | ||
128 | enclen = __b64_ntop(digest, EVP_MD_size(evp_md), | ||
129 | encoded, EVP_MD_size(evp_md) * 2); | ||
130 | |||
131 | if (oidpos != 0) | ||
132 | buffer_put_char(&buf, ','); | ||
133 | |||
134 | buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, | ||
135 | sizeof(KEX_GSS_GEX_SHA1_ID) - 1); | ||
136 | buffer_append(&buf, encoded, enclen); | ||
137 | buffer_put_char(&buf, ','); | ||
138 | buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, | ||
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); | ||
144 | buffer_append(&buf, encoded, enclen); | ||
145 | |||
146 | gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); | ||
147 | gss_enc2oid[oidpos].encoded = encoded; | ||
148 | oidpos++; | ||
149 | } | ||
150 | } | ||
151 | gss_enc2oid[oidpos].oid = NULL; | ||
152 | gss_enc2oid[oidpos].encoded = NULL; | ||
153 | |||
154 | buffer_put_char(&buf, '\0'); | ||
155 | |||
156 | mechs = xmalloc(buffer_len(&buf)); | ||
157 | buffer_get(&buf, mechs, buffer_len(&buf)); | ||
158 | buffer_free(&buf); | ||
159 | |||
160 | if (strlen(mechs) == 0) { | ||
161 | xfree(mechs); | ||
162 | mechs = NULL; | ||
163 | } | ||
164 | |||
165 | return (mechs); | ||
166 | } | ||
167 | |||
168 | gss_OID | ||
169 | ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { | ||
170 | int i = 0; | ||
171 | |||
172 | switch (kex_type) { | ||
173 | case KEX_GSS_GRP1_SHA1: | ||
174 | name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; | ||
175 | break; | ||
176 | case KEX_GSS_GRP14_SHA1: | ||
177 | name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; | ||
178 | break; | ||
179 | case KEX_GSS_GEX_SHA1: | ||
180 | name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; | ||
181 | break; | ||
182 | default: | ||
183 | return GSS_C_NO_OID; | ||
184 | } | ||
185 | |||
186 | while (gss_enc2oid[i].encoded != NULL && | ||
187 | strcmp(name, gss_enc2oid[i].encoded) != 0) | ||
188 | i++; | ||
189 | |||
190 | if (gss_enc2oid[i].oid != NULL && ctx != NULL) | ||
191 | ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); | ||
192 | |||
193 | return gss_enc2oid[i].oid; | ||
194 | } | ||
195 | |||
48 | /* Check that the OID in a data stream matches that in the context */ | 196 | /* Check that the OID in a data stream matches that in the context */ |
49 | int | 197 | int |
50 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) | 198 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) |
@@ -229,6 +377,9 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) | |||
229 | OM_uint32 | 377 | OM_uint32 |
230 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | 378 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) |
231 | { | 379 | { |
380 | if (ctx == NULL) | ||
381 | return -1; | ||
382 | |||
232 | if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, | 383 | if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, |
233 | GSS_C_QOP_DEFAULT, buffer, hash))) | 384 | GSS_C_QOP_DEFAULT, buffer, hash))) |
234 | ssh_gssapi_error(ctx); | 385 | ssh_gssapi_error(ctx); |
@@ -236,6 +387,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | |||
236 | return (ctx->major); | 387 | return (ctx->major); |
237 | } | 388 | } |
238 | 389 | ||
390 | /* Priviledged when used by server */ | ||
391 | OM_uint32 | ||
392 | ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
393 | { | ||
394 | if (ctx == NULL) | ||
395 | return -1; | ||
396 | |||
397 | ctx->major = gss_verify_mic(&ctx->minor, ctx->context, | ||
398 | gssbuf, gssmic, NULL); | ||
399 | |||
400 | return (ctx->major); | ||
401 | } | ||
402 | |||
239 | void | 403 | void |
240 | ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, | 404 | ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, |
241 | const char *context) | 405 | const char *context) |
@@ -254,6 +418,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | |||
254 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; | 418 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; |
255 | OM_uint32 major, minor; | 419 | OM_uint32 major, minor; |
256 | gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; | 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; | ||
257 | 425 | ||
258 | /* RFC 4462 says we MUST NOT do SPNEGO */ | 426 | /* RFC 4462 says we MUST NOT do SPNEGO */ |
259 | if (oid->length == spnego_oid.length && | 427 | if (oid->length == spnego_oid.length && |
@@ -272,7 +440,7 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | |||
272 | GSS_C_NO_BUFFER); | 440 | GSS_C_NO_BUFFER); |
273 | } | 441 | } |
274 | 442 | ||
275 | if (GSS_ERROR(major)) | 443 | if (GSS_ERROR(major) || intctx != NULL) |
276 | ssh_gssapi_delete_ctx(ctx); | 444 | ssh_gssapi_delete_ctx(ctx); |
277 | 445 | ||
278 | return (!GSS_ERROR(major)); | 446 | return (!GSS_ERROR(major)); |