xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/dk/checksum.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
6 
7 /*
8  * Copyright (C) 1998 by the FundsXpress, INC.
9  *
10  * All rights reserved.
11  *
12  * Export of this software from the United States of America may require
13  * a specific license from the United States Government.  It is the
14  * responsibility of any person or organization contemplating export to
15  * obtain such a license before exporting.
16  *
17  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18  * distribute this software and its documentation for any purpose and
19  * without fee is hereby granted, provided that the above copyright
20  * notice appear in all copies and that both that copyright notice and
21  * this permission notice appear in supporting documentation, and that
22  * the name of FundsXpress. not be used in advertising or publicity pertaining
23  * to distribution of the software without specific, written prior
24  * permission.  FundsXpress makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is" without express
26  * or implied warranty.
27  *
28  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31  */
32 
33 #include <k5-int.h>
34 #include <etypes.h>
35 #include <dk.h>
36 
37 #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
38 
39 /*
40  * Derive the key for checksum calculation.
41  * This is only called (currently) for SHA1-DES3
42  * checksum types.
43  *
44  * The primary benefit here is that a KEF template
45  * is created for use when doing the HMAC operation which
46  * saves ALOT of computation cycles and improves performance.
47  */
48 static krb5_error_code
49 derive_cksum_key(krb5_context context,
50 		struct krb5_enc_provider *enc,
51 		const krb5_keyblock *key,
52 		krb5_keyusage usage,
53 		krb5_keyblock **outkey)
54 {
55 	krb5_error_code ret = 0;
56 	krb5_keyblock *cached_key = NULL;
57 	krb5_data d1;
58 	unsigned char constantdata[K5CLENGTH];
59 
60 	cached_key = find_derived_key(usage, DK_CKSUM_KEY_BYTE,
61 				    (krb5_keyblock *)key);
62 	if (cached_key)
63 		*outkey = cached_key;
64 	else {
65 		*outkey = krb5_create_derived_keyblock(key->length);
66 		if (*outkey == NULL)
67 			return (ENOMEM);
68 
69 		constantdata[0] = (usage>>24)&0xff;
70 		constantdata[1] = (usage>>16)&0xff;
71 		constantdata[2] = (usage>>8)&0xff;
72 		constantdata[3] = usage&0xff;
73 		constantdata[4] = DK_CKSUM_KEY_BYTE;
74 
75 		d1.data = (char *)constantdata;
76 		d1.length = sizeof(constantdata);
77 
78 		ret = krb5_derive_key(context, enc, key,
79 				    *outkey, &d1);
80 		if (ret) {
81 			krb5_free_keyblock(context, *outkey);
82 			*outkey = NULL;
83 			return (ret);
84 		}
85 #ifdef _KERNEL
86 		/*
87 		 * By default, derived keys get the "mech_type"
88 		 * that was associated with their parent.
89 		 * we need to switch the mech_type to correspond
90 		 * to the checksum mech type.
91 		 */
92 		if (ret == 0 &&
93 		    (*outkey)->kef_mt != context->kef_cksum_mt) {
94 			(*outkey)->kef_mt = context->kef_cksum_mt;
95 			if ((*outkey)->key_tmpl != NULL) {
96 				crypto_destroy_ctx_template((*outkey)->key_tmpl);
97 				(*outkey)->key_tmpl = NULL;
98 			}
99 			ret = update_key_template(*outkey);
100 		}
101 #endif /* _KERNEL */
102 		if (ret == 0)
103 			ret = add_derived_key((krb5_keyblock *)key, usage,
104 			    DK_CKSUM_KEY_BYTE,
105 			    *outkey);
106 	}
107 finish:
108 	KRB5_LOG0(KRB5_INFO, "derive_cksum_key() end.");
109 	return (ret);
110 }
111 
112 /* ARGSUSED */
113 krb5_error_code
114 krb5_dk_make_checksum(context, hash, key, usage, input, output)
115      krb5_context context;
116      krb5_const struct krb5_hash_provider *hash;
117      krb5_const krb5_keyblock *key;
118      krb5_keyusage usage;
119      krb5_const krb5_data *input;
120      krb5_data *output;
121 {
122     int i;
123     krb5_error_code ret;
124     krb5_keyblock *cksum_key = NULL;
125     struct krb5_enc_provider *enc = NULL;
126 
127     KRB5_LOG0(KRB5_INFO, "krb5_dk_make_checksum() start");
128 
129     for (i=0; i<krb5_enctypes_length; i++) {
130 	if (krb5_enctypes_list[i].etype == key->enctype)
131 	    break;
132     }
133     if (i == krb5_enctypes_length) {
134 	KRB5_LOG(KRB5_ERR, "krb5_ck_make_checksum bad enctype: %d",
135 		key->enctype);
136 	return(KRB5_BAD_ENCTYPE);
137     }
138     enc = (struct krb5_enc_provider *)krb5_enctypes_list[i].enc;
139 
140 #ifdef _KERNEL
141     if (key->kef_key.ck_data == NULL &&
142 	(ret = init_key_kef(krb5_enctypes_list[i].kef_cipher_mt,
143 			    (krb5_keyblock *)key)))
144 	    goto cleanup;
145 #endif
146     ret = derive_cksum_key(context, enc, key, usage, &cksum_key);
147     if (ret != 0)
148 	    goto cleanup;
149 
150 #ifdef _KERNEL
151     if ((ret = krb5_hmac(context, (krb5_keyblock *)cksum_key,
152 			input, output))) {
153 	KRB5_LOG(KRB5_ERR, "krb5_hmac error: %0x", ret);
154 	(void) memset(output->data, 0, output->length);
155     }
156 #else
157     if ((ret = krb5_hmac(context, hash, cksum_key, 1, input, output)) != 0) {
158 	KRB5_LOG(KRB5_ERR, "krb5_hmac error: %0x", ret);
159 	(void) memset(output->data, 0, output->length);
160     }
161 #endif /* _KERNEL */
162 cleanup:
163 
164     KRB5_LOG0(KRB5_INFO, "krb5_dk_make_checksum() end");
165     return(ret);
166 }
167 
168