1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 5 * Authors: Doug Rabson <dfr@rabson.org> 6 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/malloc.h> 35 #include <sys/kobj.h> 36 #include <sys/mbuf.h> 37 38 #include <kgssapi/gssapi.h> 39 #include <kgssapi/gssapi_impl.h> 40 41 #include "kcrypto.h" 42 43 static struct krb5_encryption_class *krb5_encryption_classes[] = { 44 &krb5_des_encryption_class, 45 &krb5_des3_encryption_class, 46 &krb5_aes128_encryption_class, 47 &krb5_aes256_encryption_class, 48 &krb5_arcfour_encryption_class, 49 &krb5_arcfour_56_encryption_class, 50 NULL 51 }; 52 53 struct krb5_encryption_class * 54 krb5_find_encryption_class(int etype) 55 { 56 int i; 57 58 for (i = 0; krb5_encryption_classes[i]; i++) { 59 if (krb5_encryption_classes[i]->ec_type == etype) 60 return (krb5_encryption_classes[i]); 61 } 62 return (NULL); 63 } 64 65 struct krb5_key_state * 66 krb5_create_key(const struct krb5_encryption_class *ec) 67 { 68 struct krb5_key_state *ks; 69 70 ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK); 71 ks->ks_class = ec; 72 refcount_init(&ks->ks_refs, 1); 73 ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK); 74 ec->ec_init(ks); 75 76 return (ks); 77 } 78 79 void 80 krb5_free_key(struct krb5_key_state *ks) 81 { 82 83 if (refcount_release(&ks->ks_refs)) { 84 ks->ks_class->ec_destroy(ks); 85 bzero(ks->ks_key, ks->ks_class->ec_keylen); 86 free(ks->ks_key, M_GSSAPI); 87 free(ks, M_GSSAPI); 88 } 89 } 90 91 static size_t 92 gcd(size_t a, size_t b) 93 { 94 95 if (b == 0) 96 return (a); 97 return gcd(b, a % b); 98 } 99 100 static size_t 101 lcm(size_t a, size_t b) 102 { 103 return ((a * b) / gcd(a, b)); 104 } 105 106 /* 107 * Rotate right 13 of a variable precision number in 'in', storing the 108 * result in 'out'. The number is assumed to be big-endian in memory 109 * representation. 110 */ 111 static void 112 krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen) 113 { 114 uint32_t carry; 115 size_t i; 116 117 /* 118 * Special case when numlen == 1. A rotate right 13 of a 119 * single byte number changes to a rotate right 5. 120 */ 121 if (numlen == 1) { 122 carry = in[0] >> 5; 123 out[0] = (in[0] << 3) | carry; 124 return; 125 } 126 127 carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1]; 128 for (i = 2; i < numlen; i++) { 129 out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5); 130 } 131 out[1] = ((carry & 31) << 3) | (in[0] >> 5); 132 out[0] = carry >> 5; 133 } 134 135 /* 136 * Add two variable precision numbers in big-endian representation 137 * using ones-complement arithmetic. 138 */ 139 static void 140 krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len) 141 { 142 int n, i; 143 144 /* 145 * First calculate the 2s complement sum, remembering the 146 * carry. 147 */ 148 n = 0; 149 for (i = len - 1; i >= 0; i--) { 150 n = out[i] + in[i] + n; 151 out[i] = n; 152 n >>= 8; 153 } 154 /* 155 * Then add back the carry. 156 */ 157 for (i = len - 1; n && i >= 0; i--) { 158 n = out[i] + n; 159 out[i] = n; 160 n >>= 8; 161 } 162 } 163 164 static void 165 krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) 166 { 167 size_t tmplen; 168 uint8_t *tmp; 169 size_t i; 170 uint8_t *p; 171 172 tmplen = lcm(inlen, outlen); 173 tmp = malloc(tmplen, M_GSSAPI, M_WAITOK); 174 175 bcopy(in, tmp, inlen); 176 for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) { 177 krb5_rotate_right_13(p + inlen, p, inlen); 178 } 179 bzero(out, outlen); 180 for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) { 181 krb5_ones_complement_add(out, p, outlen); 182 } 183 free(tmp, M_GSSAPI); 184 } 185 186 struct krb5_key_state * 187 krb5_derive_key(struct krb5_key_state *inkey, 188 void *constant, size_t constantlen) 189 { 190 struct krb5_key_state *dk; 191 const struct krb5_encryption_class *ec = inkey->ks_class; 192 uint8_t *folded; 193 uint8_t *bytes, *p, *q; 194 struct mbuf *m; 195 int randomlen, i; 196 197 /* 198 * Expand the constant to blocklen bytes. 199 */ 200 folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK); 201 krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen); 202 203 /* 204 * Generate enough bytes for keybits rounded up to a multiple 205 * of blocklen. 206 */ 207 randomlen = roundup(ec->ec_keybits / 8, ec->ec_blocklen); 208 bytes = malloc(randomlen, M_GSSAPI, M_WAITOK); 209 MGET(m, M_WAITOK, MT_DATA); 210 m->m_len = ec->ec_blocklen; 211 for (i = 0, p = bytes, q = folded; i < randomlen; 212 q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) { 213 bcopy(q, m->m_data, ec->ec_blocklen); 214 krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0); 215 bcopy(m->m_data, p, ec->ec_blocklen); 216 } 217 m_free(m); 218 219 dk = krb5_create_key(ec); 220 krb5_random_to_key(dk, bytes); 221 222 free(folded, M_GSSAPI); 223 free(bytes, M_GSSAPI); 224 225 return (dk); 226 } 227 228 static struct krb5_key_state * 229 krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which) 230 { 231 const struct krb5_encryption_class *ec = basekey->ks_class; 232 233 if (ec->ec_flags & EC_DERIVED_KEYS) { 234 uint8_t constant[5]; 235 236 constant[0] = usage >> 24; 237 constant[1] = usage >> 16; 238 constant[2] = usage >> 8; 239 constant[3] = usage; 240 constant[4] = which; 241 return (krb5_derive_key(basekey, constant, 5)); 242 } else { 243 refcount_acquire(&basekey->ks_refs); 244 return (basekey); 245 } 246 } 247 248 struct krb5_key_state * 249 krb5_get_encryption_key(struct krb5_key_state *basekey, int usage) 250 { 251 252 return (krb5_get_usage_key(basekey, usage, 0xaa)); 253 } 254 255 struct krb5_key_state * 256 krb5_get_integrity_key(struct krb5_key_state *basekey, int usage) 257 { 258 259 return (krb5_get_usage_key(basekey, usage, 0x55)); 260 } 261 262 struct krb5_key_state * 263 krb5_get_checksum_key(struct krb5_key_state *basekey, int usage) 264 { 265 266 return (krb5_get_usage_key(basekey, usage, 0x99)); 267 } 268