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 #include <sys/sysctl.h> 38 39 #include <kgssapi/gssapi.h> 40 #include <kgssapi/gssapi_impl.h> 41 42 #include "kcrypto.h" 43 44 static struct krb5_encryption_class *krb5_encryption_classes[] = { 45 &krb5_aes128_encryption_class, 46 &krb5_aes256_encryption_class, 47 NULL 48 }; 49 50 struct krb5_encryption_class * 51 krb5_find_encryption_class(int etype) 52 { 53 int i; 54 55 for (i = 0; krb5_encryption_classes[i]; i++) { 56 if (krb5_encryption_classes[i]->ec_type == etype) 57 return (krb5_encryption_classes[i]); 58 } 59 return (NULL); 60 } 61 62 struct krb5_key_state * 63 krb5_create_key(const struct krb5_encryption_class *ec) 64 { 65 struct krb5_key_state *ks; 66 67 ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK); 68 ks->ks_class = ec; 69 refcount_init(&ks->ks_refs, 1); 70 ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK); 71 ec->ec_init(ks); 72 73 return (ks); 74 } 75 76 void 77 krb5_free_key(struct krb5_key_state *ks) 78 { 79 80 if (refcount_release(&ks->ks_refs)) { 81 ks->ks_class->ec_destroy(ks); 82 bzero(ks->ks_key, ks->ks_class->ec_keylen); 83 free(ks->ks_key, M_GSSAPI); 84 free(ks, M_GSSAPI); 85 } 86 } 87 88 static size_t 89 gcd(size_t a, size_t b) 90 { 91 92 if (b == 0) 93 return (a); 94 return gcd(b, a % b); 95 } 96 97 static size_t 98 lcm(size_t a, size_t b) 99 { 100 return ((a * b) / gcd(a, b)); 101 } 102 103 /* 104 * Rotate right 13 of a variable precision number in 'in', storing the 105 * result in 'out'. The number is assumed to be big-endian in memory 106 * representation. 107 */ 108 static void 109 krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen) 110 { 111 uint32_t carry; 112 size_t i; 113 114 /* 115 * Special case when numlen == 1. A rotate right 13 of a 116 * single byte number changes to a rotate right 5. 117 */ 118 if (numlen == 1) { 119 carry = in[0] >> 5; 120 out[0] = (in[0] << 3) | carry; 121 return; 122 } 123 124 carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1]; 125 for (i = 2; i < numlen; i++) { 126 out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5); 127 } 128 out[1] = ((carry & 31) << 3) | (in[0] >> 5); 129 out[0] = carry >> 5; 130 } 131 132 /* 133 * Add two variable precision numbers in big-endian representation 134 * using ones-complement arithmetic. 135 */ 136 static void 137 krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len) 138 { 139 int n, i; 140 141 /* 142 * First calculate the 2s complement sum, remembering the 143 * carry. 144 */ 145 n = 0; 146 for (i = len - 1; i >= 0; i--) { 147 n = out[i] + in[i] + n; 148 out[i] = n; 149 n >>= 8; 150 } 151 /* 152 * Then add back the carry. 153 */ 154 for (i = len - 1; n && i >= 0; i--) { 155 n = out[i] + n; 156 out[i] = n; 157 n >>= 8; 158 } 159 } 160 161 static void 162 krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) 163 { 164 size_t tmplen; 165 uint8_t *tmp; 166 size_t i; 167 uint8_t *p; 168 169 tmplen = lcm(inlen, outlen); 170 tmp = malloc(tmplen, M_GSSAPI, M_WAITOK); 171 172 bcopy(in, tmp, inlen); 173 for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) { 174 krb5_rotate_right_13(p + inlen, p, inlen); 175 } 176 bzero(out, outlen); 177 for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) { 178 krb5_ones_complement_add(out, p, outlen); 179 } 180 free(tmp, M_GSSAPI); 181 } 182 183 struct krb5_key_state * 184 krb5_derive_key(struct krb5_key_state *inkey, 185 void *constant, size_t constantlen) 186 { 187 struct krb5_key_state *dk; 188 const struct krb5_encryption_class *ec = inkey->ks_class; 189 uint8_t *folded; 190 uint8_t *bytes, *p, *q; 191 struct mbuf *m; 192 int randomlen, i; 193 194 /* 195 * Expand the constant to blocklen bytes. 196 */ 197 folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK); 198 krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen); 199 200 /* 201 * Generate enough bytes for keybits rounded up to a multiple 202 * of blocklen. 203 */ 204 randomlen = roundup(ec->ec_keybits / 8, ec->ec_blocklen); 205 bytes = malloc(randomlen, M_GSSAPI, M_WAITOK); 206 MGET(m, M_WAITOK, MT_DATA); 207 m->m_len = ec->ec_blocklen; 208 for (i = 0, p = bytes, q = folded; i < randomlen; 209 q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) { 210 bcopy(q, m->m_data, ec->ec_blocklen); 211 krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0); 212 bcopy(m->m_data, p, ec->ec_blocklen); 213 } 214 m_free(m); 215 216 dk = krb5_create_key(ec); 217 krb5_random_to_key(dk, bytes); 218 219 free(folded, M_GSSAPI); 220 free(bytes, M_GSSAPI); 221 222 return (dk); 223 } 224 225 static struct krb5_key_state * 226 krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which) 227 { 228 const struct krb5_encryption_class *ec = basekey->ks_class; 229 230 if (ec->ec_flags & EC_DERIVED_KEYS) { 231 uint8_t constant[5]; 232 233 constant[0] = usage >> 24; 234 constant[1] = usage >> 16; 235 constant[2] = usage >> 8; 236 constant[3] = usage; 237 constant[4] = which; 238 return (krb5_derive_key(basekey, constant, 5)); 239 } else { 240 refcount_acquire(&basekey->ks_refs); 241 return (basekey); 242 } 243 } 244 245 struct krb5_key_state * 246 krb5_get_encryption_key(struct krb5_key_state *basekey, int usage) 247 { 248 249 return (krb5_get_usage_key(basekey, usage, 0xaa)); 250 } 251 252 struct krb5_key_state * 253 krb5_get_integrity_key(struct krb5_key_state *basekey, int usage) 254 { 255 256 return (krb5_get_usage_key(basekey, usage, 0x55)); 257 } 258 259 struct krb5_key_state * 260 krb5_get_checksum_key(struct krb5_key_state *basekey, int usage) 261 { 262 263 return (krb5_get_usage_key(basekey, usage, 0x99)); 264 } 265