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