1 /* $NetBSD: gssapi_link.c,v 1.8 2014/12/10 04:37:58 christos Exp $ */
4 * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Id: gssapi_link.c,v 1.17 2011/03/28 05:32:16 marka Exp
28 #include <isc/base64.h>
29 #include <isc/buffer.h>
31 #include <isc/string.h>
34 #include <dst/result.h>
36 #include "dst_internal.h"
37 #include "dst_parse.h"
39 #include <dst/gssapi.h>
41 #define INITIAL_BUFFER_SIZE 1024
42 #define BUFFER_EXTRA 1024
44 #define REGION_TO_GBUFFER(r, gb) \
46 (gb).length = (r).length; \
47 (gb).value = (r).base; \
48 } while (/*CONSTCOND*/0)
50 #define GBUFFER_TO_REGION(gb, r) \
52 (r).length = (unsigned int)(gb).length; \
53 (r).base = (gb).value; \
54 } while (/*CONSTCOND*/0)
57 struct dst_gssapi_signverifyctx
{
62 * Allocate a temporary "context" for use in gathering data for signing
66 gssapi_create_signverify_ctx(dst_key_t
*key
, dst_context_t
*dctx
) {
67 dst_gssapi_signverifyctx_t
*ctx
;
72 ctx
= isc_mem_get(dctx
->mctx
, sizeof(dst_gssapi_signverifyctx_t
));
74 return (ISC_R_NOMEMORY
);
76 result
= isc_buffer_allocate(dctx
->mctx
, &ctx
->buffer
,
78 if (result
!= ISC_R_SUCCESS
) {
79 isc_mem_put(dctx
->mctx
, ctx
, sizeof(dst_gssapi_signverifyctx_t
));
83 dctx
->ctxdata
.gssctx
= ctx
;
85 return (ISC_R_SUCCESS
);
89 * Destroy the temporary sign/verify context.
92 gssapi_destroy_signverify_ctx(dst_context_t
*dctx
) {
93 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
96 if (ctx
->buffer
!= NULL
)
97 isc_buffer_free(&ctx
->buffer
);
98 isc_mem_put(dctx
->mctx
, ctx
, sizeof(dst_gssapi_signverifyctx_t
));
99 dctx
->ctxdata
.gssctx
= NULL
;
104 * Add data to our running buffer of data we will be signing or verifying.
105 * This code will see if the new data will fit in our existing buffer, and
106 * copy it in if it will. If not, it will attempt to allocate a larger
107 * buffer and copy old+new into it, and free the old buffer.
110 gssapi_adddata(dst_context_t
*dctx
, const isc_region_t
*data
) {
111 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
112 isc_buffer_t
*newbuffer
= NULL
;
117 result
= isc_buffer_copyregion(ctx
->buffer
, data
);
118 if (result
== ISC_R_SUCCESS
)
119 return (ISC_R_SUCCESS
);
121 length
= isc_buffer_length(ctx
->buffer
) + data
->length
+ BUFFER_EXTRA
;
123 result
= isc_buffer_allocate(dctx
->mctx
, &newbuffer
, length
);
124 if (result
!= ISC_R_SUCCESS
)
127 isc_buffer_usedregion(ctx
->buffer
, &r
);
128 (void)isc_buffer_copyregion(newbuffer
, &r
);
129 (void)isc_buffer_copyregion(newbuffer
, data
);
131 isc_buffer_free(&ctx
->buffer
);
132 ctx
->buffer
= newbuffer
;
134 return (ISC_R_SUCCESS
);
141 gssapi_sign(dst_context_t
*dctx
, isc_buffer_t
*sig
) {
142 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
143 isc_region_t message
;
144 gss_buffer_desc gmessage
, gsig
;
145 OM_uint32 minor
, gret
;
146 gss_ctx_id_t gssctx
= dctx
->key
->keydata
.gssctx
;
150 * Convert the data we wish to sign into a structure gssapi can
153 isc_buffer_usedregion(ctx
->buffer
, &message
);
154 REGION_TO_GBUFFER(message
, gmessage
);
157 * Generate the signature.
159 gret
= gss_get_mic(&minor
, gssctx
, GSS_C_QOP_DEFAULT
, &gmessage
,
163 * If it did not complete, we log the result and return a generic
166 if (gret
!= GSS_S_COMPLETE
) {
167 gss_log(3, "GSS sign error: %s",
168 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
169 return (ISC_R_FAILURE
);
173 * If it will not fit in our allocated buffer, return that we need
176 if (gsig
.length
> isc_buffer_availablelength(sig
)) {
177 gss_release_buffer(&minor
, &gsig
);
178 return (ISC_R_NOSPACE
);
182 * Copy the output into our buffer space, and release the gssapi
185 isc_buffer_putmem(sig
, gsig
.value
, (unsigned int)gsig
.length
);
186 if (gsig
.length
!= 0U)
187 gss_release_buffer(&minor
, &gsig
);
189 return (ISC_R_SUCCESS
);
196 gssapi_verify(dst_context_t
*dctx
, const isc_region_t
*sig
) {
197 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
198 isc_region_t message
, r
;
199 gss_buffer_desc gmessage
, gsig
;
200 OM_uint32 minor
, gret
;
201 gss_ctx_id_t gssctx
= dctx
->key
->keydata
.gssctx
;
206 * Convert the data we wish to sign into a structure gssapi can
209 isc_buffer_usedregion(ctx
->buffer
, &message
);
210 REGION_TO_GBUFFER(message
, gmessage
);
214 * It seem that gss_verify_mic() modifies the signature buffer,
215 * at least on Heimdal's implementation. Copy it here to an allocated
218 buf
= isc_mem_allocate(dst__memory_pool
, sig
->length
);
220 return (ISC_R_FAILURE
);
221 memmove(buf
, sig
->base
, sig
->length
);
223 r
.length
= sig
->length
;
224 REGION_TO_GBUFFER(r
, gsig
);
229 gret
= gss_verify_mic(&minor
, gssctx
, &gmessage
, &gsig
, NULL
);
231 isc_mem_free(dst__memory_pool
, buf
);
234 * Convert return codes into something useful to us.
236 if (gret
!= GSS_S_COMPLETE
) {
237 gss_log(3, "GSS verify error: %s",
238 gss_error_tostring(gret
, minor
, err
, sizeof(err
)));
239 if (gret
== GSS_S_DEFECTIVE_TOKEN
||
240 gret
== GSS_S_BAD_SIG
||
241 gret
== GSS_S_DUPLICATE_TOKEN
||
242 gret
== GSS_S_OLD_TOKEN
||
243 gret
== GSS_S_UNSEQ_TOKEN
||
244 gret
== GSS_S_GAP_TOKEN
||
245 gret
== GSS_S_CONTEXT_EXPIRED
||
246 gret
== GSS_S_NO_CONTEXT
||
247 gret
== GSS_S_FAILURE
)
248 return(DST_R_VERIFYFAILURE
);
250 return (ISC_R_FAILURE
);
253 return (ISC_R_SUCCESS
);
257 gssapi_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
258 gss_ctx_id_t gsskey1
= key1
->keydata
.gssctx
;
259 gss_ctx_id_t gsskey2
= key2
->keydata
.gssctx
;
262 return (ISC_TF(gsskey1
== gsskey2
));
266 gssapi_generate(dst_key_t
*key
, int unused
, void (*callback
)(int)) {
272 return (ISC_R_FAILURE
);
276 gssapi_isprivate(const dst_key_t
*key
) {
282 gssapi_destroy(dst_key_t
*key
) {
283 REQUIRE(key
!= NULL
);
284 dst_gssapi_deletectx(key
->mctx
, &key
->keydata
.gssctx
);
285 key
->keydata
.gssctx
= NULL
;
289 gssapi_restore(dst_key_t
*key
, const char *keystr
) {
290 OM_uint32 major
, minor
;
292 isc_buffer_t
*b
= NULL
;
294 gss_buffer_desc gssbuffer
;
297 len
= strlen(keystr
);
299 return (ISC_R_BADBASE64
);
303 result
= isc_buffer_allocate(key
->mctx
, &b
, len
);
304 if (result
!= ISC_R_SUCCESS
)
307 result
= isc_base64_decodestring(keystr
, b
);
308 if (result
!= ISC_R_SUCCESS
) {
313 isc_buffer_remainingregion(b
, &r
);
314 REGION_TO_GBUFFER(r
, gssbuffer
);
315 major
= gss_import_sec_context(&minor
, &gssbuffer
,
316 &key
->keydata
.gssctx
);
317 if (major
!= GSS_S_COMPLETE
) {
319 return (ISC_R_FAILURE
);
323 return (ISC_R_SUCCESS
);
327 gssapi_dump(dst_key_t
*key
, isc_mem_t
*mctx
, char **buffer
, int *length
) {
328 OM_uint32 major
, minor
;
329 gss_buffer_desc gssbuffer
;
336 major
= gss_export_sec_context(&minor
, &key
->keydata
.gssctx
,
338 if (major
!= GSS_S_COMPLETE
) {
339 fprintf(stderr
, "gss_export_sec_context -> %d, %d\n",
341 return (ISC_R_FAILURE
);
343 if (gssbuffer
.length
== 0U)
344 return (ISC_R_FAILURE
);
345 len
= ((gssbuffer
.length
+ 2)/3) * 4;
346 buf
= isc_mem_get(mctx
, len
);
348 gss_release_buffer(&minor
, &gssbuffer
);
349 return (ISC_R_NOMEMORY
);
351 isc_buffer_init(&b
, buf
, (unsigned int)len
);
352 GBUFFER_TO_REGION(gssbuffer
, r
);
353 result
= isc_base64_totext(&r
, 0, "", &b
);
354 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
355 gss_release_buffer(&minor
, &gssbuffer
);
358 return (ISC_R_SUCCESS
);
361 static dst_func_t gssapi_functions
= {
362 gssapi_create_signverify_ctx
,
363 NULL
, /*%< createctx2 */
364 gssapi_destroy_signverify_ctx
,
368 NULL
, /*%< verify2 */
369 NULL
, /*%< computesecret */
371 NULL
, /*%< paramcompare */
376 NULL
, /*%< fromdns */
379 NULL
, /*%< cleanup */
380 NULL
, /*%< fromlabel */
386 dst__gssapi_init(dst_func_t
**funcp
) {
387 REQUIRE(funcp
!= NULL
);
389 *funcp
= &gssapi_functions
;
390 return (ISC_R_SUCCESS
);
394 int gssapi_link_unneeded
= 1;