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