1/*
2 * Copyright (c) 2013-2016 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#if !MACH_ASSERT
85#pragma unused(owned)
86#endif
87 VERIFY(in6_cga.cga_initialized);
88 LCK_MTX_ASSERT(&in6_cga.cga_mutex, owned);
89}
90
91static boolean_t
92in6_cga_is_prepare_valid(const struct in6_cga_prepare *prepare,
93 const struct iovec *pubkey)
94{
95 static const u_int8_t zeroes[IN6_CGA_PREPARE_ZEROES] = { };
96 SHA1_CTX ctx;
97 u_int8_t sha1[SHA1_RESULTLEN];
98 u_int i, n;
99
100 VERIFY(prepare != NULL);
101 VERIFY(pubkey != NULL && pubkey->iov_base != NULL);
102
103 if (prepare->cga_security_level == 0)
104 return (TRUE);
105
106 if (prepare->cga_security_level > 7)
107 return (FALSE);
108
109 SHA1Init(&ctx);
110 SHA1Update(&ctx, &prepare->cga_modifier.octets,
111 IN6_CGA_MODIFIER_LENGTH);
112 SHA1Update(&ctx, &zeroes, IN6_CGA_PREPARE_ZEROES);
113 SHA1Update(&ctx, pubkey->iov_base, pubkey->iov_len);
114 /* FUTURE: extension fields */
115 SHA1Final(sha1, &ctx);
116
117 n = 2 * (u_int) prepare->cga_security_level;
118 VERIFY(n < SHA1_RESULTLEN);
119 for (i = 0; i < n; ++i)
120 if (sha1[i] != 0)
121 return (FALSE);
122
123 return (TRUE);
124}
125
126/*
127 * @brief Generate interface identifier for CGA
128 * XXX You may notice that following does not really
129 * mirror what is decribed in:
130 * https://tools.ietf.org/html/rfc3972#section-4
131 * By design kernel here will assume that that
132 * modifier has been converged on by userspace
133 * for first part of the algorithm for the given
134 * security level.
135 * We are not doing that yet but that's how the code
136 * below is written. So really we are starting
137 * from bullet 4 of the algorithm.
138 *
139 * @param prepare Pointer to object containing modifier,
140 * security level & externsion to be used.
141 * @param pubkey Public key used for IID generation
142 * @param collisions Collission count on DAD failure
143 * XXX We are not really re-generating IID on DAD
144 * failures for now.
145 * @param in6 Pointer to the address containing
146 * the prefix.
147 *
148 * @return void
149 */
150static void
151in6_cga_generate_iid(const struct in6_cga_prepare *prepare,
152 const struct iovec *pubkey, u_int8_t collisions, struct in6_addr *in6)
153{
154 SHA1_CTX ctx;
155 u_int8_t sha1[SHA1_RESULTLEN];
156
157 VERIFY(prepare != NULL);
158 VERIFY(prepare->cga_security_level < 8);
159 VERIFY(pubkey != NULL && pubkey->iov_base != NULL);
160 VERIFY(in6 != NULL);
161
162 SHA1Init(&ctx);
163 SHA1Update(&ctx, &prepare->cga_modifier.octets, 16);
164 SHA1Update(&ctx, in6->s6_addr, 8);
165 SHA1Update(&ctx, &collisions, 1);
166 SHA1Update(&ctx, pubkey->iov_base, pubkey->iov_len);
167 /* FUTURE: extension fields */
168 SHA1Final(sha1, &ctx);
169
170 in6->s6_addr8[8] =
171 (prepare->cga_security_level << 5) | (sha1[0] & 0x1c);
172 in6->s6_addr8[9] = sha1[1];
173 in6->s6_addr8[10] = sha1[2];
174 in6->s6_addr8[11] = sha1[3];
175 in6->s6_addr8[12] = sha1[4];
176 in6->s6_addr8[13] = sha1[5];
177 in6->s6_addr8[14] = sha1[6];
178 in6->s6_addr8[15] = sha1[7];
179}
180
181void
182in6_cga_init(void)
183{
184 lck_mtx_init(&in6_cga.cga_mutex, ifa_mtx_grp, ifa_mtx_attr);
185 in6_cga.cga_initialized = TRUE;
186}
187
188void
189in6_cga_node_lock(void)
190{
191 VERIFY(in6_cga.cga_initialized);
192 lck_mtx_lock(&in6_cga.cga_mutex);
193}
194
195void
196in6_cga_node_unlock(void)
197{
198 VERIFY(in6_cga.cga_initialized);
199 lck_mtx_unlock(&in6_cga.cga_mutex);
200}
201
202void
203in6_cga_query(struct in6_cga_nodecfg *cfg)
204{
205 VERIFY(cfg != NULL);
206 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
207
208 cfg->cga_pubkey = in6_cga.cga_pubkey;
209 cfg->cga_prepare = in6_cga.cga_prepare;
210}
211
212int
213in6_cga_start(const struct in6_cga_nodecfg *cfg)
214{
215 struct iovec privkey, pubkey;
216 const struct in6_cga_prepare *prepare;
217 caddr_t pubkeycopy, privkeycopy;
218
219 VERIFY(cfg != NULL);
220 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
221
222 privkey = cfg->cga_privkey;
223 if (privkey.iov_base == NULL || privkey.iov_len == 0 ||
224 privkey.iov_len >= IN6_CGA_KEY_MAXSIZE)
225 return (EINVAL);
226 pubkey = cfg->cga_pubkey;
227 if (pubkey.iov_base == NULL || pubkey.iov_len == 0 ||
228 pubkey.iov_len >= IN6_CGA_KEY_MAXSIZE)
229 return (EINVAL);
230 prepare = &cfg->cga_prepare;
231
232 if (!in6_cga_is_prepare_valid(prepare, &pubkey))
233 return (EINVAL);
234
235 in6_cga.cga_prepare = *prepare;
236
237 MALLOC(privkeycopy, caddr_t, privkey.iov_len, M_IP6CGA, M_WAITOK);
238 if (privkeycopy == NULL)
239 return (ENOMEM);
240
241 MALLOC(pubkeycopy, caddr_t, pubkey.iov_len, M_IP6CGA, M_WAITOK);
242 if (pubkeycopy == NULL) {
243 if (privkeycopy != NULL)
244 FREE(privkeycopy, M_IP6CGA);
245 return (ENOMEM);
246 }
247
248 bcopy(privkey.iov_base, privkeycopy, privkey.iov_len);
249 privkey.iov_base = privkeycopy;
250 if (in6_cga.cga_privkey.iov_base != NULL)
251 FREE(in6_cga.cga_privkey.iov_base, M_IP6CGA);
252 in6_cga.cga_privkey = privkey;
253
254 bcopy(pubkey.iov_base, pubkeycopy, pubkey.iov_len);
255 pubkey.iov_base = pubkeycopy;
256 if (in6_cga.cga_pubkey.iov_base != NULL)
257 FREE(in6_cga.cga_pubkey.iov_base, M_IP6CGA);
258 in6_cga.cga_pubkey = pubkey;
259
260 return (0);
261}
262
263int
264in6_cga_stop(void)
265{
266 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
267
268 if (in6_cga.cga_privkey.iov_base != NULL) {
269 FREE(in6_cga.cga_privkey.iov_base, M_IP6CGA);
270 in6_cga.cga_privkey.iov_base = NULL;
271 in6_cga.cga_privkey.iov_len = 0;
272 }
273
274 if (in6_cga.cga_pubkey.iov_base != NULL) {
275 FREE(in6_cga.cga_pubkey.iov_base, M_IP6CGA);
276 in6_cga.cga_pubkey.iov_base = NULL;
277 in6_cga.cga_pubkey.iov_len = 0;
278 }
279
280 return (0);
281}
282
283ssize_t
284in6_cga_parameters_prepare(void *output, size_t max,
285 const struct in6_addr *prefix, u_int8_t collisions,
286 const struct in6_cga_modifier *modifier)
287{
288 caddr_t cursor;
289
290 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
291
292 if (in6_cga.cga_pubkey.iov_len == 0) {
293 /* No public key */
294 return (EINVAL);
295 }
296
297 if (output == NULL ||
298 max < in6_cga.cga_pubkey.iov_len + sizeof (modifier->octets) + 9) {
299 /* Output buffer error */
300 return (EINVAL);
301 }
302
303 cursor = output;
304 if (modifier == NULL) modifier = &in6_cga.cga_prepare.cga_modifier;
305 if (prefix == NULL) {
306 static const struct in6_addr llprefix = {{{ 0xfe, 0x80 }}};
307 prefix = &llprefix;
308 }
309
310 bcopy(&modifier->octets, cursor, sizeof (modifier->octets));
311 cursor += sizeof (modifier->octets);
312
313 *cursor++ = (char) collisions;
314
315 bcopy(&prefix->s6_addr[0], cursor, 8);
316 cursor += 8;
317
318 bcopy(in6_cga.cga_pubkey.iov_base, cursor, in6_cga.cga_pubkey.iov_len);
319 cursor += in6_cga.cga_pubkey.iov_len;
320
321 /* FUTURE: Extension fields */
322
323 return ((ssize_t)(cursor - (caddr_t)output));
324}
325
326int
327in6_cga_generate(struct in6_cga_prepare *prepare, u_int8_t collisions,
328 struct in6_addr *in6)
329{
330 int error;
331 const struct iovec *pubkey;
332
333 in6_cga_node_lock_assert(LCK_MTX_ASSERT_OWNED);
334 VERIFY(in6 != NULL);
335
336 if (prepare == NULL)
337 prepare = &in6_cga.cga_prepare;
338 else
339 prepare->cga_security_level =
340 in6_cga.cga_prepare.cga_security_level;
341
342 pubkey = &in6_cga.cga_pubkey;
343
344 if (pubkey->iov_base != NULL) {
345 in6_cga_generate_iid(prepare, pubkey, collisions, in6);
346 error = 0;
347 }
348 else
349 error = EADDRNOTAVAIL;
350
351 return (error);
352}
353
354/* End of file */
355