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