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