/*
* 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
* 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
*/
/*
* token.c
*
* Copyright (c) 1997, by Sun Microsystems, Inc.
* All rights reserved.
*
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dh_gssapi.h"
#include "crypto.h"
extern int
get_der_length(unsigned char **, unsigned int, unsigned int *);
extern unsigned int
der_length_size(unsigned int);
extern int
put_der_length(unsigned int, unsigned char **, unsigned int);
static OM_uint32
static OM_uint32
/*
* get_qop: For a Diffie-Hellman token_t, return the associate QOP
*/
static dh_qop_t
{
case DH_INIT_CNTX:
case DH_ACCEPT_CNTX:
return (DH_MECH_QOP);
case DH_MIC:
case DH_WRAP:
default:
/* Should never get here */
return (DH_MECH_QOP);
}
}
/*
* __make_ap_token: This routine generates a Diffie-Hellman serialized
* token which has an ASN.1 application 0 header prepended. The unserialized
* token supplied should be of type DH_INIT_CNTX.
*
* The ASN.1 applicationtion prefix is encoded as follows:
*
* +------+
* | 0x60 | 1 TAG for APPLICATION 0
* +------+
* | |
* ~ ~ app_size DER encoded length of oid_size + token_size
* | |
* +------+
* | 0x06 | 1 TAG for OID
* +------+
* | | der_length_size
* ~ ~ (mech->length) DER encoded length of mech->length
* | |
* +------+
* | |
* ~ ~ mech->length OID elements (mech->elements)
* | |
* +------+
* | 0x00 | 0-3 XDR padding
* +------+
* | |
* ~ ~ Serialized DH token
* | |
* +------+
* | 0x00 | 0-3 Left over XDR padding
* +------+
*
* We will define the token_size to be the sizeof the serialize token plus
* 3 the maximum XDR paddinging that will be needed. Thus the XDR padding
* plus the left over XDR padding will alway equal 3.
*/
{
/* Allocate the signature for the input token */
!= DH_SUCCESS)
return (stat);
/*
* We will first determine the size of the output token in
* a bottom up fashion.
*/
/* Fetch the size of a serialized DH token */
/*
* The token itself needs to be pasted on to the ASN.1
* application header on BYTES_PER_XDR_UNIT boundry. So we may
* need upto BYTES_PER_XDR_UNIT - 1 extra bytes.
*/
/* bytes to store the length */
/* Allocate a buffer to serialize into */
return (DH_NOMEM_FAILURE);
}
/* ASN.1 application 0 header */
/* Encode the tag */
*buf++ = 0x60;
/* Encode the app length */
/* Encode the OID tag */
*buf++ = 0x06;
/* Encode the OID length */
/* Encode the OID elemeents */
/* Encode the Diffie-Hellmam token */
/*
* Token has to be on BYTES_PER_XDR_UNIT boundry. (RNDUP is
* from xdr.h)
*/
/* Buffer for xdrmem_create to use */
/* Paste the DH token on */
!= DH_SUCCESS) {
}
/* We're done with the signature, the token has been serialized */
return (stat);
}
/*
* __make_token: Given an unserialized DH token, serialize it puting the
* serialized output in result. If this token has a type of DH_MIC, then
* the optional message, msg, should be supplied. The mic caluclated will be
* over the message as well as the serialized token.
*/
{
unsigned int token_size;
unsigned char *buf;
/* Allocate a signature for this token */
!= DH_SUCCESS)
return (stat);
/* Get the output token size to know how much to allocate */
/* Allocate the buffer to hold the serialized token */
return (DH_NOMEM_FAILURE);
}
/* Set the result */
/* Create the xdr stream using the allocated buffer */
/* Encode the token */
!= DH_SUCCESS) {
}
/* Release the signature */
return (stat);
}
/*
* __get_ap_token: This routine deserializes a Diffie-Hellman serialized
* token which has an ASN.1 application 0 header prepended. The resulting
* unserialized token supplied should be of type DH_INIT_CNTX..
*
* The ASN.1 applicationtion prefix and token is encoded as follows:
*
* +------+
* | 0x60 | 1 TAG for APPLICATION 0
* +------+
* | |
* ~ ~ app_size DER encoded length of oid_size + token_size
* | |
* +------+
* | 0x06 | 1 TAG for OID
* +------+
* | | der_length_size
* ~ ~ (mech->length) DER encoded length of mech->length
* | |
* +------+
* | |
* ~ ~ mech->length OID elements (mech->elements)
* | |
* +------+
* | 0x00 | 0-3 XDR padding
* +------+
* | |
* ~ ~ Serialized DH token
* | |
* +------+
* | 0x00 | 0-3 Left over XDR padding
* +------+
*
* We will define the token_size to be the sizeof the serialize token plus
* 3 the maximum XDR paddinging that will be needed. Thus the XDR padding
* plus the left over XDR padding will alway equal 3.
*/
{
unsigned char *buf, *p;
int len;
/* Set p and buf to point to the beginning of the token */
/* Check that this is an ASN.1 APPLICATION 0 token */
if (*p++ != 0x60)
return (DH_DECODE_FAILURE);
/* Determine the length for the DER encoding of the packet length */
return (DH_DECODE_FAILURE);
/*
* See if the number of bytes specified by the
* encoded length is all there
*/
return (DH_DECODE_FAILURE);
/*
* Running total of the APPLICATION 0 prefix so far. One for the
* tag (0x60) and the bytes necessary to encode the length of the
* packet.
*/
/* Check that we're now looking at an OID */
if (*p++ != 0x06)
return (DH_DECODE_FAILURE);
/* Get OID length and the number of bytes that to encode it */
/*
* Now add the byte for the OID tag, plus the bytes for the oid
* length, plus the oid length its self. That is, add the size
* of the encoding of the OID to the running total of the
* APPLICATION 0 header. The result is the total size of the header.
*/
/*
* The DH token length is the application length minus the length
* of the OID encoding.
*/
/* Sanity check the token length */
return (DH_DECODE_FAILURE);
/* Check that this token is for this OID */
return (DH_DECODE_FAILURE);
return (DH_DECODE_FAILURE);
/* Round up the header size to XDR boundry */
/* Get the start of XDR encoded token */
/* Create and XDR stream to decode from */
/*
* Clear the deserialized token (we'll have the xdr routines
* do the the allocations).
*/
/* Zero out the signature */
/*
* Decode the DH_INIT_CNTX token. Note that at this point we have no
* session keys established, so that keys is null. The unencrypted
* signature will be made available to the caller in sig. The
* caller can then attempt to decrypt the session keys in token
* and encrypt the returned sig with those keys to check the
* integrity of the token.
*/
!= DH_SUCCESS) {
return (stat);
}
return (stat);
}
/*
* __get_token: Deserialize a supplied Diffie-Hellman token. Note the
* session keys should always be supplied to this routine. The message
* should only be supplied if the token is of DH_MIC type.
*/
{
/* Create a an XDR stream out of the input token */
/* Clear the token_desc and signature. */
/* Decode the token */
!= DH_SUCCESS)
/* If we fail release the deserialized token */
/* We always free the signature */
return (stat);
}
/*
* Warning these routines assumes that xdrs was created with xdrmem_create!
*/
/*
* __xdr_encode_token: Given an allocated xdrs stream serialize the supplied
* token_desc pointed to by objp, using keys to encrypt the signature. If
* msg is non null then calculate the signature over msg as well as the
* serialized token. Note this protocol is designed with the signature as
* the last part of any token. In this way the signature that is calculated is
* always done over the entire token. All fields in any token are thus
* protected from tampering
*/
static OM_uint32
{
/* Check that xdrs is valid */
return (DH_BADARG_FAILURE);
/* Encode the protocol versioned body */
return (DH_ENCODE_FAILURE);
/* Calculate the signature */
if (stat != DH_SUCCESS)
return (stat);
/* Encode the signature */
return (DH_ENCODE_FAILURE);
return (DH_SUCCESS);
}
/*
* __xdr_decode_token: Decode a token from an XDR stream into a token_desc
* pointed to by objp. We will calculate a signature over the serialized
* token and an optional message. The calculated signature will be
* returned to the caller in sig. If the supplied keys are available this
* routine will compare that the verifier in the deserialized token is
* the same as the calculated signature over the input stream. This is
* the usual case. However if the supplied serialized token is DH_INIT_CNTX,
* the keys have not yet been established. So we just give the caller back
* our raw signature (Non encrypted) and the deserialized token. Higher in
* the food chain (currently __dh_gss_accept_sec_context), we will attempt
* to decrypt the session keys and call __verify_sig with the decrypted
* session keys the signature returned from this routine and the deserialized
* token.
*
* Note it is assumed that sig does point to a valid uninitialized signature.
*/
static OM_uint32
{
/* Check that we are decoding */
return (DH_BADARG_FAILURE);
/* Decode the protocol versioned body */
return (DH_DECODE_FAILURE);
/* Allocate the signature for this tokens QOP */
return (stat);
/*
* Call __mk_sig in crypto.c to calculate the signature based on
* the decoded QOP. __mk_sig will encrypt the signature with the
* supplied keys if they are available. If keys is null the signature
* will be just the unencrypted check sum.
*/
if (stat != DH_SUCCESS)
return (stat);
/* Now decode the supplied signature */
return (stat);
/*
* If we have keys then we can check that the signatures
* are the same
*/
return (DH_VERIFIER_MISMATCH);
return (DH_SUCCESS);
}