/contrib/bind9/lib/dns/gssapi_link.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 393 lines · 258 code · 59 blank · 76 comment · 53 complexity · 5086e8ccfbd7f74cf1a9e8d4e3530535 MD5 · raw file

  1. /*
  2. * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 2000-2002 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /*
  18. * $Id$
  19. */
  20. #include <config.h>
  21. #ifdef GSSAPI
  22. #include <isc/base64.h>
  23. #include <isc/buffer.h>
  24. #include <isc/mem.h>
  25. #include <isc/string.h>
  26. #include <isc/util.h>
  27. #include <dst/result.h>
  28. #include "dst_internal.h"
  29. #include "dst_parse.h"
  30. #include <dst/gssapi.h>
  31. #define INITIAL_BUFFER_SIZE 1024
  32. #define BUFFER_EXTRA 1024
  33. #define REGION_TO_GBUFFER(r, gb) \
  34. do { \
  35. (gb).length = (r).length; \
  36. (gb).value = (r).base; \
  37. } while (0)
  38. #define GBUFFER_TO_REGION(gb, r) \
  39. do { \
  40. (r).length = (gb).length; \
  41. (r).base = (gb).value; \
  42. } while (0)
  43. struct dst_gssapi_signverifyctx {
  44. isc_buffer_t *buffer;
  45. };
  46. /*%
  47. * Allocate a temporary "context" for use in gathering data for signing
  48. * or verifying.
  49. */
  50. static isc_result_t
  51. gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
  52. dst_gssapi_signverifyctx_t *ctx;
  53. isc_result_t result;
  54. UNUSED(key);
  55. ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
  56. if (ctx == NULL)
  57. return (ISC_R_NOMEMORY);
  58. ctx->buffer = NULL;
  59. result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
  60. INITIAL_BUFFER_SIZE);
  61. if (result != ISC_R_SUCCESS) {
  62. isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
  63. return (result);
  64. }
  65. dctx->ctxdata.gssctx = ctx;
  66. return (ISC_R_SUCCESS);
  67. }
  68. /*%
  69. * Destroy the temporary sign/verify context.
  70. */
  71. static void
  72. gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
  73. dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
  74. if (ctx != NULL) {
  75. if (ctx->buffer != NULL)
  76. isc_buffer_free(&ctx->buffer);
  77. isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
  78. dctx->ctxdata.gssctx = NULL;
  79. }
  80. }
  81. /*%
  82. * Add data to our running buffer of data we will be signing or verifying.
  83. * This code will see if the new data will fit in our existing buffer, and
  84. * copy it in if it will. If not, it will attempt to allocate a larger
  85. * buffer and copy old+new into it, and free the old buffer.
  86. */
  87. static isc_result_t
  88. gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
  89. dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
  90. isc_buffer_t *newbuffer = NULL;
  91. isc_region_t r;
  92. unsigned int length;
  93. isc_result_t result;
  94. result = isc_buffer_copyregion(ctx->buffer, data);
  95. if (result == ISC_R_SUCCESS)
  96. return (ISC_R_SUCCESS);
  97. length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
  98. result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
  99. if (result != ISC_R_SUCCESS)
  100. return (result);
  101. isc_buffer_usedregion(ctx->buffer, &r);
  102. (void)isc_buffer_copyregion(newbuffer, &r);
  103. (void)isc_buffer_copyregion(newbuffer, data);
  104. isc_buffer_free(&ctx->buffer);
  105. ctx->buffer = newbuffer;
  106. return (ISC_R_SUCCESS);
  107. }
  108. /*%
  109. * Sign.
  110. */
  111. static isc_result_t
  112. gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
  113. dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
  114. isc_region_t message;
  115. gss_buffer_desc gmessage, gsig;
  116. OM_uint32 minor, gret;
  117. gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
  118. char buf[1024];
  119. /*
  120. * Convert the data we wish to sign into a structure gssapi can
  121. * understand.
  122. */
  123. isc_buffer_usedregion(ctx->buffer, &message);
  124. REGION_TO_GBUFFER(message, gmessage);
  125. /*
  126. * Generate the signature.
  127. */
  128. gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
  129. &gsig);
  130. /*
  131. * If it did not complete, we log the result and return a generic
  132. * failure code.
  133. */
  134. if (gret != GSS_S_COMPLETE) {
  135. gss_log(3, "GSS sign error: %s",
  136. gss_error_tostring(gret, minor, buf, sizeof(buf)));
  137. return (ISC_R_FAILURE);
  138. }
  139. /*
  140. * If it will not fit in our allocated buffer, return that we need
  141. * more space.
  142. */
  143. if (gsig.length > isc_buffer_availablelength(sig)) {
  144. gss_release_buffer(&minor, &gsig);
  145. return (ISC_R_NOSPACE);
  146. }
  147. /*
  148. * Copy the output into our buffer space, and release the gssapi
  149. * allocated space.
  150. */
  151. isc_buffer_putmem(sig, gsig.value, gsig.length);
  152. if (gsig.length != 0U)
  153. gss_release_buffer(&minor, &gsig);
  154. return (ISC_R_SUCCESS);
  155. }
  156. /*%
  157. * Verify.
  158. */
  159. static isc_result_t
  160. gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
  161. dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
  162. isc_region_t message, r;
  163. gss_buffer_desc gmessage, gsig;
  164. OM_uint32 minor, gret;
  165. gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
  166. unsigned char *buf;
  167. char err[1024];
  168. /*
  169. * Convert the data we wish to sign into a structure gssapi can
  170. * understand.
  171. */
  172. isc_buffer_usedregion(ctx->buffer, &message);
  173. REGION_TO_GBUFFER(message, gmessage);
  174. /*
  175. * XXXMLG
  176. * It seem that gss_verify_mic() modifies the signature buffer,
  177. * at least on Heimdal's implementation. Copy it here to an allocated
  178. * buffer.
  179. */
  180. buf = isc_mem_allocate(dst__memory_pool, sig->length);
  181. if (buf == NULL)
  182. return (ISC_R_FAILURE);
  183. memcpy(buf, sig->base, sig->length);
  184. r.base = buf;
  185. r.length = sig->length;
  186. REGION_TO_GBUFFER(r, gsig);
  187. /*
  188. * Verify the data.
  189. */
  190. gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
  191. isc_mem_free(dst__memory_pool, buf);
  192. /*
  193. * Convert return codes into something useful to us.
  194. */
  195. if (gret != GSS_S_COMPLETE) {
  196. gss_log(3, "GSS verify error: %s",
  197. gss_error_tostring(gret, minor, err, sizeof(err)));
  198. if (gret == GSS_S_DEFECTIVE_TOKEN ||
  199. gret == GSS_S_BAD_SIG ||
  200. gret == GSS_S_DUPLICATE_TOKEN ||
  201. gret == GSS_S_OLD_TOKEN ||
  202. gret == GSS_S_UNSEQ_TOKEN ||
  203. gret == GSS_S_GAP_TOKEN ||
  204. gret == GSS_S_CONTEXT_EXPIRED ||
  205. gret == GSS_S_NO_CONTEXT ||
  206. gret == GSS_S_FAILURE)
  207. return(DST_R_VERIFYFAILURE);
  208. else
  209. return (ISC_R_FAILURE);
  210. }
  211. return (ISC_R_SUCCESS);
  212. }
  213. static isc_boolean_t
  214. gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
  215. gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
  216. gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
  217. /* No idea */
  218. return (ISC_TF(gsskey1 == gsskey2));
  219. }
  220. static isc_result_t
  221. gssapi_generate(dst_key_t *key, int unused, void (*callback)(int)) {
  222. UNUSED(key);
  223. UNUSED(unused);
  224. UNUSED(callback);
  225. /* No idea */
  226. return (ISC_R_FAILURE);
  227. }
  228. static isc_boolean_t
  229. gssapi_isprivate(const dst_key_t *key) {
  230. UNUSED(key);
  231. return (ISC_TRUE);
  232. }
  233. static void
  234. gssapi_destroy(dst_key_t *key) {
  235. REQUIRE(key != NULL);
  236. dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
  237. key->keydata.gssctx = NULL;
  238. }
  239. static isc_result_t
  240. gssapi_restore(dst_key_t *key, const char *keystr) {
  241. OM_uint32 major, minor;
  242. size_t len;
  243. isc_buffer_t *b = NULL;
  244. isc_region_t r;
  245. gss_buffer_desc gssbuffer;
  246. isc_result_t result;
  247. len = strlen(keystr);
  248. if ((len % 4) != 0U)
  249. return (ISC_R_BADBASE64);
  250. len = (len / 4) * 3;
  251. result = isc_buffer_allocate(key->mctx, &b, len);
  252. if (result != ISC_R_SUCCESS)
  253. return (result);
  254. result = isc_base64_decodestring(keystr, b);
  255. if (result != ISC_R_SUCCESS) {
  256. isc_buffer_free(&b);
  257. return (result);
  258. }
  259. isc_buffer_remainingregion(b, &r);
  260. REGION_TO_GBUFFER(r, gssbuffer);
  261. major = gss_import_sec_context(&minor, &gssbuffer,
  262. &key->keydata.gssctx);
  263. if (major != GSS_S_COMPLETE) {
  264. isc_buffer_free(&b);
  265. return (ISC_R_FAILURE);
  266. }
  267. isc_buffer_free(&b);
  268. return (ISC_R_SUCCESS);
  269. }
  270. static isc_result_t
  271. gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
  272. OM_uint32 major, minor;
  273. gss_buffer_desc gssbuffer;
  274. size_t len;
  275. char *buf;
  276. isc_buffer_t b;
  277. isc_region_t r;
  278. isc_result_t result;
  279. major = gss_export_sec_context(&minor, &key->keydata.gssctx,
  280. &gssbuffer);
  281. if (major != GSS_S_COMPLETE) {
  282. fprintf(stderr, "gss_export_sec_context -> %d, %d\n",
  283. major, minor);
  284. return (ISC_R_FAILURE);
  285. }
  286. if (gssbuffer.length == 0U)
  287. return (ISC_R_FAILURE);
  288. len = ((gssbuffer.length + 2)/3) * 4;
  289. buf = isc_mem_get(mctx, len);
  290. if (buf == NULL) {
  291. gss_release_buffer(&minor, &gssbuffer);
  292. return (ISC_R_NOMEMORY);
  293. }
  294. isc_buffer_init(&b, buf, len);
  295. GBUFFER_TO_REGION(gssbuffer, r);
  296. result = isc_base64_totext(&r, 0, "", &b);
  297. RUNTIME_CHECK(result == ISC_R_SUCCESS);
  298. gss_release_buffer(&minor, &gssbuffer);
  299. *buffer = buf;
  300. *length = len;
  301. return (ISC_R_SUCCESS);
  302. }
  303. static dst_func_t gssapi_functions = {
  304. gssapi_create_signverify_ctx,
  305. gssapi_destroy_signverify_ctx,
  306. gssapi_adddata,
  307. gssapi_sign,
  308. gssapi_verify,
  309. NULL, /*%< computesecret */
  310. gssapi_compare,
  311. NULL, /*%< paramcompare */
  312. gssapi_generate,
  313. gssapi_isprivate,
  314. gssapi_destroy,
  315. NULL, /*%< todns */
  316. NULL, /*%< fromdns */
  317. NULL, /*%< tofile */
  318. NULL, /*%< parse */
  319. NULL, /*%< cleanup */
  320. NULL, /*%< fromlabel */
  321. gssapi_dump,
  322. gssapi_restore,
  323. };
  324. isc_result_t
  325. dst__gssapi_init(dst_func_t **funcp) {
  326. REQUIRE(funcp != NULL);
  327. if (*funcp == NULL)
  328. *funcp = &gssapi_functions;
  329. return (ISC_R_SUCCESS);
  330. }
  331. #else
  332. int gssapi_link_unneeded = 1;
  333. #endif
  334. /*! \file */