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  *	crypto.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 <sys/note.h>
31*7c478bd9Sstevel@tonic-gate #include "dh_gssapi.h"
32*7c478bd9Sstevel@tonic-gate #include "crypto.h"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate /* Release the storage for a signature */
35*7c478bd9Sstevel@tonic-gate void
__free_signature(dh_signature_t sig)36*7c478bd9Sstevel@tonic-gate __free_signature(dh_signature_t sig)
37*7c478bd9Sstevel@tonic-gate {
38*7c478bd9Sstevel@tonic-gate 	Free(sig->dh_signature_val);
39*7c478bd9Sstevel@tonic-gate 	sig->dh_signature_val = NULL;
40*7c478bd9Sstevel@tonic-gate 	sig->dh_signature_len = 0;
41*7c478bd9Sstevel@tonic-gate }
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /* Release the storage for a gss_buffer */
44*7c478bd9Sstevel@tonic-gate void
__dh_release_buffer(gss_buffer_t b)45*7c478bd9Sstevel@tonic-gate __dh_release_buffer(gss_buffer_t b)
46*7c478bd9Sstevel@tonic-gate {
47*7c478bd9Sstevel@tonic-gate 	Free(b->value);
48*7c478bd9Sstevel@tonic-gate 	b->length = 0;
49*7c478bd9Sstevel@tonic-gate 	b->value = NULL;
50*7c478bd9Sstevel@tonic-gate }
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate typedef struct cipher_entry {
53*7c478bd9Sstevel@tonic-gate 	cipher_proc cipher;	/* Routine to en/decrypt with */
54*7c478bd9Sstevel@tonic-gate 	unsigned int pad;	/* Padding need for the routine */
55*7c478bd9Sstevel@tonic-gate } cipher_entry, *cipher_t;
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate typedef struct verifer_entry {
58*7c478bd9Sstevel@tonic-gate 	verifier_proc msg;	/* Routine to calculate the check sum */
59*7c478bd9Sstevel@tonic-gate 	unsigned int size;	/* Size of check sum */
60*7c478bd9Sstevel@tonic-gate 	cipher_t signer;	/* Cipher entry to sign the check sum */
61*7c478bd9Sstevel@tonic-gate } verifier_entry, *verifier_t;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate typedef struct QOP_entry {
64*7c478bd9Sstevel@tonic-gate 	int export_level;	/* Not currentlyt used */
65*7c478bd9Sstevel@tonic-gate 	verifier_t verifier;	/* Verifier entry to use for integrity */
66*7c478bd9Sstevel@tonic-gate } QOP_entry;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate /*
69*7c478bd9Sstevel@tonic-gate  * Return the length produced by using cipher entry c given the supplied len
70*7c478bd9Sstevel@tonic-gate  */
71*7c478bd9Sstevel@tonic-gate static unsigned int
cipher_pad(cipher_t c,unsigned int len)72*7c478bd9Sstevel@tonic-gate cipher_pad(cipher_t c, unsigned int len)
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate 	unsigned int pad;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	pad = c ? c->pad : 1;
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate 	return (((len + pad - 1)/pad)*pad);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate /*
83*7c478bd9Sstevel@tonic-gate  * Des [en/de]crypt buffer, buf of length, len for each key provided using
84*7c478bd9Sstevel@tonic-gate  * an CBC initialization vector ivec.
85*7c478bd9Sstevel@tonic-gate  * If the mode is encrypt we will use the following pattern if the number
86*7c478bd9Sstevel@tonic-gate  * of keys is odd
87*7c478bd9Sstevel@tonic-gate  * encrypt(buf, k[0]), decrypt(buf, k[1]), encrypt(buf, k[2])
88*7c478bd9Sstevel@tonic-gate  *	decrypt(buf, k[4]) ... encrypt(buf, k[keynum - 1])
89*7c478bd9Sstevel@tonic-gate  * If we have an even number of keys and additional encryption will be
90*7c478bd9Sstevel@tonic-gate  * done with the first key, i.e., ecrypt(buf, k[0]);
91*7c478bd9Sstevel@tonic-gate  * In each [en/de]cription above we will used the passed in CBC initialization
92*7c478bd9Sstevel@tonic-gate  * vector. The new initialization vector will be the vector return from the
93*7c478bd9Sstevel@tonic-gate  * last encryption.
94*7c478bd9Sstevel@tonic-gate  *
95*7c478bd9Sstevel@tonic-gate  * In the decryption case we reverse the proccess. Note in this case
96*7c478bd9Sstevel@tonic-gate  * the return ivec will be from the first decryption.
97*7c478bd9Sstevel@tonic-gate  */
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate static int
__desN_crypt(des_block keys[],int keynum,char * buf,unsigned int len,unsigned int mode,char * ivec)100*7c478bd9Sstevel@tonic-gate __desN_crypt(des_block keys[], int keynum, char *buf, unsigned int len,
101*7c478bd9Sstevel@tonic-gate     unsigned int mode, char *ivec)
102*7c478bd9Sstevel@tonic-gate {
103*7c478bd9Sstevel@tonic-gate 	/* Get the direction of ciphering */
104*7c478bd9Sstevel@tonic-gate 	unsigned int m = mode & (DES_ENCRYPT | DES_DECRYPT);
105*7c478bd9Sstevel@tonic-gate 	/* Get the remaining flags from mode */
106*7c478bd9Sstevel@tonic-gate 	unsigned int flags = mode & ~(DES_ENCRYPT | DES_DECRYPT);
107*7c478bd9Sstevel@tonic-gate 	des_block svec, dvec;
108*7c478bd9Sstevel@tonic-gate 	int i, j, stat;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	/* Do we have at least one key */
111*7c478bd9Sstevel@tonic-gate 	if (keynum < 1)
112*7c478bd9Sstevel@tonic-gate 		return (DESERR_BADPARAM);
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	/* Save the passed in ivec */
115*7c478bd9Sstevel@tonic-gate 	memcpy(svec.c, ivec, sizeof (des_block));
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	/* For  each key do the appropriate cipher */
118*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < keynum; i++) {
119*7c478bd9Sstevel@tonic-gate 		j = (mode & DES_DECRYPT) ? keynum - 1 - i : i;
120*7c478bd9Sstevel@tonic-gate 		stat = cbc_crypt(keys[j].c, buf, len, m | flags, ivec);
121*7c478bd9Sstevel@tonic-gate 		if (mode & DES_DECRYPT && i == 0)
122*7c478bd9Sstevel@tonic-gate 			memcpy(dvec.c, ivec, sizeof (des_block));
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 		if (DES_FAILED(stat))
125*7c478bd9Sstevel@tonic-gate 			return (stat);
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 		m = (m == DES_ENCRYPT ? DES_DECRYPT : DES_ENCRYPT);
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 		if ((mode & DES_DECRYPT) || i != keynum - 1 || i%2)
130*7c478bd9Sstevel@tonic-gate 			memcpy(ivec, svec.c, sizeof (des_block));
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	/*
134*7c478bd9Sstevel@tonic-gate 	 * If we have an even number of keys then do an extra round of
135*7c478bd9Sstevel@tonic-gate 	 * [en/de]cryption with the first key.
136*7c478bd9Sstevel@tonic-gate 	 */
137*7c478bd9Sstevel@tonic-gate 	if (keynum % 2 == 0)
138*7c478bd9Sstevel@tonic-gate 		stat = cbc_crypt(keys[0].c, buf, len, mode, ivec);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	/* If were decrypting ivec is set from first decryption */
141*7c478bd9Sstevel@tonic-gate 	if (mode & DES_DECRYPT)
142*7c478bd9Sstevel@tonic-gate 		memcpy(ivec, dvec.c, sizeof (des_block));
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	return (stat);
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate /*
149*7c478bd9Sstevel@tonic-gate  * DesN crypt packaged for use as a cipher entry
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate static OM_uint32
__dh_desN_crypt(gss_buffer_t buf,dh_key_set_t keys,cipher_mode_t cipher_mode)152*7c478bd9Sstevel@tonic-gate __dh_desN_crypt(gss_buffer_t buf, dh_key_set_t keys, cipher_mode_t cipher_mode)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	int stat = DESERR_BADPARAM;
155*7c478bd9Sstevel@tonic-gate 	int encrypt_flag = (cipher_mode == ENCIPHER);
156*7c478bd9Sstevel@tonic-gate 	unsigned mode = (encrypt_flag ? DES_ENCRYPT : DES_DECRYPT) | DES_HW;
157*7c478bd9Sstevel@tonic-gate 	des_block ivec;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	if (keys->dh_key_set_len < 1)
160*7c478bd9Sstevel@tonic-gate 		return (DH_BADARG_FAILURE);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	/*
163*7c478bd9Sstevel@tonic-gate 	 * We all ways start of with ivec set to zeros. There is no
164*7c478bd9Sstevel@tonic-gate 	 * good way to maintain ivecs since packets could be out of sequence
165*7c478bd9Sstevel@tonic-gate 	 * duplicated or worst of all lost. Under these conditions the
166*7c478bd9Sstevel@tonic-gate 	 * higher level protocol would have to some how resync the ivecs
167*7c478bd9Sstevel@tonic-gate 	 * on both sides and start again. Theres no mechanism for this in
168*7c478bd9Sstevel@tonic-gate 	 * GSS.
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 	memset(&ivec, 0, sizeof (ivec));
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	/* Do the encryption/decryption */
173*7c478bd9Sstevel@tonic-gate 	stat = __desN_crypt(keys->dh_key_set_val, keys->dh_key_set_len,
174*7c478bd9Sstevel@tonic-gate 			    (char *)buf->value, buf->length, mode, ivec.c);
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if (DES_FAILED(stat))
177*7c478bd9Sstevel@tonic-gate 		return (DH_CIPHER_FAILURE);
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Package up plain des cbc crypt for use as a cipher entry.
184*7c478bd9Sstevel@tonic-gate  */
185*7c478bd9Sstevel@tonic-gate static OM_uint32
__dh_des_crypt(gss_buffer_t buf,dh_key_set_t keys,cipher_mode_t cipher_mode)186*7c478bd9Sstevel@tonic-gate __dh_des_crypt(gss_buffer_t buf, dh_key_set_t keys, cipher_mode_t cipher_mode)
187*7c478bd9Sstevel@tonic-gate {
188*7c478bd9Sstevel@tonic-gate 	int stat = DESERR_BADPARAM;
189*7c478bd9Sstevel@tonic-gate 	int encrypt_flag = (cipher_mode == ENCIPHER);
190*7c478bd9Sstevel@tonic-gate 	unsigned mode = (encrypt_flag ? DES_ENCRYPT : DES_DECRYPT) | DES_HW;
191*7c478bd9Sstevel@tonic-gate 	des_block ivec;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	if (keys->dh_key_set_len < 1)
194*7c478bd9Sstevel@tonic-gate 		return (DH_BADARG_FAILURE);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	/*  Set the ivec to zeros and then cbc crypt the result */
197*7c478bd9Sstevel@tonic-gate 	memset(&ivec, 0, sizeof (ivec));
198*7c478bd9Sstevel@tonic-gate 	stat = cbc_crypt(keys->dh_key_set_val[0].c, (char *)buf->value,
199*7c478bd9Sstevel@tonic-gate 			buf->length, mode, ivec.c);
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	if (DES_FAILED(stat))
202*7c478bd9Sstevel@tonic-gate 		return (DH_CIPHER_FAILURE);
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate /*
208*7c478bd9Sstevel@tonic-gate  * MD5_verifier: This is a verifier routine suitable for use in a
209*7c478bd9Sstevel@tonic-gate  * verifier entry. It calculates the MD5 check sum over an optional
210*7c478bd9Sstevel@tonic-gate  * msg and a token. It signs it using the supplied cipher_proc and stores
211*7c478bd9Sstevel@tonic-gate  * the result in signature.
212*7c478bd9Sstevel@tonic-gate  *
213*7c478bd9Sstevel@tonic-gate  * Note signature should already be allocated and be large enough to
214*7c478bd9Sstevel@tonic-gate  * hold the signature after its been encrypted. If keys is null, then
215*7c478bd9Sstevel@tonic-gate  * we will just return the unencrypted check sum.
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate static OM_uint32
MD5_verifier(gss_buffer_t tok,gss_buffer_t msg,cipher_proc signer,dh_key_set_t keys,dh_signature_t signature)218*7c478bd9Sstevel@tonic-gate MD5_verifier(gss_buffer_t tok, /* The buffer to sign */
219*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t msg, /* Optional buffer to include */
220*7c478bd9Sstevel@tonic-gate 	    cipher_proc signer, /* Routine to encrypt the integrity check */
221*7c478bd9Sstevel@tonic-gate 	    dh_key_set_t keys, /* Optiona keys to be used with the above */
222*7c478bd9Sstevel@tonic-gate 	    dh_signature_t signature /* The resulting MIC */)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	MD5_CTX md5_ctx;	/* MD5 context */
225*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc buf;	/* GSS buffer to hold keys for cipher routine */
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	/* Initialize the MD5 context */
228*7c478bd9Sstevel@tonic-gate 	MD5Init(&md5_ctx);
229*7c478bd9Sstevel@tonic-gate 	/* If we have a message to digest, digest it */
230*7c478bd9Sstevel@tonic-gate 	if (msg)
231*7c478bd9Sstevel@tonic-gate 	    MD5Update(&md5_ctx, (unsigned char *)msg->value, msg->length);
232*7c478bd9Sstevel@tonic-gate 	/* Digest the supplied token */
233*7c478bd9Sstevel@tonic-gate 	MD5Update(&md5_ctx, (unsigned char *)tok->value, tok->length);
234*7c478bd9Sstevel@tonic-gate 	/* Finalize the sum. The MD5 context contains the digets */
235*7c478bd9Sstevel@tonic-gate 	MD5Final(&md5_ctx);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	/* Copy the digest to the signature */
238*7c478bd9Sstevel@tonic-gate 	memcpy(signature->dh_signature_val, (void *)md5_ctx.digest, 16);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	buf.length = signature->dh_signature_len;
241*7c478bd9Sstevel@tonic-gate 	buf.value = signature->dh_signature_val;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	/* If we have keys encrypt it */
244*7c478bd9Sstevel@tonic-gate 	if (keys != NULL)
245*7c478bd9Sstevel@tonic-gate 		return (signer(&buf, keys, ENCIPHER));
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
248*7c478bd9Sstevel@tonic-gate }
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate /* Cipher table */
251*7c478bd9Sstevel@tonic-gate static
252*7c478bd9Sstevel@tonic-gate cipher_entry cipher_tab[] = {
253*7c478bd9Sstevel@tonic-gate 	{ NULL, 1},
254*7c478bd9Sstevel@tonic-gate 	{ __dh_desN_crypt, 8},
255*7c478bd9Sstevel@tonic-gate 	{ __dh_des_crypt, 8}
256*7c478bd9Sstevel@tonic-gate };
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate #define	__NO_CRYPT	&cipher_tab[0]
260*7c478bd9Sstevel@tonic-gate #define	__DES_N_CRYPT	&cipher_tab[1]
261*7c478bd9Sstevel@tonic-gate #define	__DES_CRYPT	&cipher_tab[2]
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate /* Verifier table */
264*7c478bd9Sstevel@tonic-gate static
265*7c478bd9Sstevel@tonic-gate verifier_entry verifier_tab[] = {
266*7c478bd9Sstevel@tonic-gate 	{ MD5_verifier, 16, __DES_N_CRYPT },
267*7c478bd9Sstevel@tonic-gate 	{ MD5_verifier, 16, __DES_CRYPT }
268*7c478bd9Sstevel@tonic-gate };
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate /* QOP table */
271*7c478bd9Sstevel@tonic-gate static
272*7c478bd9Sstevel@tonic-gate QOP_entry QOP_table[] = {
273*7c478bd9Sstevel@tonic-gate 	{ 0, &verifier_tab[0] },
274*7c478bd9Sstevel@tonic-gate 	{ 0, &verifier_tab[1] }
275*7c478bd9Sstevel@tonic-gate };
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate #define	QOP_ENTRIES (sizeof (QOP_table) / sizeof (QOP_entry))
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * __dh_is_valid_QOP: Return true if qop is valid entry into the QOP
281*7c478bd9Sstevel@tonic-gate  * table, else return false.
282*7c478bd9Sstevel@tonic-gate  */
283*7c478bd9Sstevel@tonic-gate bool_t
__dh_is_valid_QOP(dh_qop_t qop)284*7c478bd9Sstevel@tonic-gate __dh_is_valid_QOP(dh_qop_t qop)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	bool_t is_valid = FALSE;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	is_valid = qop < QOP_ENTRIES;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	return (is_valid);
291*7c478bd9Sstevel@tonic-gate }
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate /*
294*7c478bd9Sstevel@tonic-gate  * __alloc_sig: Allocate a signature for a given QOP. This takes into
295*7c478bd9Sstevel@tonic-gate  * account the size of the signature after padding for the encryption
296*7c478bd9Sstevel@tonic-gate  * routine.
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate OM_uint32
__alloc_sig(dh_qop_t qop,dh_signature_t sig)299*7c478bd9Sstevel@tonic-gate __alloc_sig(dh_qop_t qop, dh_signature_t sig)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat = DH_VERIFIER_FAILURE;
302*7c478bd9Sstevel@tonic-gate 	verifier_entry *v;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/* Check that the QOP is valid */
305*7c478bd9Sstevel@tonic-gate 	if (!__dh_is_valid_QOP(qop))
306*7c478bd9Sstevel@tonic-gate 		return (DH_UNKNOWN_QOP);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	/* Get the verifier entry from the QOP entry */
309*7c478bd9Sstevel@tonic-gate 	v = QOP_table[qop].verifier;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/* Calulate the length needed for the signature */
312*7c478bd9Sstevel@tonic-gate 	sig->dh_signature_len = cipher_pad(v->signer, v->size);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	/* Allocate the signature */
315*7c478bd9Sstevel@tonic-gate 	sig->dh_signature_val = (void*)New(char, sig->dh_signature_len);
316*7c478bd9Sstevel@tonic-gate 	if (sig->dh_signature_val == NULL) {
317*7c478bd9Sstevel@tonic-gate 		sig->dh_signature_len = 0;
318*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	stat = DH_SUCCESS;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	return (stat);
324*7c478bd9Sstevel@tonic-gate }
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate /*
327*7c478bd9Sstevel@tonic-gate  * __get_sig_size: Return the total size needed for a signature given a QOP.
328*7c478bd9Sstevel@tonic-gate  */
329*7c478bd9Sstevel@tonic-gate OM_uint32
__get_sig_size(dh_qop_t qop,unsigned int * size)330*7c478bd9Sstevel@tonic-gate __get_sig_size(dh_qop_t qop, unsigned int *size)
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	/* Check for valid QOP */
333*7c478bd9Sstevel@tonic-gate 	if (__dh_is_valid_QOP(qop)) {
334*7c478bd9Sstevel@tonic-gate 		/* Get the verifier entry */
335*7c478bd9Sstevel@tonic-gate 		verifier_t v = QOP_table[qop].verifier;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 		/* Return the size include the padding needed for encryption */
338*7c478bd9Sstevel@tonic-gate 		*size = v ? cipher_pad(v->signer, v->size) : 0;
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 		return (DH_SUCCESS);
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 	*size = 0;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	return (DH_UNKNOWN_QOP);
345*7c478bd9Sstevel@tonic-gate }
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate /*
348*7c478bd9Sstevel@tonic-gate  * __mk_sig: Generate a signature using a given qop over a token of a
349*7c478bd9Sstevel@tonic-gate  * given length and an optional message. We use the supplied keys to
350*7c478bd9Sstevel@tonic-gate  * encrypt the check sum if they are available. The output is place
351*7c478bd9Sstevel@tonic-gate  * in a preallocate signature, that was allocated using __alloc_sig.
352*7c478bd9Sstevel@tonic-gate  */
353*7c478bd9Sstevel@tonic-gate OM_uint32
__mk_sig(dh_qop_t qop,char * tok,long len,gss_buffer_t mesg,dh_key_set_t keys,dh_signature_t sig)354*7c478bd9Sstevel@tonic-gate __mk_sig(dh_qop_t qop, /* The QOP to use */
355*7c478bd9Sstevel@tonic-gate 	char *tok, /* The token to sign */
356*7c478bd9Sstevel@tonic-gate 	long len, /* The tokens length */
357*7c478bd9Sstevel@tonic-gate 	gss_buffer_t mesg,	/* An optional message to be included */
358*7c478bd9Sstevel@tonic-gate 	dh_key_set_t keys, /* The optional encryption keys */
359*7c478bd9Sstevel@tonic-gate 	dh_signature_t sig /* The resulting MIC */)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat = DH_VERIFIER_FAILURE;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	verifier_entry *v;	/* Verifier entry */
365*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc buf;	/* Buffer to package tok */
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	/* Make sure the QOP is valid */
368*7c478bd9Sstevel@tonic-gate 	if (!__dh_is_valid_QOP(qop))
369*7c478bd9Sstevel@tonic-gate 		return (DH_UNKNOWN_QOP);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	/* Grab the verifier entry for the qop */
372*7c478bd9Sstevel@tonic-gate 	v = QOP_table[qop].verifier;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	/* Package the token for use in a verifier_proc */
375*7c478bd9Sstevel@tonic-gate 	buf.length = len;
376*7c478bd9Sstevel@tonic-gate 	buf.value = tok;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	/*
379*7c478bd9Sstevel@tonic-gate 	 * Calculate the signature using the supplied keys. If keys
380*7c478bd9Sstevel@tonic-gate 	 * is null, the the v->signer->cipher routine will not be called
381*7c478bd9Sstevel@tonic-gate 	 * and sig will not be encrypted.
382*7c478bd9Sstevel@tonic-gate 	 */
383*7c478bd9Sstevel@tonic-gate 	stat = (*v->msg)(&buf, mesg, v->signer->cipher, keys, sig);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	return (stat);
386*7c478bd9Sstevel@tonic-gate }
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate /*
389*7c478bd9Sstevel@tonic-gate  * __verify_sig: Verify that the supplied signature, sig, is the same
390*7c478bd9Sstevel@tonic-gate  * as the token verifier
391*7c478bd9Sstevel@tonic-gate  */
392*7c478bd9Sstevel@tonic-gate OM_uint32
__verify_sig(dh_token_t token,dh_qop_t qop,dh_key_set_t keys,dh_signature_t sig)393*7c478bd9Sstevel@tonic-gate __verify_sig(dh_token_t token, /* The token to be verified */
394*7c478bd9Sstevel@tonic-gate 	    dh_qop_t qop, /* The QOP to use */
395*7c478bd9Sstevel@tonic-gate 	    dh_key_set_t keys, /* The context session keys */
396*7c478bd9Sstevel@tonic-gate 	    dh_signature_t sig /* The signature from the serialized token */)
397*7c478bd9Sstevel@tonic-gate {
398*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat = DH_VERIFIER_FAILURE;
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	cipher_proc cipher;	/* cipher routine to use */
401*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc buf;	/* Packaging for sig */
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	/* Check the QOP */
404*7c478bd9Sstevel@tonic-gate 	if (!__dh_is_valid_QOP(qop))
405*7c478bd9Sstevel@tonic-gate 		return (DH_UNKNOWN_QOP);
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	/* Package up the supplied signature */
408*7c478bd9Sstevel@tonic-gate 	buf.length = sig->dh_signature_len;
409*7c478bd9Sstevel@tonic-gate 	buf.value = sig->dh_signature_val;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	/* Get the cipher proc to use from the verifier entry for qop */
412*7c478bd9Sstevel@tonic-gate 	cipher = QOP_table[qop].verifier->signer->cipher;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	/* Encrypt the check sum using the supplied set of keys */
415*7c478bd9Sstevel@tonic-gate 	if ((stat = (*cipher)(&buf, keys, ENCIPHER)) != DH_SUCCESS)
416*7c478bd9Sstevel@tonic-gate 		return (stat);
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	/* Compare the signatures */
419*7c478bd9Sstevel@tonic-gate 	if (__cmpsig(sig, &token->verifier))
420*7c478bd9Sstevel@tonic-gate 		return (DH_SUCCESS);
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	stat = DH_VERIFIER_MISMATCH;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	return (stat);
425*7c478bd9Sstevel@tonic-gate }
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate /*
428*7c478bd9Sstevel@tonic-gate  * __cmpsig: Return true if two signatures are the same, else false.
429*7c478bd9Sstevel@tonic-gate  */
430*7c478bd9Sstevel@tonic-gate bool_t
__cmpsig(dh_signature_t s1,dh_signature_t s2)431*7c478bd9Sstevel@tonic-gate __cmpsig(dh_signature_t s1, dh_signature_t s2)
432*7c478bd9Sstevel@tonic-gate {
433*7c478bd9Sstevel@tonic-gate 	return (s1->dh_signature_len == s2->dh_signature_len &&
434*7c478bd9Sstevel@tonic-gate 	    memcmp(s1->dh_signature_val,
435*7c478bd9Sstevel@tonic-gate 		s2->dh_signature_val, s1->dh_signature_len) == 0);
436*7c478bd9Sstevel@tonic-gate }
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate /*
439*7c478bd9Sstevel@tonic-gate  * wrap_msg_body: Wrap the message pointed to be in into a
440*7c478bd9Sstevel@tonic-gate  * message pointed to by out that has ben padded out by pad bytes.
441*7c478bd9Sstevel@tonic-gate  *
442*7c478bd9Sstevel@tonic-gate  * The output message looks like:
443*7c478bd9Sstevel@tonic-gate  * out->length = total length of out->value including any padding
444*7c478bd9Sstevel@tonic-gate  * out->value points to memory as follows:
445*7c478bd9Sstevel@tonic-gate  * +------------+-------------------------+---------|
446*7c478bd9Sstevel@tonic-gate  * | in->length | in->value               | XDR PAD |
447*7c478bd9Sstevel@tonic-gate  * +------------+-------------------------+---------|
448*7c478bd9Sstevel@tonic-gate  *    4 bytes      in->length bytes         0 - 3
449*7c478bd9Sstevel@tonic-gate  */
450*7c478bd9Sstevel@tonic-gate static OM_uint32
wrap_msg_body(gss_buffer_t in,gss_buffer_t out)451*7c478bd9Sstevel@tonic-gate wrap_msg_body(gss_buffer_t in, gss_buffer_t out)
452*7c478bd9Sstevel@tonic-gate {
453*7c478bd9Sstevel@tonic-gate 	XDR xdrs;			/* xdrs to wrap with */
454*7c478bd9Sstevel@tonic-gate 	unsigned int len, out_len;	/* length  */
455*7c478bd9Sstevel@tonic-gate 	size_t size;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	out->length = 0;
458*7c478bd9Sstevel@tonic-gate 	out->value = 0;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	/* Make sure the address of len points to a 32 bit word */
461*7c478bd9Sstevel@tonic-gate 	len = (unsigned int)in->length;
462*7c478bd9Sstevel@tonic-gate 	if (len != in->length)
463*7c478bd9Sstevel@tonic-gate 		return (DH_ENCODE_FAILURE);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	size = ((in->length + sizeof (OM_uint32) + 3)/4) * 4;
466*7c478bd9Sstevel@tonic-gate 	out_len = size;
467*7c478bd9Sstevel@tonic-gate 	if (out_len != size)
468*7c478bd9Sstevel@tonic-gate 		return (DH_ENCODE_FAILURE);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	/* Allocate the output buffer and set the length */
471*7c478bd9Sstevel@tonic-gate 	if ((out->value = (void *)New(char, len)) == NULL)
472*7c478bd9Sstevel@tonic-gate 		return (DH_NOMEM_FAILURE);
473*7c478bd9Sstevel@tonic-gate 	out->length = out_len;
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	/* Create xdr stream to wrap into */
477*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, out->value, out->length, XDR_ENCODE);
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	/* Wrap the bytes in value */
480*7c478bd9Sstevel@tonic-gate 	if (!xdr_bytes(&xdrs, (char **)&in->value, &len, len)) {
481*7c478bd9Sstevel@tonic-gate 		__dh_release_buffer(out);
482*7c478bd9Sstevel@tonic-gate 		return (DH_ENCODE_FAILURE);
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
486*7c478bd9Sstevel@tonic-gate }
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate /*
489*7c478bd9Sstevel@tonic-gate  * __QOPSeal: Wrap the input message placing the output in output given
490*7c478bd9Sstevel@tonic-gate  * a valid QOP. If confidentialiy is requested it is ignored. We can't
491*7c478bd9Sstevel@tonic-gate  * support privacy. The return flag will always be zero.
492*7c478bd9Sstevel@tonic-gate  */
493*7c478bd9Sstevel@tonic-gate OM_uint32
__QOPSeal(dh_qop_t qop,gss_buffer_t input,int conf_req,dh_key_set_t keys,gss_buffer_t output,int * conf_ret)494*7c478bd9Sstevel@tonic-gate __QOPSeal(dh_qop_t qop, /* The QOP to use */
495*7c478bd9Sstevel@tonic-gate 	gss_buffer_t input, /* The buffer to wrap */
496*7c478bd9Sstevel@tonic-gate 	int conf_req, /* Do we want privacy ? */
497*7c478bd9Sstevel@tonic-gate 	dh_key_set_t keys, /* The session keys */
498*7c478bd9Sstevel@tonic-gate 	gss_buffer_t output, /* The wraped message */
499*7c478bd9Sstevel@tonic-gate 	int *conf_ret /* Did we encrypt it? */)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(conf_req,keys))
502*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat = DH_CIPHER_FAILURE;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	*conf_ret = FALSE;	/* No encryption allowed */
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	/* Check for valid QOP */
507*7c478bd9Sstevel@tonic-gate 	if (!__dh_is_valid_QOP(qop))
508*7c478bd9Sstevel@tonic-gate 		return (DH_UNKNOWN_QOP);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	/* Wrap the message */
511*7c478bd9Sstevel@tonic-gate 	if ((stat = wrap_msg_body(input, output))
512*7c478bd9Sstevel@tonic-gate 	    != DH_SUCCESS)
513*7c478bd9Sstevel@tonic-gate 		return (stat);
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	return (stat);
516*7c478bd9Sstevel@tonic-gate }
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate /*
519*7c478bd9Sstevel@tonic-gate  * unwrap_msg_body: Unwrap the message, that was wrapped from above
520*7c478bd9Sstevel@tonic-gate  */
521*7c478bd9Sstevel@tonic-gate static OM_uint32
unwrap_msg_body(gss_buffer_t in,gss_buffer_t out)522*7c478bd9Sstevel@tonic-gate unwrap_msg_body(gss_buffer_t in, gss_buffer_t out)
523*7c478bd9Sstevel@tonic-gate {
524*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
525*7c478bd9Sstevel@tonic-gate 	unsigned int len;	/* sizeof (len) == 32bits */
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	/* Create an xdr stream to on wrap in */
528*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, in->value, in->length, XDR_DECODE);
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	/* Unwrap the input into out->value */
531*7c478bd9Sstevel@tonic-gate 	if (!xdr_bytes(&xdrs, (char **)&out->value, &len, in->length))
532*7c478bd9Sstevel@tonic-gate 		return (DH_DECODE_FAILURE);
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	/* set the length */
535*7c478bd9Sstevel@tonic-gate 	out->length = len;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	return (DH_SUCCESS);
538*7c478bd9Sstevel@tonic-gate }
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate /*
541*7c478bd9Sstevel@tonic-gate  * __QOPUnSeal: Unwrap the input message into output using the supplied QOP.
542*7c478bd9Sstevel@tonic-gate  * Note it is the callers responsibility to release the allocated output
543*7c478bd9Sstevel@tonic-gate  * buffer. If conf_req is true we return DH_CIPHER_FAILURE since we don't
544*7c478bd9Sstevel@tonic-gate  * support privacy.
545*7c478bd9Sstevel@tonic-gate  */
546*7c478bd9Sstevel@tonic-gate OM_uint32
__QOPUnSeal(dh_qop_t qop,gss_buffer_t input,int conf_req,dh_key_set_t keys,gss_buffer_t output)547*7c478bd9Sstevel@tonic-gate __QOPUnSeal(dh_qop_t qop, /* The QOP to use */
548*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t input, /* The message to unwrap */
549*7c478bd9Sstevel@tonic-gate 	    int conf_req, /* Is the message encrypted */
550*7c478bd9Sstevel@tonic-gate 	    dh_key_set_t keys, /* The session keys to decrypt if conf_req */
551*7c478bd9Sstevel@tonic-gate 	    gss_buffer_t output /* The unwraped message */)
552*7c478bd9Sstevel@tonic-gate {
553*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(keys))
554*7c478bd9Sstevel@tonic-gate 	OM_uint32 stat = DH_CIPHER_FAILURE;
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	/* Check that the qop is valid */
557*7c478bd9Sstevel@tonic-gate 	if (!__dh_is_valid_QOP(qop))
558*7c478bd9Sstevel@tonic-gate 		return (DH_UNKNOWN_QOP);
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	/* Set output to sane values */
561*7c478bd9Sstevel@tonic-gate 	output->length = 0;
562*7c478bd9Sstevel@tonic-gate 	output->value = NULL;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	/* Fail if this is privacy */
565*7c478bd9Sstevel@tonic-gate 	if (conf_req)
566*7c478bd9Sstevel@tonic-gate 		return (DH_CIPHER_FAILURE);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	/* Unwrap the input into the output, return the status */
569*7c478bd9Sstevel@tonic-gate 	stat = unwrap_msg_body(input, output);
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	return (stat);
572*7c478bd9Sstevel@tonic-gate }
573