1/* 2 * Copyright (c) 2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <sys/types.h> 30#include <sys/malloc.h> 31 32#include <kern/locks.h> 33 34#include <libkern/crypto/sha1.h> 35 36#include <net/if.h> 37 38#include <netinet/in.h> 39#include <netinet6/in6_var.h> 40#include <netinet/ip6.h> 41#include <netinet6/ip6_var.h> 42#include <netinet6/nd6.h> 43 44#define IN6_CGA_HASH1_LENGTH 8 45#define IN6_CGA_HASH2_LENGTH 14 46#define IN6_CGA_PREPARE_ZEROES 9 47 48struct in6_cga_hash1 { 49 u_int8_t octets[IN6_CGA_HASH1_LENGTH]; 50}; 51 52struct in6_cga_hash2 { 53 u_int8_t octets[IN6_CGA_HASH2_LENGTH]; 54}; 55 56struct in6_cga_singleton { 57 boolean_t cga_initialized; 58 decl_lck_mtx_data(, cga_mutex); 59 struct in6_cga_prepare cga_prepare; 60 struct iovec cga_pubkey; 61 struct iovec cga_privkey; 62}; 63 64static struct in6_cga_singleton in6_cga = { 65 .cga_initialized = FALSE, 66 .cga_mutex = {}, 67 .cga_prepare = { 68 .cga_modifier = {}, 69 .cga_security_level = 0, 70 }, 71 .cga_pubkey = { 72 .iov_base = NULL, 73 .iov_len = 0, 74 }, 75 .cga_privkey = { 76 .iov_base = NULL, 77 .iov_len = 0, 78 }, 79}; 80 81static void 82in6_cga_node_lock_assert(int owned) 83{ 84 VERIFY(in6_cga.cga_initialized); 85 lck_mtx_assert(&in6_cga.cga_mutex, owned); 86} 87 88static boolean_t 89in6_cga_is_prepare_valid(const struct in6_cga_prepare *prepare, 90 const struct iovec *pubkey) 91{ 92 static const u_int8_t zeroes[IN6_CGA_PREPARE_ZEROES] = { }; 93 SHA1_CTX ctx; 94 u_int8_t sha1[SHA1_RESULTLEN]; 95 u_int i, n; 96 97 VERIFY(prepare != NULL); 98 VERIFY(pubkey != NULL && pubkey->iov_base != NULL); 99 100 if (prepare->cga_security_level == 0) 101 return (TRUE); 102 103 if (prepare->cga_security_level > 7) 104 return (FALSE); 105 106 SHA1Init(&ctx); 107 SHA1Update(&ctx, &prepare->cga_modifier.octets, 108 IN6_CGA_MODIFIER_LENGTH); 109 SHA1Update(&ctx, &zeroes, IN6_CGA_PREPARE_ZEROES); 110 SHA1Update(&ctx, pubkey->iov_base, pubkey->iov_len); 111 /* FUTURE: extension fields */ 112 SHA1Final(sha1, &ctx); 113 114 n = 2 * (u_int) prepare->cga_security_level; 115 VERIFY(n < SHA1_RESULTLEN); 116 for (i = 0; i < n; ++i) 117 if (sha1[i] != 0) 118 return (FALSE); 119 120 return (TRUE); 121} 122 123static void 124in6_cga_generate_iid(const struct in6_cga_prepare *prepare, 125 const struct iovec *pubkey, u_int8_t collisions, struct in6_addr *in6) 126{ 127 SHA1_CTX ctx; 128 u_int8_t sha1[SHA1_RESULTLEN]; 129 130 VERIFY(prepare != NULL); 131 VERIFY(prepare->cga_security_level < 8); 132 VERIFY(pubkey != NULL && pubkey->iov_base != NULL); 133 VERIFY(in6 != NULL); 134 135 SHA1Init(&ctx); 136 SHA1Update(&ctx, &prepare->cga_modifier.octets, 16); 137 SHA1Update(&ctx, in6->s6_addr, 8); 138 SHA1Update(&ctx, &collisions, 1); 139 SHA1Update(&ctx, pubkey->iov_base, pubkey->iov_len); 140 /* FUTURE: extension fields */ 141 SHA1Final(sha1, &ctx); 142 143 in6->s6_addr8[8] = 144 (prepare->cga_security_level << 5) | (sha1[0] & 0x1c); 145 in6->s6_addr8[9] = sha1[1]; 146 in6->s6_addr8[10] = sha1[2]; 147 in6->s6_addr8[11] = sha1[3]; 148 in6->s6_addr8[12] = sha1[4]; 149 in6->s6_addr8[13] = sha1[5]; 150 in6->s6_addr8[14] = sha1[6]; 151 in6->s6_addr8[15] = sha1[7]; 152} 153 154void 155in6_cga_init(void) 156{ 157 lck_mtx_init(&in6_cga.cga_mutex, ifa_mtx_grp, ifa_mtx_attr); 158 in6_cga.cga_initialized = TRUE; 159} 160 161void 162in6_cga_node_lock(void) 163{ 164 VERIFY(in6_cga.cga_initialized); 165 lck_mtx_lock(&in6_cga.cga_mutex); 166} 167 168void 169in6_cga_node_unlock(void) 170{ 171 VERIFY(in6_cga.cga_initialized); 172 lck_mtx_unlock(&in6_cga.cga_mutex); 173} 174 175void 176in6_cga_query(struct in6_cga_nodecfg *cfg) 177{ 178 VERIFY(cfg != NULL); 179 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED); 180 181 cfg->cga_pubkey = in6_cga.cga_pubkey; 182 cfg->cga_prepare = in6_cga.cga_prepare; 183} 184 185int 186in6_cga_start(const struct in6_cga_nodecfg *cfg) 187{ 188 struct iovec privkey, pubkey; 189 const struct in6_cga_prepare *prepare; 190 caddr_t pubkeycopy, privkeycopy; 191 192 VERIFY(cfg != NULL); 193 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED); 194 195 privkey = cfg->cga_privkey; 196 if (privkey.iov_base == NULL || privkey.iov_len == 0 || 197 privkey.iov_len >= IN6_CGA_KEY_MAXSIZE) 198 return (EINVAL); 199 pubkey = cfg->cga_pubkey; 200 if (pubkey.iov_base == NULL || pubkey.iov_len == 0 || 201 pubkey.iov_len >= IN6_CGA_KEY_MAXSIZE) 202 return (EINVAL); 203 prepare = &cfg->cga_prepare; 204 205 if (!in6_cga_is_prepare_valid(prepare, &pubkey)) 206 return (EINVAL); 207 208 in6_cga.cga_prepare = *prepare; 209 210 MALLOC(privkeycopy, caddr_t, privkey.iov_len, M_IP6CGA, M_WAITOK); 211 if (privkeycopy == NULL) 212 return (ENOMEM); 213 214 MALLOC(pubkeycopy, caddr_t, pubkey.iov_len, M_IP6CGA, M_WAITOK); 215 if (pubkeycopy == NULL) { 216 if (privkeycopy != NULL) 217 FREE(privkeycopy, M_IP6CGA); 218 return (ENOMEM); 219 } 220 221 bcopy(privkey.iov_base, privkeycopy, privkey.iov_len); 222 privkey.iov_base = privkeycopy; 223 if (in6_cga.cga_privkey.iov_base != NULL) 224 FREE(in6_cga.cga_privkey.iov_base, M_IP6CGA); 225 in6_cga.cga_privkey = privkey; 226 227 bcopy(pubkey.iov_base, pubkeycopy, pubkey.iov_len); 228 pubkey.iov_base = pubkeycopy; 229 if (in6_cga.cga_pubkey.iov_base != NULL) 230 FREE(in6_cga.cga_pubkey.iov_base, M_IP6CGA); 231 in6_cga.cga_pubkey = pubkey; 232 233 return (0); 234} 235 236int 237in6_cga_stop(void) 238{ 239 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED); 240 241 if (in6_cga.cga_privkey.iov_base != NULL) { 242 FREE(in6_cga.cga_privkey.iov_base, M_IP6CGA); 243 in6_cga.cga_privkey.iov_base = NULL; 244 in6_cga.cga_privkey.iov_len = 0; 245 } 246 247 if (in6_cga.cga_pubkey.iov_base != NULL) { 248 FREE(in6_cga.cga_pubkey.iov_base, M_IP6CGA); 249 in6_cga.cga_pubkey.iov_base = NULL; 250 in6_cga.cga_pubkey.iov_len = 0; 251 } 252 253 return (0); 254} 255 256ssize_t 257in6_cga_parameters_prepare(void *output, size_t max, 258 const struct in6_addr *prefix, u_int8_t collisions, 259 const struct in6_cga_modifier *modifier) 260{ 261 caddr_t cursor; 262 263 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED); 264 265 if (in6_cga.cga_pubkey.iov_len == 0) { 266 /* No public key */ 267 return (EINVAL); 268 } 269 270 if (output == NULL || 271 max < in6_cga.cga_pubkey.iov_len + sizeof (modifier->octets) + 9) { 272 /* Output buffer error */ 273 return (EINVAL); 274 } 275 276 cursor = output; 277 if (modifier == NULL) modifier = &in6_cga.cga_prepare.cga_modifier; 278 if (prefix == NULL) { 279 static const struct in6_addr llprefix = {{{ 0xfe, 0x80 }}}; 280 prefix = &llprefix; 281 } 282 283 bcopy(&modifier->octets, cursor, sizeof (modifier->octets)); 284 cursor += sizeof (modifier->octets); 285 286 *cursor++ = (char) collisions; 287 288 bcopy(&prefix->s6_addr[0], cursor, 8); 289 cursor += 8; 290 291 bcopy(in6_cga.cga_pubkey.iov_base, cursor, in6_cga.cga_pubkey.iov_len); 292 cursor += in6_cga.cga_pubkey.iov_len; 293 294 /* FUTURE: Extension fields */ 295 296 return ((ssize_t)(cursor - (caddr_t)output)); 297} 298 299int 300in6_cga_generate(const struct in6_cga_prepare *prepare, u_int8_t collisions, 301 struct in6_addr *in6) 302{ 303 int error; 304 const struct iovec *pubkey; 305 306 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED); 307 VERIFY(in6 != NULL); 308 309 if (prepare == NULL) 310 prepare = &in6_cga.cga_prepare; 311 312 pubkey = &in6_cga.cga_pubkey; 313 314 if (pubkey->iov_base != NULL) { 315 in6_cga_generate_iid(prepare, pubkey, collisions, in6); 316 error = 0; 317 } 318 else 319 error = EADDRNOTAVAIL; 320 321 return (error); 322} 323 324/* End of file */ 325