4 * Copyright (C) 2004-2009 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.14 2009/10/24 23:47:36 tbox Exp
28 #include <isc/buffer.h>
30 #include <isc/string.h>
33 #include <dst/result.h>
35 #include "dst_internal.h"
36 #include "dst_parse.h"
38 #include <dst/gssapi.h>
40 #define INITIAL_BUFFER_SIZE 1024
41 #define BUFFER_EXTRA 1024
43 #define REGION_TO_GBUFFER(r, gb) \
45 (gb).length = (r).length; \
46 (gb).value = (r).base; \
50 struct dst_gssapi_signverifyctx
{
55 * Allocate a temporary "context" for use in gathering data for signing
59 gssapi_create_signverify_ctx(dst_key_t
*key
, dst_context_t
*dctx
) {
60 dst_gssapi_signverifyctx_t
*ctx
;
65 ctx
= isc_mem_get(dctx
->mctx
, sizeof(dst_gssapi_signverifyctx_t
));
67 return (ISC_R_NOMEMORY
);
69 result
= isc_buffer_allocate(dctx
->mctx
, &ctx
->buffer
,
71 if (result
!= ISC_R_SUCCESS
) {
72 isc_mem_put(dctx
->mctx
, ctx
, sizeof(dst_gssapi_signverifyctx_t
));
76 dctx
->ctxdata
.gssctx
= ctx
;
78 return (ISC_R_SUCCESS
);
82 * Destroy the temporary sign/verify context.
85 gssapi_destroy_signverify_ctx(dst_context_t
*dctx
) {
86 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
89 if (ctx
->buffer
!= NULL
)
90 isc_buffer_free(&ctx
->buffer
);
91 isc_mem_put(dctx
->mctx
, ctx
, sizeof(dst_gssapi_signverifyctx_t
));
92 dctx
->ctxdata
.gssctx
= NULL
;
97 * Add data to our running buffer of data we will be signing or verifying.
98 * This code will see if the new data will fit in our existing buffer, and
99 * copy it in if it will. If not, it will attempt to allocate a larger
100 * buffer and copy old+new into it, and free the old buffer.
103 gssapi_adddata(dst_context_t
*dctx
, const isc_region_t
*data
) {
104 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
105 isc_buffer_t
*newbuffer
= NULL
;
110 result
= isc_buffer_copyregion(ctx
->buffer
, data
);
111 if (result
== ISC_R_SUCCESS
)
112 return (ISC_R_SUCCESS
);
114 length
= isc_buffer_length(ctx
->buffer
) + data
->length
+ BUFFER_EXTRA
;
116 result
= isc_buffer_allocate(dctx
->mctx
, &newbuffer
, length
);
117 if (result
!= ISC_R_SUCCESS
)
120 isc_buffer_usedregion(ctx
->buffer
, &r
);
121 (void)isc_buffer_copyregion(newbuffer
, &r
);
122 (void)isc_buffer_copyregion(newbuffer
, data
);
124 isc_buffer_free(&ctx
->buffer
);
125 ctx
->buffer
= newbuffer
;
127 return (ISC_R_SUCCESS
);
134 gssapi_sign(dst_context_t
*dctx
, isc_buffer_t
*sig
) {
135 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
136 isc_region_t message
;
137 gss_buffer_desc gmessage
, gsig
;
138 OM_uint32 minor
, gret
;
139 gss_ctx_id_t gssctx
= dctx
->key
->keydata
.gssctx
;
143 * Convert the data we wish to sign into a structure gssapi can
146 isc_buffer_usedregion(ctx
->buffer
, &message
);
147 REGION_TO_GBUFFER(message
, gmessage
);
150 * Generate the signature.
152 gret
= gss_get_mic(&minor
, gssctx
, GSS_C_QOP_DEFAULT
, &gmessage
,
156 * If it did not complete, we log the result and return a generic
159 if (gret
!= GSS_S_COMPLETE
) {
160 gss_log(3, "GSS sign error: %s",
161 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
162 return (ISC_R_FAILURE
);
166 * If it will not fit in our allocated buffer, return that we need
169 if (gsig
.length
> isc_buffer_availablelength(sig
)) {
170 gss_release_buffer(&minor
, &gsig
);
171 return (ISC_R_NOSPACE
);
175 * Copy the output into our buffer space, and release the gssapi
178 isc_buffer_putmem(sig
, gsig
.value
, gsig
.length
);
179 if (gsig
.length
!= 0)
180 gss_release_buffer(&minor
, &gsig
);
182 return (ISC_R_SUCCESS
);
189 gssapi_verify(dst_context_t
*dctx
, const isc_region_t
*sig
) {
190 dst_gssapi_signverifyctx_t
*ctx
= dctx
->ctxdata
.gssctx
;
191 isc_region_t message
, r
;
192 gss_buffer_desc gmessage
, gsig
;
193 OM_uint32 minor
, gret
;
194 gss_ctx_id_t gssctx
= dctx
->key
->keydata
.gssctx
;
199 * Convert the data we wish to sign into a structure gssapi can
202 isc_buffer_usedregion(ctx
->buffer
, &message
);
203 REGION_TO_GBUFFER(message
, gmessage
);
207 * It seem that gss_verify_mic() modifies the signature buffer,
208 * at least on Heimdal's implementation. Copy it here to an allocated
211 buf
= isc_mem_allocate(dst__memory_pool
, sig
->length
);
213 return (ISC_R_FAILURE
);
214 memcpy(buf
, sig
->base
, sig
->length
);
216 r
.length
= sig
->length
;
217 REGION_TO_GBUFFER(r
, gsig
);
222 gret
= gss_verify_mic(&minor
, gssctx
, &gmessage
, &gsig
, NULL
);
224 isc_mem_free(dst__memory_pool
, buf
);
227 * Convert return codes into something useful to us.
229 if (gret
!= GSS_S_COMPLETE
) {
230 gss_log(3, "GSS verify error: %s",
231 gss_error_tostring(gret
, minor
, err
, sizeof(err
)));
232 if (gret
== GSS_S_DEFECTIVE_TOKEN
||
233 gret
== GSS_S_BAD_SIG
||
234 gret
== GSS_S_DUPLICATE_TOKEN
||
235 gret
== GSS_S_OLD_TOKEN
||
236 gret
== GSS_S_UNSEQ_TOKEN
||
237 gret
== GSS_S_GAP_TOKEN
||
238 gret
== GSS_S_CONTEXT_EXPIRED
||
239 gret
== GSS_S_NO_CONTEXT
||
240 gret
== GSS_S_FAILURE
)
241 return(DST_R_VERIFYFAILURE
);
243 return (ISC_R_FAILURE
);
246 return (ISC_R_SUCCESS
);
250 gssapi_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
251 gss_ctx_id_t gsskey1
= key1
->keydata
.gssctx
;
252 gss_ctx_id_t gsskey2
= key2
->keydata
.gssctx
;
255 return (ISC_TF(gsskey1
== gsskey2
));
259 gssapi_generate(dst_key_t
*key
, int unused
, void (*callback
)(int)) {
265 return (ISC_R_FAILURE
);
269 gssapi_isprivate(const dst_key_t
*key
) {
275 gssapi_destroy(dst_key_t
*key
) {
276 REQUIRE(key
!= NULL
);
277 dst_gssapi_deletectx(key
->mctx
, &key
->keydata
.gssctx
);
278 key
->keydata
.gssctx
= NULL
;
281 static dst_func_t gssapi_functions
= {
282 gssapi_create_signverify_ctx
,
283 gssapi_destroy_signverify_ctx
,
287 NULL
, /*%< computesecret */
289 NULL
, /*%< paramcompare */
294 NULL
, /*%< fromdns */
297 NULL
, /*%< cleanup */
298 NULL
, /*%< fromlabel */
302 dst__gssapi_init(dst_func_t
**funcp
) {
303 REQUIRE(funcp
!= NULL
);
305 *funcp
= &gssapi_functions
;
306 return (ISC_R_SUCCESS
);
310 int gssapi_link_unneeded
= 1;