1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  *	token.c
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  *	Copyright (c) 1997, by Sun Microsystems, Inc.
26*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <stdio.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "dh_gssapi.h"
35*7c478bd9Sstevel@tonic-gate #include "crypto.h"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate extern int
38*7c478bd9Sstevel@tonic-gate get_der_length(unsigned char **, unsigned int, unsigned int *);
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate extern unsigned int
41*7c478bd9Sstevel@tonic-gate der_length_size(unsigned int);
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate extern int
44*7c478bd9Sstevel@tonic-gate put_der_length(unsigned int, unsigned char **, unsigned int);
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #define	MSO_BIT (8*(sizeof (int) - 1))	/* Most significant octet bit */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate static OM_uint32
49*7c478bd9Sstevel@tonic-gate __xdr_encode_token(XDR *, gss_buffer_t, dh_token_t, dh_key_set_t);
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static OM_uint32
52*7c478bd9Sstevel@tonic-gate __xdr_decode_token(XDR *, gss_buffer_t,
53*7c478bd9Sstevel@tonic-gate 		dh_token_t, dh_key_set_t, dh_signature_t);
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * get_qop: For a Diffie-Hellman token_t, return the associate QOP
57*7c478bd9Sstevel@tonic-gate  */
58*7c478bd9Sstevel@tonic-gate static dh_qop_t
get_qop(dh_token_t t)59*7c478bd9Sstevel@tonic-gate get_qop(dh_token_t t)
60*7c478bd9Sstevel@tonic-gate {
61*7c478bd9Sstevel@tonic-gate 	dh_token_body_t body = &t->ver.dh_version_u.body;
62*7c478bd9Sstevel@tonic-gate 	switch (body->type) {
63*7c478bd9Sstevel@tonic-gate 	case DH_INIT_CNTX:
64*7c478bd9Sstevel@tonic-gate 	case DH_ACCEPT_CNTX:
65*7c478bd9Sstevel@tonic-gate 		return (DH_MECH_QOP);
66*7c478bd9Sstevel@tonic-gate 	case DH_MIC:
67*7c478bd9Sstevel@tonic-gate 		return (body->dh_token_body_desc_u.sign.qop);
68*7c478bd9Sstevel@tonic-gate 	case DH_WRAP:
69*7c478bd9Sstevel@tonic-gate 		return (body->dh_token_body_desc_u.seal.mic.qop);
70*7c478bd9Sstevel@tonic-gate 	default:
71*7c478bd9Sstevel@tonic-gate 		/* Should never get here */
72*7c478bd9Sstevel@tonic-gate 		return (DH_MECH_QOP);
73*7c478bd9Sstevel@tonic-gate 	}
74*7c478bd9Sstevel@tonic-gate }
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * __make_ap_token: This routine generates a Diffie-Hellman serialized
78*7c478bd9Sstevel@tonic-gate  * token which has an ASN.1 application 0 header prepended. The unserialized
79*7c478bd9Sstevel@tonic-gate  * token supplied should be of type DH_INIT_CNTX.
80*7c478bd9Sstevel@tonic-gate  *
81*7c478bd9Sstevel@tonic-gate  * The ASN.1 applicationtion prefix is encoded as follows:
82*7c478bd9Sstevel@tonic-gate  *
83*7c478bd9Sstevel@tonic-gate  *	+------+
84*7c478bd9Sstevel@tonic-gate  *	| 0x60 |	1	TAG for APPLICATION 0
85*7c478bd9Sstevel@tonic-gate  *	+------+
86*7c478bd9Sstevel@tonic-gate  *	|      |
87*7c478bd9Sstevel@tonic-gate  *	~      ~     app_size	DER encoded length of oid_size + token_size
88*7c478bd9Sstevel@tonic-gate  *	|      |
89*7c478bd9Sstevel@tonic-gate  *      +------+
90*7c478bd9Sstevel@tonic-gate  *	| 0x06 |	1	TAG for OID
91*7c478bd9Sstevel@tonic-gate  *	+------+
92*7c478bd9Sstevel@tonic-gate  *	|      |  der_length_size
93*7c478bd9Sstevel@tonic-gate  *	~      ~  (mech->length) DER encoded length of mech->length
94*7c478bd9Sstevel@tonic-gate  *	|      |
95*7c478bd9Sstevel@tonic-gate  *	+------+
96*7c478bd9Sstevel@tonic-gate  *	|      |
97*7c478bd9Sstevel@tonic-gate  *	~      ~  mech->length	OID elements (mech->elements)
98*7c478bd9Sstevel@tonic-gate  *	|      |
99*7c478bd9Sstevel@tonic-gate  *	+------+
100*7c478bd9Sstevel@tonic-gate  *	| 0x00 |       0-3	XDR padding
101*7c478bd9Sstevel@tonic-gate  *	+------+
102*7c478bd9Sstevel@tonic-gate  *	|      |
103*7c478bd9Sstevel@tonic-gate  *	~      ~		Serialized DH token
104*7c478bd9Sstevel@tonic-gate  *	|      |
105*7c478bd9Sstevel@tonic-gate  *	+------+
106*7c478bd9Sstevel@tonic-gate  *	| 0x00 |       0-3	Left over XDR padding
107*7c478bd9Sstevel@tonic-gate  *	+------+
108*7c478bd9Sstevel@tonic-gate  *
109*7c478bd9Sstevel@tonic-gate  * We will define the token_size to be the sizeof the serialize token plus
110*7c478bd9Sstevel@tonic-gate  * 3 the maximum XDR paddinging that will be needed. Thus the XDR padding
111*7c478bd9Sstevel@tonic-gate  * plus the left over XDR padding will alway equal 3.
112*7c478bd9Sstevel@tonic-gate  */
113*7c478bd9Sstevel@tonic-gate OM_uint32
__make_ap_token(gss_buffer_t result,gss_OID mech,dh_token_t token,dh_key_set_t keys)114*7c478bd9Sstevel@tonic-gate __make_ap_token(gss_buffer_t result, /* The serialized token */
115*7c478bd9Sstevel@tonic-gate 		gss_OID mech, /* The mechanism this is for */
116*7c478bd9Sstevel@tonic-gate 		dh_token_t token, /* The unserialized input token */
117*7c478bd9Sstevel@tonic-gate 		dh_key_set_t keys /* The session keys to sign the token */)
118*7c478bd9Sstevel@tonic-gate {
119*7c478bd9Sstevel@tonic-gate 	unsigned int size, hsize, token_size, app_size, oid_size, start;
120*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
121*7c478bd9Sstevel@tonic-gate 	unsigned char *sv, *buf, *xdrmem;
122*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	/* Allocate the signature for the input token */
125*7c478bd9Sstevel@tonic-gate 	if ((stat = __alloc_sig(get_qop(token),
126*7c478bd9Sstevel@tonic-gate 				&token->verifier))
127*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS)
128*7c478bd9Sstevel@tonic-gate 		return (stat);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/*
131*7c478bd9Sstevel@tonic-gate 	 * We will first determine the size of the output token in
132*7c478bd9Sstevel@tonic-gate 	 * a bottom up fashion.
133*7c478bd9Sstevel@tonic-gate 	 */
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	/* Fetch the size of a serialized DH token */
136*7c478bd9Sstevel@tonic-gate 	token_size = xdr_sizeof((xdrproc_t)xdr_dh_token_desc, (void *)token);
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	/*
139*7c478bd9Sstevel@tonic-gate 	 * The token itself needs to be pasted on to the ASN.1
140*7c478bd9Sstevel@tonic-gate 	 * application header on BYTES_PER_XDR_UNIT boundry. So we may
141*7c478bd9Sstevel@tonic-gate 	 *  need upto BYTES_PER_XDR_UNIT - 1 extra bytes.
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 	token_size += BYTES_PER_XDR_UNIT -1;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	oid_size = mech->length;
147*7c478bd9Sstevel@tonic-gate 	oid_size += der_length_size(mech->length);
148*7c478bd9Sstevel@tonic-gate 	oid_size += 1;   /* tag x06 for Oid */
149*7c478bd9Sstevel@tonic-gate 	/* bytes to store the length */
150*7c478bd9Sstevel@tonic-gate 	app_size = der_length_size(oid_size + token_size);
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	hsize = app_size + oid_size;
153*7c478bd9Sstevel@tonic-gate 	hsize += 1;  /* tag 0x60  for application 0 */
154*7c478bd9Sstevel@tonic-gate 	size = hsize + token_size;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	/* Allocate a buffer to serialize into */
157*7c478bd9Sstevel@tonic-gate 	buf = New(unsigned char, size);
158*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
159*7c478bd9Sstevel@tonic-gate 		__free_signature(&token->verifier);
160*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	result->value = sv = buf;
164*7c478bd9Sstevel@tonic-gate 	result->length = size;
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	/* ASN.1 application 0 header */
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	/* Encode the tag */
169*7c478bd9Sstevel@tonic-gate 	*buf++ = 0x60;
170*7c478bd9Sstevel@tonic-gate 	/* Encode the app length */
171*7c478bd9Sstevel@tonic-gate 	put_der_length(oid_size + token_size, &buf, app_size);
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	/* Encode the OID tag */
174*7c478bd9Sstevel@tonic-gate 	*buf++ = 0x06;
175*7c478bd9Sstevel@tonic-gate 	/* Encode the OID length */
176*7c478bd9Sstevel@tonic-gate 	put_der_length(mech->length, &buf, oid_size);
177*7c478bd9Sstevel@tonic-gate 	/* Encode the OID elemeents */
178*7c478bd9Sstevel@tonic-gate 	memcpy(buf, mech->elements, mech->length);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/* Encode the Diffie-Hellmam token */
181*7c478bd9Sstevel@tonic-gate 	/*
182*7c478bd9Sstevel@tonic-gate 	 * Token has to be on BYTES_PER_XDR_UNIT boundry. (RNDUP is
183*7c478bd9Sstevel@tonic-gate 	 * from xdr.h)
184*7c478bd9Sstevel@tonic-gate 	 */
185*7c478bd9Sstevel@tonic-gate 	start = RNDUP(hsize);
186*7c478bd9Sstevel@tonic-gate 	/* Buffer for xdrmem_create to use */
187*7c478bd9Sstevel@tonic-gate 	xdrmem = &sv[start];
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, (caddr_t)xdrmem, token_size, XDR_ENCODE);
190*7c478bd9Sstevel@tonic-gate 	/* Paste the DH token on */
191*7c478bd9Sstevel@tonic-gate 	if ((stat = __xdr_encode_token(&xdrs, NULL, token, keys))
192*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS) {
193*7c478bd9Sstevel@tonic-gate 		__free_signature(&token->verifier);
194*7c478bd9Sstevel@tonic-gate 		__dh_release_buffer(result);
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	/* We're done with the signature, the token has been serialized */
198*7c478bd9Sstevel@tonic-gate 	__free_signature(&token->verifier);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	return (stat);
201*7c478bd9Sstevel@tonic-gate }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate  * __make_token: Given an unserialized DH token, serialize it puting the
205*7c478bd9Sstevel@tonic-gate  * serialized output in result. If this token has a type of DH_MIC, then
206*7c478bd9Sstevel@tonic-gate  * the optional message, msg, should be supplied. The mic caluclated will be
207*7c478bd9Sstevel@tonic-gate  * over the message as well as the serialized token.
208*7c478bd9Sstevel@tonic-gate  */
209*7c478bd9Sstevel@tonic-gate OM_uint32
__make_token(gss_buffer_t result,gss_buffer_t msg,dh_token_t token,dh_key_set_t keys)210*7c478bd9Sstevel@tonic-gate __make_token(gss_buffer_t result, /* Serialized token goes here */
211*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t msg,	/* Optional message for DH_MIC tokens */
212*7c478bd9Sstevel@tonic-gate 	    dh_token_t token,	/* The token to encode */
213*7c478bd9Sstevel@tonic-gate 	    dh_key_set_t keys	/* The keys to encrypt the check sum with */)
214*7c478bd9Sstevel@tonic-gate {
215*7c478bd9Sstevel@tonic-gate 	unsigned int token_size;
216*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
217*7c478bd9Sstevel@tonic-gate 	unsigned char *buf;
218*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	/* Allocate a signature for this token */
221*7c478bd9Sstevel@tonic-gate 	if ((stat = __alloc_sig(get_qop(token),
222*7c478bd9Sstevel@tonic-gate 				&token->verifier))
223*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS)
224*7c478bd9Sstevel@tonic-gate 		return (stat);
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	/* Get the output token size to know how much to allocate */
227*7c478bd9Sstevel@tonic-gate 	token_size = xdr_sizeof((xdrproc_t)xdr_dh_token_desc, (void *)token);
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	/* Allocate the buffer to hold the serialized token */
230*7c478bd9Sstevel@tonic-gate 	buf = New(unsigned char, token_size);
231*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
232*7c478bd9Sstevel@tonic-gate 		__free_signature(&token->verifier);
233*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/* Set the result */
237*7c478bd9Sstevel@tonic-gate 	result->length = token_size;
238*7c478bd9Sstevel@tonic-gate 	result->value = (void *)buf;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	/* Create the xdr stream using the allocated buffer */
241*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, (char *)buf, token_size, XDR_ENCODE);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	/* Encode the token */
244*7c478bd9Sstevel@tonic-gate 	if ((stat = __xdr_encode_token(&xdrs, msg, token, keys))
245*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS) {
246*7c478bd9Sstevel@tonic-gate 		__free_signature(&token->verifier);
247*7c478bd9Sstevel@tonic-gate 		__dh_release_buffer(result);
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	/* Release the signature */
251*7c478bd9Sstevel@tonic-gate 	__free_signature(&token->verifier);
252*7c478bd9Sstevel@tonic-gate 	return (stat);
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate /*
256*7c478bd9Sstevel@tonic-gate  * __get_ap_token: This routine deserializes a Diffie-Hellman serialized
257*7c478bd9Sstevel@tonic-gate  * token which has an ASN.1 application 0 header prepended. The resulting
258*7c478bd9Sstevel@tonic-gate  * unserialized token supplied should be of type DH_INIT_CNTX..
259*7c478bd9Sstevel@tonic-gate  *
260*7c478bd9Sstevel@tonic-gate  * The ASN.1 applicationtion prefix  and token is encoded as follows:
261*7c478bd9Sstevel@tonic-gate  *
262*7c478bd9Sstevel@tonic-gate  *	+------+
263*7c478bd9Sstevel@tonic-gate  *	| 0x60 |	1	TAG for APPLICATION 0
264*7c478bd9Sstevel@tonic-gate  *	+------+
265*7c478bd9Sstevel@tonic-gate  *	|      |
266*7c478bd9Sstevel@tonic-gate  *	~      ~     app_size	DER encoded length of oid_size + token_size
267*7c478bd9Sstevel@tonic-gate  *	|      |
268*7c478bd9Sstevel@tonic-gate  *      +------+
269*7c478bd9Sstevel@tonic-gate  *	| 0x06 |	1	TAG for OID
270*7c478bd9Sstevel@tonic-gate  *	+------+
271*7c478bd9Sstevel@tonic-gate  *	|      |  der_length_size
272*7c478bd9Sstevel@tonic-gate  *	~      ~  (mech->length) DER encoded length of mech->length
273*7c478bd9Sstevel@tonic-gate  *	|      |
274*7c478bd9Sstevel@tonic-gate  *	+------+
275*7c478bd9Sstevel@tonic-gate  *	|      |
276*7c478bd9Sstevel@tonic-gate  *	~      ~  mech->length	OID elements (mech->elements)
277*7c478bd9Sstevel@tonic-gate  *	|      |
278*7c478bd9Sstevel@tonic-gate  *	+------+
279*7c478bd9Sstevel@tonic-gate  *	| 0x00 |       0-3	XDR padding
280*7c478bd9Sstevel@tonic-gate  *	+------+
281*7c478bd9Sstevel@tonic-gate  *	|      |
282*7c478bd9Sstevel@tonic-gate  *	~      ~		Serialized DH token
283*7c478bd9Sstevel@tonic-gate  *	|      |
284*7c478bd9Sstevel@tonic-gate  *	+------+
285*7c478bd9Sstevel@tonic-gate  *	| 0x00 |       0-3	Left over XDR padding
286*7c478bd9Sstevel@tonic-gate  *	+------+
287*7c478bd9Sstevel@tonic-gate  *
288*7c478bd9Sstevel@tonic-gate  * We will define the token_size to be the sizeof the serialize token plus
289*7c478bd9Sstevel@tonic-gate  * 3 the maximum XDR paddinging that will be needed. Thus the XDR padding
290*7c478bd9Sstevel@tonic-gate  * plus the left over XDR padding will alway equal 3.
291*7c478bd9Sstevel@tonic-gate  */
292*7c478bd9Sstevel@tonic-gate OM_uint32
__get_ap_token(gss_buffer_t input,gss_OID mech,dh_token_t token,dh_signature_t sig)293*7c478bd9Sstevel@tonic-gate __get_ap_token(gss_buffer_t input, /* The token to deserialize */
294*7c478bd9Sstevel@tonic-gate 	    gss_OID mech, /* This context's OID */
295*7c478bd9Sstevel@tonic-gate 	    dh_token_t token, /* The resulting token */
296*7c478bd9Sstevel@tonic-gate 	    dh_signature_t sig /* The signature found over the input token */)
297*7c478bd9Sstevel@tonic-gate {
298*7c478bd9Sstevel@tonic-gate 	unsigned char *buf, *p;
299*7c478bd9Sstevel@tonic-gate 	unsigned int oid_len, token_len, bytes, hsize;
300*7c478bd9Sstevel@tonic-gate 	int len;
301*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
302*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/* Set p and buf to point to the beginning of the token */
305*7c478bd9Sstevel@tonic-gate 	p = buf = (unsigned char *)input->value;
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	/* Check that this is an ASN.1 APPLICATION 0 token */
308*7c478bd9Sstevel@tonic-gate 	if (*p++ != 0x60)
309*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/* Determine the length for the DER encoding of the packet length */
312*7c478bd9Sstevel@tonic-gate 	if ((len = get_der_length(&p, input->length - 1, &bytes)) < 0)
313*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*
316*7c478bd9Sstevel@tonic-gate 	 * See if the number of bytes specified by the
317*7c478bd9Sstevel@tonic-gate 	 * encoded length is all there
318*7c478bd9Sstevel@tonic-gate 	 */
319*7c478bd9Sstevel@tonic-gate 	if (input->length - 1 - bytes != len)
320*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	/*
323*7c478bd9Sstevel@tonic-gate 	 * Running total of the APPLICATION 0 prefix so far. One for the
324*7c478bd9Sstevel@tonic-gate 	 * tag (0x60) and the bytes necessary to encode the length of the
325*7c478bd9Sstevel@tonic-gate 	 * packet.
326*7c478bd9Sstevel@tonic-gate 	 */
327*7c478bd9Sstevel@tonic-gate 	hsize = 1 + bytes;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	/* Check that we're now looking at an OID */
330*7c478bd9Sstevel@tonic-gate 	if (*p++ != 0x06)
331*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	/* Get OID length and the number of bytes that to encode it */
334*7c478bd9Sstevel@tonic-gate 	oid_len = get_der_length(&p, len - 1, &bytes);
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	/*
337*7c478bd9Sstevel@tonic-gate 	 * Now add the byte for the OID tag, plus the bytes for the oid
338*7c478bd9Sstevel@tonic-gate 	 * length, plus the oid length its self. That is, add the size
339*7c478bd9Sstevel@tonic-gate 	 * of the encoding of the OID to the running total of the
340*7c478bd9Sstevel@tonic-gate 	 * APPLICATION 0 header. The result is the total size of the header.
341*7c478bd9Sstevel@tonic-gate 	 */
342*7c478bd9Sstevel@tonic-gate 	hsize += 1 + bytes + oid_len;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	/*
345*7c478bd9Sstevel@tonic-gate 	 * The DH token length is the application length minus the length
346*7c478bd9Sstevel@tonic-gate 	 * of the OID encoding.
347*7c478bd9Sstevel@tonic-gate 	 */
348*7c478bd9Sstevel@tonic-gate 	token_len = len - 1 - bytes - oid_len;
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	/* Sanity check the token length */
351*7c478bd9Sstevel@tonic-gate 	if (input->length - hsize != token_len)
352*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	/* Check that this token is for this OID */
355*7c478bd9Sstevel@tonic-gate 	if (mech->length != oid_len)
356*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
357*7c478bd9Sstevel@tonic-gate 	if (memcmp(mech->elements, p, oid_len) != 0)
358*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	/* Round up the header size to XDR boundry */
361*7c478bd9Sstevel@tonic-gate 	hsize = RNDUP(hsize);
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	/* Get the start of XDR encoded token */
364*7c478bd9Sstevel@tonic-gate 	p = &buf[hsize];
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/* Create and XDR stream to decode from */
367*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, (caddr_t)p, token_len, XDR_DECODE);
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	/*
370*7c478bd9Sstevel@tonic-gate 	 * Clear the deserialized token (we'll have the xdr routines
371*7c478bd9Sstevel@tonic-gate 	 * do the the allocations).
372*7c478bd9Sstevel@tonic-gate 	 */
373*7c478bd9Sstevel@tonic-gate 	memset(token, 0, sizeof (dh_token_desc));
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	/* Zero out the signature */
376*7c478bd9Sstevel@tonic-gate 	memset(sig, 0, sizeof (*sig));
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	/*
379*7c478bd9Sstevel@tonic-gate 	 * Decode the DH_INIT_CNTX token. Note that at this point we have no
380*7c478bd9Sstevel@tonic-gate 	 * session keys established, so that keys is null. The unencrypted
381*7c478bd9Sstevel@tonic-gate 	 * signature will be made available to the caller in sig. The
382*7c478bd9Sstevel@tonic-gate 	 * caller can then attempt to decrypt the session keys in token
383*7c478bd9Sstevel@tonic-gate 	 * and encrypt the returned sig  with those keys to check the
384*7c478bd9Sstevel@tonic-gate 	 * integrity of the token.
385*7c478bd9Sstevel@tonic-gate 	 */
386*7c478bd9Sstevel@tonic-gate 	if ((stat = __xdr_decode_token(&xdrs, NULL, token, NULL, sig))
387*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS) {
388*7c478bd9Sstevel@tonic-gate 		xdr_free(xdr_dh_token_desc, (char *)token);
389*7c478bd9Sstevel@tonic-gate 		return (stat);
390*7c478bd9Sstevel@tonic-gate 	}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	return (stat);
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate /*
396*7c478bd9Sstevel@tonic-gate  * __get_token: Deserialize a supplied Diffie-Hellman token. Note the
397*7c478bd9Sstevel@tonic-gate  * session keys should always be supplied to this routine. The message
398*7c478bd9Sstevel@tonic-gate  * should only be supplied if the token is of DH_MIC type.
399*7c478bd9Sstevel@tonic-gate  */
400*7c478bd9Sstevel@tonic-gate OM_uint32
__get_token(gss_buffer_t input,gss_buffer_t msg,dh_token_t token,dh_key_set_t keys)401*7c478bd9Sstevel@tonic-gate __get_token(gss_buffer_t input, /* The token to deserialize */
402*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t msg, /* Optional message to generate verifier over */
403*7c478bd9Sstevel@tonic-gate 	    dh_token_t token,    /* The decode token */
404*7c478bd9Sstevel@tonic-gate 	    dh_key_set_t keys    /* The session keys */)
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
407*7c478bd9Sstevel@tonic-gate 	dh_signature sig;
408*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	/* Create a an XDR stream out of the input token */
411*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, (caddr_t)input->value, input->length, XDR_DECODE);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	/* Clear the token_desc and signature. */
414*7c478bd9Sstevel@tonic-gate 	memset(token, 0, sizeof (dh_token_desc));
415*7c478bd9Sstevel@tonic-gate 	memset(&sig, 0, sizeof (sig));
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	/* Decode the token */
418*7c478bd9Sstevel@tonic-gate 	if ((stat = __xdr_decode_token(&xdrs, msg, token, keys, &sig))
419*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS)
420*7c478bd9Sstevel@tonic-gate 		/* If we fail release the deserialized token */
421*7c478bd9Sstevel@tonic-gate 		xdr_free(xdr_dh_token_desc, (char *)token);
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	/* We always free the signature */
424*7c478bd9Sstevel@tonic-gate 	__free_signature(&sig);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	return (stat);
427*7c478bd9Sstevel@tonic-gate }
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate /*
430*7c478bd9Sstevel@tonic-gate  * Warning these routines assumes that xdrs was created with xdrmem_create!
431*7c478bd9Sstevel@tonic-gate  */
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate /*
434*7c478bd9Sstevel@tonic-gate  * __xdr_encode_token: Given an allocated xdrs stream serialize the supplied
435*7c478bd9Sstevel@tonic-gate  * token_desc pointed to by objp, using keys to encrypt the signature. If
436*7c478bd9Sstevel@tonic-gate  * msg is non null then calculate the signature over msg as well as the
437*7c478bd9Sstevel@tonic-gate  * serialized token. Note this protocol is designed with the signature as
438*7c478bd9Sstevel@tonic-gate  * the last part of any token. In this way the signature that is calculated is
439*7c478bd9Sstevel@tonic-gate  * always done over the entire token. All fields in any token are thus
440*7c478bd9Sstevel@tonic-gate  * protected from tampering
441*7c478bd9Sstevel@tonic-gate  */
442*7c478bd9Sstevel@tonic-gate static OM_uint32
__xdr_encode_token(register XDR * xdrs,gss_buffer_t msg,dh_token_desc * objp,dh_key_set_t keys)443*7c478bd9Sstevel@tonic-gate __xdr_encode_token(register XDR *xdrs, gss_buffer_t msg,
444*7c478bd9Sstevel@tonic-gate 		dh_token_desc *objp, dh_key_set_t keys)
445*7c478bd9Sstevel@tonic-gate {
446*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	/* Check that xdrs is valid */
449*7c478bd9Sstevel@tonic-gate 	if (xdrs == 0 || xdrs->x_op != XDR_ENCODE)
450*7c478bd9Sstevel@tonic-gate 		return (DH_BADARG_FAILURE);
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	/* Encode the protocol versioned body */
453*7c478bd9Sstevel@tonic-gate 	if (!xdr_dh_version(xdrs, &objp->ver))
454*7c478bd9Sstevel@tonic-gate 		return (DH_ENCODE_FAILURE);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	/* Calculate the signature */
457*7c478bd9Sstevel@tonic-gate 	stat = __mk_sig(get_qop(objp), xdrs->x_base,
458*7c478bd9Sstevel@tonic-gate 			xdr_getpos(xdrs), msg, keys,
459*7c478bd9Sstevel@tonic-gate 			&objp->verifier);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	if (stat != DH_SUCCESS)
462*7c478bd9Sstevel@tonic-gate 		return (stat);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	/* Encode the signature */
465*7c478bd9Sstevel@tonic-gate 	if (!xdr_dh_signature(xdrs, &objp->verifier))
466*7c478bd9Sstevel@tonic-gate 		return (DH_ENCODE_FAILURE);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate /*
472*7c478bd9Sstevel@tonic-gate  * __xdr_decode_token: Decode a token from an XDR stream into a token_desc
473*7c478bd9Sstevel@tonic-gate  * pointed to by objp. We will calculate a signature over the serialized
474*7c478bd9Sstevel@tonic-gate  * token and an optional message. The calculated signature will be
475*7c478bd9Sstevel@tonic-gate  * returned to the caller in sig. If the supplied keys are available this
476*7c478bd9Sstevel@tonic-gate  * routine will compare that the verifier in the deserialized token is
477*7c478bd9Sstevel@tonic-gate  * the same as the calculated signature over the input stream. This is
478*7c478bd9Sstevel@tonic-gate  * the usual case. However if the supplied serialized token is DH_INIT_CNTX,
479*7c478bd9Sstevel@tonic-gate  * the keys have not yet been established. So we just give the caller back
480*7c478bd9Sstevel@tonic-gate  * our raw signature (Non encrypted) and the deserialized token. Higher in
481*7c478bd9Sstevel@tonic-gate  * the food chain (currently __dh_gss_accept_sec_context), we will attempt
482*7c478bd9Sstevel@tonic-gate  * to decrypt the session keys and call __verify_sig with the decrypted
483*7c478bd9Sstevel@tonic-gate  * session keys the signature returned from this routine and the deserialized
484*7c478bd9Sstevel@tonic-gate  * token.
485*7c478bd9Sstevel@tonic-gate  *
486*7c478bd9Sstevel@tonic-gate  * Note it is assumed that sig does point to a valid uninitialized signature.
487*7c478bd9Sstevel@tonic-gate  */
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate static OM_uint32
__xdr_decode_token(register XDR * xdrs,gss_buffer_t msg,dh_token_desc * objp,dh_key_set_t keys,dh_signature_t sig)490*7c478bd9Sstevel@tonic-gate __xdr_decode_token(register XDR *xdrs, gss_buffer_t msg,
491*7c478bd9Sstevel@tonic-gate 		dh_token_desc *objp, dh_key_set_t keys, dh_signature_t sig)
492*7c478bd9Sstevel@tonic-gate {
493*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	/* Check that we are decoding */
496*7c478bd9Sstevel@tonic-gate 	if (xdrs == 0 || xdrs->x_op != XDR_DECODE)
497*7c478bd9Sstevel@tonic-gate 		return (DH_BADARG_FAILURE);
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	/* Decode the protocol versioned body */
500*7c478bd9Sstevel@tonic-gate 	if (!xdr_dh_version(xdrs, &objp->ver))
501*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	/* Allocate the signature for this tokens QOP */
504*7c478bd9Sstevel@tonic-gate 	if ((stat = __alloc_sig(get_qop(objp), sig)) != DH_SUCCESS)
505*7c478bd9Sstevel@tonic-gate 		return (stat);
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	/*
508*7c478bd9Sstevel@tonic-gate 	 * Call __mk_sig in crypto.c to calculate the signature based on
509*7c478bd9Sstevel@tonic-gate 	 * the decoded QOP. __mk_sig will encrypt the signature with the
510*7c478bd9Sstevel@tonic-gate 	 * supplied keys if they are available. If keys is null the signature
511*7c478bd9Sstevel@tonic-gate 	 * will be just the unencrypted check sum.
512*7c478bd9Sstevel@tonic-gate 	 */
513*7c478bd9Sstevel@tonic-gate 	stat = __mk_sig(get_qop(objp), xdrs->x_base,
514*7c478bd9Sstevel@tonic-gate 			xdr_getpos(xdrs), msg, keys, sig);
515*7c478bd9Sstevel@tonic-gate 	if (stat != DH_SUCCESS)
516*7c478bd9Sstevel@tonic-gate 		return (stat);
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	/* Now decode the supplied signature */
519*7c478bd9Sstevel@tonic-gate 	if (!xdr_dh_signature(xdrs, &objp->verifier))
520*7c478bd9Sstevel@tonic-gate 		return (stat);
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	/*
523*7c478bd9Sstevel@tonic-gate 	 * If we have keys then we can check that the signatures
524*7c478bd9Sstevel@tonic-gate 	 * are the same
525*7c478bd9Sstevel@tonic-gate 	 */
526*7c478bd9Sstevel@tonic-gate 	if (keys && !__cmpsig(sig, &objp->verifier))
527*7c478bd9Sstevel@tonic-gate 		return (DH_VERIFIER_MISMATCH);
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
530*7c478bd9Sstevel@tonic-gate }
531