context.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/note.h>
#include "dh_gssapi.h"
/*
* This module contains the implementation of the gssapi context support
* routines for the Diffie-Hellman mechanism.
*
* The GSS routines that are supported by this module are:
* gss_context_time
* gss_delete_sec_context
* gss_inquire_context
* gss_wrap_size_limit
*
* The following routines are not supported for the Diffie-Hellman
* Mechanism at this time.
* gss_export_sec_context
* gss_import_sec_context
*
* The following routine is not supported since it is obsolete in version 2
* of the GSS-API.
* gss_process_context_token.
*
* Note that support for gss_init_sec_context and gss_accept_sec_context is
* found in context_establish.c
*/
OM_uint32
__dh_gss_context_time(void *ctx, /* Mechanism context (not used) */
OM_uint32 * minor, /* GSS minor status */
gss_ctx_id_t context, /* GSS context handle */
OM_uint32* time_remaining /* Time remaining */)
{
_NOTE(ARGUNUSED(ctx))
/* Context is a dh context */
dh_gss_context_t cntx = (dh_gss_context_t)context;
time_t now = time(0);
if (minor == 0)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
if (time_remaining == 0)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
/* Validate context */
if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
return (GSS_S_NO_CONTEXT);
/* See if it is always valid */
if (cntx->expire == (time_t)GSS_C_INDEFINITE) {
*time_remaining = GSS_C_INDEFINITE;
return (GSS_S_COMPLETE);
}
/* Calculate the remainning time */
*time_remaining = (now < cntx->expire) ? cntx->expire - now : 0;
/* Return expired if there is no time left */
return (*time_remaining ? GSS_S_COMPLETE : GSS_S_CONTEXT_EXPIRED);
}
/*
* Delete a Diffie-Hellman context that is pointed to by context.
* On a successfull return *context will be NULL.
*/
OM_uint32
__dh_gss_delete_sec_context(void *ctx, /* Mechanism context */
OM_uint32 *minor, /* Mechanism status */
gss_ctx_id_t *context, /* GSS context */
gss_buffer_t token /* GSS token */)
{
_NOTE(ARGUNUSED(ctx))
dh_gss_context_t cntx;
if (context == 0)
return (GSS_S_CALL_INACCESSIBLE_READ |
GSS_S_CALL_INACCESSIBLE_WRITE);
/* context is a Diffie-Hellman context */
cntx = (dh_gss_context_t)*context;
if (minor == 0)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
/*
* If token then set the length to zero value to zero to indicate
* We indicat a null token since we don't need to send a token to
* the other side.
*/
if (token) {
token->length = 0;
token->value = NULL;
}
/* Deleting a null context is OK */
if (cntx == NULL)
return (GSS_S_COMPLETE);
/* Validate the context */
if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
return (GSS_S_NO_CONTEXT);
/* Zero out the session keys! */
memset(cntx->keys, 0, cntx->no_keys * sizeof (des_block));
/* Unregister the context */
*minor = __dh_remove_context(cntx);
/* Free storage */
__dh_destroy_seq_hist(cntx);
free(cntx->remote);
free(cntx->local);
Free(cntx->keys);
Free(cntx);
/* Set context to NULL */
*context = NULL;
return (GSS_S_COMPLETE);
}
/*
* Diffie-Hellman mechanism currently does not support exporting and importing
* gss contexts.
*/
OM_uint32
/*ARGSUSED*/
__dh_gss_export_sec_context(void *ctx, OM_uint32 *minor,
gss_ctx_id_t *context, gss_buffer_t token)
{
return (GSS_S_UNAVAILABLE);
}
OM_uint32
/*ARGSUSED*/
__dh_gss_import_sec_context(void * ctx, OM_uint32 *minor,
gss_buffer_t token, gss_ctx_id_t *context)
{
return (GSS_S_UNAVAILABLE);
}
/*
* Get the state of a Diffie-Hellman context
*/
OM_uint32
__dh_gss_inquire_context(void *ctx, /* Mechanism context */
OM_uint32 *minor, /* Mechanism status */
gss_ctx_id_t context, /* GSS context */
gss_name_t *initiator, /* Name of initiator */
gss_name_t *acceptor, /* Name of acceptor */
OM_uint32 *time_rec, /* Amount of time left */
gss_OID *mech, /* return OID of mechanism */
OM_uint32 *flags_rec, /* flags set on context */
int *local, /* True if we're the initiator */
int *open /* True if the context is established */)
{
dh_gss_context_t cntx;
OM_uint32 stat = GSS_S_COMPLETE;
OM_uint32 t;
/* context is a Diffie-Hellman */
cntx = (dh_gss_context_t)context;
/* Validate the context */
if ((*minor = __dh_validate_context(cntx)) != DH_SUCCESS)
return (GSS_S_NO_CONTEXT);
/* If the caller wants the mechanism OID set *mech to if we can */
if (mech) {
if (ctx == 0) {
*mech = GSS_C_NO_OID;
return (GSS_S_CALL_INACCESSIBLE_READ);
}
else
*mech = ((dh_context_t)ctx)->mech;
}
/* set t to be the time left on the context */
if (cntx->expire == GSS_C_INDEFINITE)
t = GSS_C_INDEFINITE;
else {
time_t now = time(0);
t = now > cntx->expire ? 0 : (OM_uint32)(cntx->expire - now);
}
/* If the caller wants the initiator set *initiator to it. */
if (initiator) {
dh_principal p = cntx->initiate ? cntx->local : cntx->remote;
*initiator = (gss_name_t)strdup(p);
}
/* If the callers wants the acceptor set *acceptor to it. */
if (acceptor) {
dh_principal p = cntx->initiate ? cntx->remote : cntx->local;
*acceptor = (gss_name_t)strdup(p);
}
/* If the caller wants the time remaining set *time_rec to t */
if (time_rec)
*time_rec = t;
/* Return the flags in flags_rec if set */
if (flags_rec)
*flags_rec = cntx->flags;
/* ditto for local */
if (local)
*local = cntx->initiate;
/* ditto for open */
if (open)
*open = (cntx->state == ESTABLISHED);
/* return GSS_S_CONTEXT_EXPIRED if no time is left on the context */
return ((t == 0 ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE) | stat);
}
/*
* __dh_gss_process_context_token.
* This routine is not implemented. It is depricated in version 2.
*/
OM_uint32
/*ARGSUSED*/
__dh_gss_process_context_token(void *ctx, OM_uint32 *minor,
gss_ctx_id_t context, gss_buffer_t token)
{
return (GSS_S_UNAVAILABLE);
}
/*
* This implements the gss_wrap_size_limit entry point for Diffie-Hellman
* mechanism. See RFC 2078 for details. The idea here is for a context,
* qop, whether confidentiality is specified, and an output size, return
* the maximum input size that will fit in the given output size. Typically
* the output size would be the MTU of the higher level protocol using the
* GSS-API.
*/
OM_uint32
__dh_gss_wrap_size_limit(void *ctx, /* Mechanism context (not used) */
OM_uint32 *minor, /* Mechanism status */
gss_ctx_id_t context, /* GSS context handle */
int conf_req, /* True if confidentiality is wanted */
gss_qop_t qop_req, /* Requested QOP */
OM_uint32 output_size, /* The maximum ouput size */
OM_uint32 *input_size /* Input size returned */)
{
_NOTE(ARGUNUSED(ctx))
OM_uint32 major, stat = GSS_S_COMPLETE;
unsigned int msgsize, sigsize, pad = 1, size;
dh_token_desc token;
dh_wrap_t wrap = &token.ver.dh_version_u.body.dh_token_body_desc_u.seal;
OM_uint32 left;
if (input_size == 0)
stat = GSS_S_CALL_INACCESSIBLE_WRITE;
/* We check for valid unexpired context by calling gss_context_time. */
if ((major = stat | __dh_gss_context_time(ctx, minor, context, &left))
!= GSS_S_COMPLETE)
return (major | stat);
/* Find the signature size for this qop. */
if ((*minor = __get_sig_size(qop_req, &sigsize)) != DH_SUCCESS)
return (GSS_S_BAD_QOP | stat);
/* Just return if we can't give the caller what he ask for. */
if (stat)
return (stat);
/*
* If we requested confidentiality, get the cipher pad for the
* requested qop. Since we can't support privacy the cipher pad
* is always 1.
*/
if (conf_req)
pad = 1;
/*
* Set up an empty wrap token to calculate header and signature
* overhead.
*/
token.ver.verno = DH_PROTO_VERSION;
token.ver.dh_version_u.body.type = DH_WRAP;
wrap->mic.qop = qop_req;
wrap->mic.seqnum = 0;
wrap->mic.client_flag = 0;
wrap->body.body_len = 0;
wrap->body.body_val = 0;
token.verifier.dh_signature_len = sigsize;
token.verifier.dh_signature_val = 0;
/* This is the size of an empy wrap token */
size = xdr_sizeof((xdrproc_t)xdr_dh_token_desc, (void *)&token);
/* This is the amount of space left to put our message. */
msgsize = (output_size > size) ? output_size - size : 0;
/* XDR needs to pad to a four byte boundry */
msgsize = (msgsize / 4) * 4;
/* We need to pad to pad bytes for encryption (=1 if conf_req = 0) */
msgsize = (msgsize / pad) * pad;
/*
* The serialization of the inner message includes
* the original length.
*/
msgsize = (msgsize > sizeof (uint_t)) ? msgsize - sizeof (uint_t) : 0;
/*
* We now have the space for the inner wrap message, which is also
* XDR encoded and is padded to a four byte boundry.
*/
msgsize = (msgsize / 4) * 4;
*input_size = msgsize;
return (GSS_S_COMPLETE);
}