17c478bd9Sstevel@tonic-gate /* 2*505d05c7Sgtb * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate /* 97c478bd9Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 107c478bd9Sstevel@tonic-gate * 117c478bd9Sstevel@tonic-gate * All rights reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may require 147c478bd9Sstevel@tonic-gate * a specific license from the United States Government. It is the 157c478bd9Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 167c478bd9Sstevel@tonic-gate * obtain such a license before exporting. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 197c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 207c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 217c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 227c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 237c478bd9Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 247c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 257c478bd9Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 267c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 277c478bd9Sstevel@tonic-gate * or implied warranty. 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 307c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 317c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* Solaris Kerberos: 357c478bd9Sstevel@tonic-gate * this code is based on the 367c478bd9Sstevel@tonic-gate * usr/src/lib/gss_mechs/mech_krb5/crypto/keyhash_provider/k5_md5des.c 377c478bd9Sstevel@tonic-gate * file, but has been modified to use the Solaris resident md5.o kernel 387c478bd9Sstevel@tonic-gate * module and associated header /usr/include/sys/md5.o. 397c478bd9Sstevel@tonic-gate * This means that the MD5* functions are called instead of krb5_MD5*. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <krb5.h> 437c478bd9Sstevel@tonic-gate #include <des_int.h> 447c478bd9Sstevel@tonic-gate #include <keyhash_provider.h> 457c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 467c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #define CONFLENGTH 8 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* Force acceptance of krb5-beta5 md5des checksum for now. */ 517c478bd9Sstevel@tonic-gate #define KRB5_MD5DES_BETA5_COMPAT 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* des-cbc(xorkey, conf | rsa-md5(conf | data)) */ 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* this could be done in terms of the md5 and des providers, but 567c478bd9Sstevel@tonic-gate that's less efficient, and there's no need for this to be generic */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 597c478bd9Sstevel@tonic-gate static krb5_error_code 607c478bd9Sstevel@tonic-gate k5_md5des_hash(krb5_context context, 617c478bd9Sstevel@tonic-gate krb5_const krb5_keyblock *key, 627c478bd9Sstevel@tonic-gate krb5_keyusage usage, 637c478bd9Sstevel@tonic-gate krb5_const krb5_data *ivec, 647c478bd9Sstevel@tonic-gate krb5_const krb5_data *input, krb5_data *output) 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate krb5_error_code ret = 0; 677c478bd9Sstevel@tonic-gate krb5_data data; 687c478bd9Sstevel@tonic-gate unsigned char conf[CONFLENGTH]; 697c478bd9Sstevel@tonic-gate unsigned char xorkey[MIT_DES_KEYSIZE]; 707c478bd9Sstevel@tonic-gate int i; 717c478bd9Sstevel@tonic-gate krb5_data *hash_input; 727c478bd9Sstevel@tonic-gate char *outptr; 737c478bd9Sstevel@tonic-gate krb5_keyblock newkey; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate if (key->length != MIT_DES_KEYSIZE) 767c478bd9Sstevel@tonic-gate return(KRB5_BAD_KEYSIZE); 777c478bd9Sstevel@tonic-gate if (ivec) 787c478bd9Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL); 797c478bd9Sstevel@tonic-gate if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) 807c478bd9Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* create the confounder */ 837c478bd9Sstevel@tonic-gate data.length = CONFLENGTH; 847c478bd9Sstevel@tonic-gate data.data = (char *) conf; 857c478bd9Sstevel@tonic-gate if ((ret = krb5_c_random_make_octets(context, &data))) 867c478bd9Sstevel@tonic-gate return(ret); 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* hash the confounder, then the input data */ 897c478bd9Sstevel@tonic-gate hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2); 907c478bd9Sstevel@tonic-gate if (hash_input == NULL) 917c478bd9Sstevel@tonic-gate return(KRB5_RC_MALLOC); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate hash_input[0].data = (char *)conf; 947c478bd9Sstevel@tonic-gate hash_input[0].length = CONFLENGTH; 957c478bd9Sstevel@tonic-gate hash_input[1].data = input->data; 967c478bd9Sstevel@tonic-gate hash_input[1].length = input->length; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* Save the pointer to the beginning of the output buffer */ 997c478bd9Sstevel@tonic-gate outptr = (char *)output->data; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Move the output ptr ahead so we can write the hash 1037c478bd9Sstevel@tonic-gate * digest directly into the buffer. 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate output->data = output->data + CONFLENGTH; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* Use generic hash function that calls to kEF */ 1087c478bd9Sstevel@tonic-gate if (k5_ef_hash(context, 2, hash_input, output)) { 1097c478bd9Sstevel@tonic-gate FREE(hash_input, sizeof(krb5_data) * 2); 1107c478bd9Sstevel@tonic-gate return(KRB5_KEF_ERROR); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* restore the original ptr to the output data */ 1147c478bd9Sstevel@tonic-gate output->data = outptr; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* 1177c478bd9Sstevel@tonic-gate * Put the confounder in the beginning of the buffer to be 1187c478bd9Sstevel@tonic-gate * encrypted. 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate bcopy(conf, output->data, CONFLENGTH); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate bcopy(key->contents, xorkey, sizeof(xorkey)); 1237c478bd9Sstevel@tonic-gate for (i=0; i<sizeof(xorkey); i++) 1247c478bd9Sstevel@tonic-gate xorkey[i] ^= 0xf0; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * Solaris Kerberos: 1287c478bd9Sstevel@tonic-gate * Encryption Framework checks for parity and weak keys. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate bzero(&newkey, sizeof(krb5_keyblock)); 1317c478bd9Sstevel@tonic-gate newkey.enctype = key->enctype; 1327c478bd9Sstevel@tonic-gate newkey.contents = xorkey; 1337c478bd9Sstevel@tonic-gate newkey.length = sizeof(xorkey); 1347c478bd9Sstevel@tonic-gate newkey.dk_list = NULL; 1357c478bd9Sstevel@tonic-gate newkey.kef_key.ck_data = NULL; 1367c478bd9Sstevel@tonic-gate ret = init_key_kef(context->kef_cipher_mt, &newkey); 1377c478bd9Sstevel@tonic-gate if (ret) { 1387c478bd9Sstevel@tonic-gate FREE(hash_input, sizeof(krb5_data) * 2); 1397c478bd9Sstevel@tonic-gate return (ret); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* encrypt it, in place. this has a return value, but it's 1437c478bd9Sstevel@tonic-gate always zero. */ 1447c478bd9Sstevel@tonic-gate ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data, 1457c478bd9Sstevel@tonic-gate (krb5_pointer) output->data, output->length, 1467c478bd9Sstevel@tonic-gate &newkey, (unsigned char*) mit_des_zeroblock, 1); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate FREE(hash_input, sizeof(krb5_data) * 2); 1497c478bd9Sstevel@tonic-gate (void)crypto_destroy_ctx_template(newkey.key_tmpl); 1507c478bd9Sstevel@tonic-gate return(ret); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1547c478bd9Sstevel@tonic-gate static krb5_error_code 1557c478bd9Sstevel@tonic-gate k5_md5des_verify(krb5_context context, 1567c478bd9Sstevel@tonic-gate krb5_const krb5_keyblock *key, 1577c478bd9Sstevel@tonic-gate krb5_keyusage usage, 1587c478bd9Sstevel@tonic-gate krb5_const krb5_data *ivec, 1597c478bd9Sstevel@tonic-gate krb5_const krb5_data *input, 1607c478bd9Sstevel@tonic-gate krb5_const krb5_data *hash, 1617c478bd9Sstevel@tonic-gate krb5_boolean *valid) 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate krb5_error_code ret = 0; 1647c478bd9Sstevel@tonic-gate unsigned char plaintext[CONFLENGTH + MD5_CKSUM_LENGTH]; 1657c478bd9Sstevel@tonic-gate unsigned char xorkey[8]; 1667c478bd9Sstevel@tonic-gate int i; 1677c478bd9Sstevel@tonic-gate int compathash = 0; 1687c478bd9Sstevel@tonic-gate krb5_octet outtmp[MD5_CKSUM_LENGTH]; 1697c478bd9Sstevel@tonic-gate size_t hisize; 1707c478bd9Sstevel@tonic-gate krb5_data *hash_input; 1717c478bd9Sstevel@tonic-gate krb5_data hash_output; 1727c478bd9Sstevel@tonic-gate krb5_keyblock newkey; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (key->length != MIT_DES_KEYSIZE) 1757c478bd9Sstevel@tonic-gate return(KRB5_BAD_KEYSIZE); 1767c478bd9Sstevel@tonic-gate if (ivec) 1777c478bd9Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL); 1787c478bd9Sstevel@tonic-gate if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) { 1797c478bd9Sstevel@tonic-gate #ifdef KRB5_MD5DES_BETA5_COMPAT 1807c478bd9Sstevel@tonic-gate if (hash->length != MD5_CKSUM_LENGTH) 1817c478bd9Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL); 1827c478bd9Sstevel@tonic-gate else 1837c478bd9Sstevel@tonic-gate compathash = 1; 1847c478bd9Sstevel@tonic-gate #else 1857c478bd9Sstevel@tonic-gate return(KRB5_CRYPTO_INTERNAL); 1867c478bd9Sstevel@tonic-gate #endif 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* create and schedule the encryption key */ 1907c478bd9Sstevel@tonic-gate (void) bcopy(key->contents, xorkey, sizeof(xorkey)); 1917c478bd9Sstevel@tonic-gate if (!compathash) { 1927c478bd9Sstevel@tonic-gate for (i=0; i<sizeof(xorkey); i++) 1937c478bd9Sstevel@tonic-gate xorkey[i] ^= 0xf0; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Solaris Kerberos: 1987c478bd9Sstevel@tonic-gate * Encryption Framework checks for parity and weak keys 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate bzero(&newkey, sizeof(krb5_keyblock)); 2017c478bd9Sstevel@tonic-gate newkey.enctype = key->enctype; 2027c478bd9Sstevel@tonic-gate newkey.contents = xorkey; 2037c478bd9Sstevel@tonic-gate newkey.length = sizeof(xorkey); 2047c478bd9Sstevel@tonic-gate newkey.dk_list = NULL; 2057c478bd9Sstevel@tonic-gate newkey.kef_key.ck_data = NULL; 2067c478bd9Sstevel@tonic-gate ret = init_key_kef(context->kef_cipher_mt, &newkey); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* decrypt it. this has a return value, but it's always zero. */ 2097c478bd9Sstevel@tonic-gate if (!compathash) { 2107c478bd9Sstevel@tonic-gate ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, 2117c478bd9Sstevel@tonic-gate (krb5_pointer) plaintext, hash->length, 2127c478bd9Sstevel@tonic-gate &newkey, (unsigned char*) mit_des_zeroblock, 0); 2137c478bd9Sstevel@tonic-gate } else { 2147c478bd9Sstevel@tonic-gate ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, 2157c478bd9Sstevel@tonic-gate (krb5_pointer) plaintext, hash->length, 2167c478bd9Sstevel@tonic-gate &newkey, xorkey, 0); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate if (ret) goto cleanup; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* hash the confounder, then the input data */ 2217c478bd9Sstevel@tonic-gate i = 1; 2227c478bd9Sstevel@tonic-gate if (!compathash) 2237c478bd9Sstevel@tonic-gate i++; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate hisize = sizeof(krb5_data) * i; 2267c478bd9Sstevel@tonic-gate hash_input = (krb5_data *)MALLOC(hisize); 2277c478bd9Sstevel@tonic-gate if (hash_input == NULL) 2287c478bd9Sstevel@tonic-gate return(KRB5_RC_MALLOC); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate i=0; 2317c478bd9Sstevel@tonic-gate if (!compathash) { 2327c478bd9Sstevel@tonic-gate hash_input[i].data = (char *)plaintext; 2337c478bd9Sstevel@tonic-gate hash_input[i].length = CONFLENGTH; 2347c478bd9Sstevel@tonic-gate i++; 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate hash_input[i].data = input->data; 2377c478bd9Sstevel@tonic-gate hash_input[i].length = input->length; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate hash_output.data = (char *)outtmp; 2407c478bd9Sstevel@tonic-gate hash_output.length = sizeof(outtmp); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if (k5_ef_hash(context, 1, hash_input, &hash_output)) { 2437c478bd9Sstevel@tonic-gate ret = KRB5_KEF_ERROR; 2447c478bd9Sstevel@tonic-gate goto cleanup; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* compare the decrypted hash to the computed one */ 2487c478bd9Sstevel@tonic-gate if (!compathash) { 2497c478bd9Sstevel@tonic-gate *valid = !bcmp((const void *)(plaintext+CONFLENGTH), 2507c478bd9Sstevel@tonic-gate (void *)outtmp, MD5_CKSUM_LENGTH); 2517c478bd9Sstevel@tonic-gate } else { 2527c478bd9Sstevel@tonic-gate *valid = !bcmp((const void *)plaintext, 2537c478bd9Sstevel@tonic-gate (void *)outtmp, MD5_CKSUM_LENGTH); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate bzero((void *)plaintext, sizeof(plaintext)); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate cleanup: 2587c478bd9Sstevel@tonic-gate if (hash_input != NULL && hisize > 0) 2597c478bd9Sstevel@tonic-gate FREE(hash_input, hisize); 2607c478bd9Sstevel@tonic-gate (void)crypto_destroy_ctx_template(newkey.key_tmpl); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate return(ret); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate const struct krb5_keyhash_provider krb5_keyhash_md5des = { 266*505d05c7Sgtb CONFLENGTH+MD5_CKSUM_LENGTH, 2677c478bd9Sstevel@tonic-gate k5_md5des_hash, 2687c478bd9Sstevel@tonic-gate k5_md5des_verify 2697c478bd9Sstevel@tonic-gate }; 270