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