/* Copyright (C) 2013 Simo Sorce This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include #include #include #include #include "gssapi_ntlmssp.h" #include "gss_ntlmssp.h" uint32_t gssntlm_get_mic(uint32_t *minor_status, gss_ctx_id_t context_handle, gss_qop_t qop_req, gss_buffer_t message_buffer, gss_buffer_t message_token) { struct gssntlm_ctx *ctx; struct ntlm_buffer message; struct ntlm_buffer signature; uint32_t retmaj, retmin; *minor_status = 0; ctx = (struct gssntlm_ctx *)context_handle; retmaj = gssntlm_context_is_valid(ctx, NULL); if (retmaj != GSS_S_COMPLETE) { return retmaj; } if (qop_req != GSS_C_QOP_DEFAULT) { return GSS_S_BAD_QOP; } if (!message_buffer->value || message_buffer->length == 0) { return GSS_S_CALL_INACCESSIBLE_READ; } message_token->value = malloc(NTLM_SIGNATURE_SIZE); if (!message_token->value) { *minor_status = ENOMEM; return GSS_S_FAILURE; } message_token->length = NTLM_SIGNATURE_SIZE; message.data = message_buffer->value; message.length = message_buffer->length; signature.data = message_token->value; signature.length = message_token->length; retmin = ntlm_sign(ctx->neg_flags, NTLM_SEND, &ctx->crypto_state, &message, &signature); if (retmin) { *minor_status = retmin; safefree(message_token->value); return GSS_S_FAILURE; } return GSS_S_COMPLETE; } uint32_t gssntlm_verify_mic(uint32_t *minor_status, gss_ctx_id_t context_handle, gss_buffer_t message_buffer, gss_buffer_t message_token, gss_qop_t *qop_state) { struct gssntlm_ctx *ctx; struct ntlm_buffer message; uint8_t token[16]; struct ntlm_buffer signature = { token, NTLM_SIGNATURE_SIZE }; uint32_t retmaj, retmin; *minor_status = 0; ctx = (struct gssntlm_ctx *)context_handle; retmaj = gssntlm_context_is_valid(ctx, NULL); if (retmaj != GSS_S_COMPLETE) { return retmaj; } if (!message_buffer->value || message_buffer->length == 0) { return GSS_S_CALL_INACCESSIBLE_READ; } if (qop_state) { *qop_state = GSS_C_QOP_DEFAULT; } message.data = message_buffer->value; message.length = message_buffer->length; retmin = ntlm_sign(ctx->neg_flags, NTLM_RECV, &ctx->crypto_state, &message, &signature); if (retmin) { *minor_status = retmin; return GSS_S_FAILURE; } if (memcmp(signature.data, message_token->value, NTLM_SIGNATURE_SIZE) != 0) { return GSS_S_BAD_SIG; } return GSS_S_COMPLETE; } uint32_t gssntlm_wrap(uint32_t *minor_status, gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer) { struct gssntlm_ctx *ctx; struct ntlm_buffer message; struct ntlm_buffer output; struct ntlm_buffer signature; uint32_t retmaj, retmin; *minor_status = 0; ctx = (struct gssntlm_ctx *)context_handle; retmaj = gssntlm_context_is_valid(ctx, NULL); if (retmaj != GSS_S_COMPLETE) { return retmaj; } if (qop_req != GSS_C_QOP_DEFAULT) { return GSS_S_BAD_QOP; } if (!input_message_buffer->value || input_message_buffer->length == 0) { return GSS_S_CALL_INACCESSIBLE_READ; } if (conf_state) { *conf_state = 0; } if (conf_req_flag == 0) { /* ignore, always seal */ } output_message_buffer->length = input_message_buffer->length + NTLM_SIGNATURE_SIZE; output_message_buffer->value = malloc(output_message_buffer->length); if (!output_message_buffer->value) { *minor_status = ENOMEM; return GSS_S_FAILURE; } message.data = input_message_buffer->value; message.length = input_message_buffer->length; signature.data = output_message_buffer->value; signature.length = NTLM_SIGNATURE_SIZE; output.data = (uint8_t *)output_message_buffer->value + NTLM_SIGNATURE_SIZE; output.length = input_message_buffer->length; retmin = ntlm_seal(ctx->neg_flags, &ctx->crypto_state, &message, &output, &signature); if (retmin) { *minor_status = retmin; safefree(output_message_buffer->value); return GSS_S_FAILURE; } return GSS_S_COMPLETE; } uint32_t gssntlm_unwrap(uint32_t *minor_status, gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, gss_qop_t *qop_state) { struct gssntlm_ctx *ctx; struct ntlm_buffer message; struct ntlm_buffer output; uint8_t sig[16]; struct ntlm_buffer signature = { sig, NTLM_SIGNATURE_SIZE }; uint32_t retmaj, retmin; *minor_status = 0; ctx = (struct gssntlm_ctx *)context_handle; retmaj = gssntlm_context_is_valid(ctx, NULL); if (retmaj != GSS_S_COMPLETE) { return retmaj; } if (!input_message_buffer->value || input_message_buffer->length == 0) { return GSS_S_CALL_INACCESSIBLE_READ; } if (conf_state) { *conf_state = 0; } if (qop_state) { *qop_state = GSS_C_QOP_DEFAULT; } output_message_buffer->length = input_message_buffer->length - NTLM_SIGNATURE_SIZE; output_message_buffer->value = malloc(output_message_buffer->length); if (!output_message_buffer->value) { *minor_status = ENOMEM; return GSS_S_FAILURE; } message.data = (uint8_t *)input_message_buffer->value + NTLM_SIGNATURE_SIZE; message.length = input_message_buffer->length - NTLM_SIGNATURE_SIZE; output.data = output_message_buffer->value; output.length = output_message_buffer->length; retmin = ntlm_unseal(ctx->neg_flags, &ctx->crypto_state, &message, &output, &signature); if (retmin) { *minor_status = retmin; safefree(output_message_buffer->value); return GSS_S_FAILURE; } if (memcmp(input_message_buffer->value, signature.data, NTLM_SIGNATURE_SIZE) != 0) { safefree(output_message_buffer->value); return GSS_S_BAD_SIG; } return GSS_S_COMPLETE; } uint32_t gssntlm_wrap_size_limit(uint32_t *minor_status, gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, uint32_t req_output_size, uint32_t *max_input_size) { struct gssntlm_ctx *ctx; uint32_t retmaj; *minor_status = 0; ctx = (struct gssntlm_ctx *)context_handle; retmaj = gssntlm_context_is_valid(ctx, NULL); if (retmaj != GSS_S_COMPLETE) { return retmaj; } if (qop_req != GSS_C_QOP_DEFAULT) { return GSS_S_BAD_QOP; } if (req_output_size < 16) { *max_input_size = 0; } else { *max_input_size = req_output_size - NTLM_SIGNATURE_SIZE; } return GSS_S_COMPLETE; }