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