/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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
*/
/*
*/
#include <string.h>
#include "dh_gssapi.h"
/*
* The following 2 routines convert a gss_channel_binding to a DH
* channel_binding and vis versa. We can no longer assume a simple
* cast because a GSS buffer_t uses a size_t for the length field wich
* is 64 bits in a 64 bit process. The xdr encoding always assumes the
* length to be 32 bits :<.
*/
static dh_channel_binding_t
{
if (gss_binding == GSS_C_NO_CHANNEL_BINDINGS)
return (NULL);
return (NULL);
return (dh_binding);
}
static gss_channel_bindings_t
{
if (dh_binding == NULL)
return (GSS_C_NO_CHANNEL_BINDINGS);
return (gss_binding);
}
/*
* Routine to compare that two gss_buffers are the same.
*/
static bool_t
{
return (FALSE);
return (TRUE);
return (TRUE);
return (FALSE);
}
/*
* Compare if two channel bindings are the same. If the local binding is
* NULL then we always return TRUE. This indicates that the local host
* does not care about any bindings.
*/
static bool_t
{
return (TRUE); /* local doesn't care so we won't either */
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
&remote->application_data));
}
/*
* Generate an accept token for a context and channel binding puting the
* generated token output.
*/
static
{
/* Grap a pointer to the context_t part of the token */
/* Set the version number from the context. */
/* Set the token type to be an ACCEPT token. */
/* Set our self as the remote for the other end. */
/* The remote side to us is the local side at the other end. */
/* Our context flags */
/* When we will expire */
/* Our channel bindings */
/* Package the context session keys into a key_set */
/* Build the token */
}
/*
* Check if a credential is valid for the requested usage. Note that
* Diffie-Hellman only supports credentials based on the callers net
* name. netname will point to the users rpc netname. It is up to the
* caller to free the netname.
*/
static OM_uint32
{
/* Set minor status */
*minor = DH_SUCCESS;
/*
* See if the users creditial is available, i.e.,
* the user is "key logged" in.
*/
if (!dh_keyopts.key_secretkey_is_set()) {
*minor = DH_NO_SECRET;
return (GSS_S_NO_CRED);
}
/*
* Get the netname.
*/
*minor = DH_NO_PRINCIPAL;
return (GSS_S_NO_CRED);
}
/*
* Check if the supplied cred is valid for the requested usage.
* The default cred never expires and has a usage of GSS_C_BOTH.
*/
return (GSS_S_NO_CRED);
}
/* See if the cred is still valid */
return (GSS_S_CREDENTIALS_EXPIRED);
}
}
return (GSS_S_COMPLETE);
}
/*
* establish_session_keys: This routine decrypts the session keys supplied
* and uses those keys to verifiy the signature over the input token
* match the signature in the token.
*/
static OM_uint32
{
int i, j;
char *saved_sig;
/*
* The following variable is used by the keyopts key_decryptsessions
* entry point. If this variable is non zero and the underling
* mechanism uses a cache of public keys, then get the public key
* for the remote out of that cache. When key_decrptsessions return
* this variable will be set to non zero if the key did come
* out of the cache, otherwise it will be set to zero.
*/
/* Save the keyset so if we fail we can try again */
return (DH_NOMEM_FAILURE);
for (i = 0; i < keys->dh_key_set_len; i++)
/* Save the unencrypted signature as well for retry attempt */
return (DH_NOMEM_FAILURE);
}
/*
* We will try to decrypt the session keys up to two times.
* The first time will let the underlying mechanism use a
* public key cache, if the set of session keys fail to
* validate the signature that is reported in the deserialized
* token, and those session keys were decrypted by a key
* derived from a public key cache, then we will try again but
* this time will advise the underlying mechanism not to use
* its cache.
*/
for (i = 0; key_was_from_cache && i < 2; i++) {
/*
* Decrypt the session keys using the mechanism specific
* routine and if this is the second time, don't use
* the cache.
*/
if (i == 1)
key_was_from_cache = 0;
&key_was_from_cache)) {
return (DH_SESSION_CIPHER_FAILURE);
}
#ifdef DH_DEBUG
for (i = 0; i < keys->dh_key_set_len; i++)
#endif
/*
* Now verify that the extracted signature from the
* deserialized token is the same as our calculation
* of the signature.
*/
DH_SUCCESS) {
return (DH_SUCCESS);
}
/* Restore the keys and signature for retry */
for (j = 0; j < keys->dh_key_set_len; j++)
}
return (stat);
}
/*
* This is the Diffie-Hellman mechanism entry point for the
* gss_accept_sec context. See RFC 2078 for details. This
* routine accepts a context establish token from the initator
* and optionally produces a token to send back to the initator to
* establish a GSS security context. The established context will
* be return via the *gss_ctx parameter.
*/
/* Local channel bindings */
{
int i;
/* Check for required parameters */
return (GSS_S_CALL_INACCESSIBLE_READ);
return (GSS_S_CALL_INACCESSIBLE_WRITE);
/* Give outputs sane values if present */
*minor = 0;
if (principal)
if (mech)
*mech = GSS_C_NO_OID;
if (flags)
*flags = 0;
if (expire)
*expire = 0;
if (del_cred)
/*
* Diffie-Hellman never returns GSS_S_CONTINUE_NEEDED from a
* gss_accept_sec_context so the only context read should be
* GSS_C_NO_CONTEXT.
*/
if (*gss_ctx != GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
/* Valdidate the local credentinal and retrieve then principal name */
if (stat != GSS_S_COMPLETE)
return (stat);
/*
* Deserialize the input into token, extracting the signature
* into sig. Where sig is our calculation of the MD5 check sum
* over the input token up to the signature.
*/
return (GSS_S_DEFECTIVE_TOKEN);
}
/* set clnt to point to the init context part of token */
/* Check that this context is really for us */
*minor = DH_NOT_LOCAL;
goto cleanup;
}
/*
* See if this is a DH protocol version that we can handle.
* Currently we can handle the one and only DH_PROTO_VERSION.
*/
goto cleanup;
}
/* Decrypt the session keys and verify the signature */
goto cleanup;
}
/* Check that the channel bindings are the same */
goto cleanup;
}
/* Everything is OK, so allocate the context */
goto cleanup;
}
/*
* The context is now established for us, though we may still
* need to send a token if the initiator requested mutual
* authentications.
*/
/* We're not the initiator */
/* Set the protocol version from the token */
/* Initialize the sequence history */
/* Set debug to false */
/* Set who the initiator is */
goto cleanup;
}
/* Set who we are */
goto cleanup;
}
/* Stash a copy of the session keys for the context */
goto cleanup;
}
/* Set the flags and expire time */
/* Create output token if needed */
goto cleanup;
}
}
/* This is now a valid context */
goto cleanup;
}
/* Return the GSS context to the caller */
/* Return the remote principal if requested */
if (principal)
/* Return the flags if requested */
if (flags)
/* Return the expire time if requested */
if (expire)
/* Return the mechanism if requested */
if (mech)
/* Release storage of the signature */
/* Tear down the deserialize token */
/* We're done */
return (GSS_S_COMPLETE);
/* Destroy incomplete context */
if (g_cntx) {
(void) __dh_remove_context(g_cntx);
}
/* Release the signature and the deserialized token. */
return (stat);
}
/*
* gen_init_token: create a token to pass to the other side
* to create a GSS context.
*/
static
{
int i, stat;
/* Create key_set for session keys */
return (DH_NOMEM_FAILURE);
/* Initialize token from GSS context */
/* Set remote to init_context part of token */
/* We're the remote to the other side */
/* And they are the local */
/* Set our flags */
/* Set the expire time */
/* hand of our channel bindings */
/* set the tokens keys */
/* Encrypt the keys for the other side */
return (DH_SESSION_CIPHER_FAILURE);
}
/* Package up our session keys */
/*
* Make an APPLICATION 0 token and place it in result.
* Note that the unecrypted ukeys key_set is used to sign
* the token.
*/
/* We're don with the encrypted session keys */
/* Return our status */
return (stat);
}
/*
* create_context: Builds the initial Diffie-Hellman GSS context.
* It should always be the case that *gss_ctx == GSS_C_NO_CONTEXT
* on entering this routine. Given the inputs we created a Diffie-Hellman
* context from them. This routine will call gen_init_token above to
* generate the output token to pass to the other side.
*/
static
{
/* Create the Diffie-Hellman context */
return (GSS_S_FAILURE);
}
/* We're not established yet */
/* We're the initiator */
/* Set the protocol version for the context */
/* Initialize the sequence and replay history */
/* Turn off debugging */
dh_gss_ctx->debug = 0;
/* Remember who we want to talk to. */
goto cleanup;
}
/* Rember who we are. */
goto cleanup;
}
/* Set up the session key */
goto cleanup;
}
/* Call the mechanism specific key generator */
goto cleanup;
}
#ifdef DH_DEBUG
{
int i;
for (i = 0; i < dh_gss_ctx->no_keys; i++)
}
#endif
/*
* We don't support currently support
* GSS_C_ANON_FLAG and GSS_C_DELEG_FLAG and GSS_C_CONF_FLAG
*/
/* This mechanism does integrity */
/* Return flags to the caller if they care */
if (flags_rec)
/* Set expire, 0 is the default, which means indefinite */
/* Actually set the expire time for the context */
/* Tell the call the time given to the context if they care */
if (time_rec)
/* Gennerate the output token to send to the other side */
if (*minor != DH_SUCCESS)
goto cleanup;
/* Recored this context as valid */
goto cleanup;
/* If we ask for mutal authentication return continue needed */
/*
* Let the caller of gss_init_sec_context know that they don't
* have a context.
*/
return (GSS_S_FAILURE);
}
/*
* continue_context: Proccess the token from the otherside in the case
* of mutual authentication.
*/
static
{
/* Set minor to sane state */
*minor = DH_SUCCESS;
/* This should never happen */
return (GSS_S_DEFECTIVE_TOKEN);
/* Package the session keys for __get_token) */
/* Deserialize the input token into tok using the session keys */
return (*minor == DH_VERIFIER_MISMATCH ?
/*
* See if this is a Diffie-Hellman protocol version that we
* can handle. Currently we can only handle the protocol version that
* we initiated.
*/
return (GSS_S_DEFECTIVE_TOKEN);
}
/* Make sure this is the right type of token */
return (GSS_S_DEFECTIVE_TOKEN);
}
/* Grab a pointer to the context part of the token */
/* Make sure this is from the remote and for us */
return (GSS_S_DEFECTIVE_TOKEN);
}
/* Make sure if the optional channel_bindings are the same */
return (GSS_S_BAD_BINDINGS);
}
/* Update the context flags with what the remote will accept */
/* We now have an established context */
/* Release the deserialized token, tok */
return (GSS_S_COMPLETE);
}
/*
* This is the Diffie-Hellman mechanism entry point for the
* gss_int_sec context. See RFC 2078 for details. This
* routine creates a new context or continues a previously created
* context if mutual authentication had been requested on the orignal
* context. The first call to this routine should set *context to
* GSS_C_NO_CONTEXT and input_token to GSS_C_NO_BUFFER or input_token->length
* to zero. To continue a context in the case of mutual authentication
* gss_ctx should point to the initial context and input_token should point
* to the token received from the remote. The established context will
* be return via the *context parameter in all cases.
*/
{
/* We need these */
if (minor == 0 || output_token == 0)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
/* Set to sane state */
*minor = DH_SUCCESS;
output_token->length = 0;
if (mech_rec)
/* Check that were the right mechanism */
if ((mech != GSS_C_NULL_OID) &&
return (GSS_S_BAD_MECH);
}
/* Validate the cred and obtain our netname in the process. */
if (stat != GSS_S_COMPLETE)
return (stat);
/* validate target name */
/*
* we could check that the target is in the proper form and
* possibly do a lookup up on the host part.
*/
/* checks for new context */
if (input_token != GSS_C_NO_BUFFER &&
input_token->length != 0)
return (GSS_S_DEFECTIVE_TOKEN);
/* Create a new context */
/* Set the GSS context to the Diffie-Hellman context */
} else {
/* Validate the context */
return (GSS_S_NO_CONTEXT);
/* Authenticate the server */
}
return (stat);
}