14c75e3aaSDag-Erling Smørgrav /*
24c75e3aaSDag-Erling Smørgrav * util/edns.c - handle base EDNS options.
34c75e3aaSDag-Erling Smørgrav *
44c75e3aaSDag-Erling Smørgrav * Copyright (c) 2018, NLnet Labs. All rights reserved.
54c75e3aaSDag-Erling Smørgrav *
64c75e3aaSDag-Erling Smørgrav * This software is open source.
74c75e3aaSDag-Erling Smørgrav *
84c75e3aaSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
94c75e3aaSDag-Erling Smørgrav * modification, are permitted provided that the following conditions
104c75e3aaSDag-Erling Smørgrav * are met:
114c75e3aaSDag-Erling Smørgrav *
124c75e3aaSDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice,
134c75e3aaSDag-Erling Smørgrav * this list of conditions and the following disclaimer.
144c75e3aaSDag-Erling Smørgrav *
154c75e3aaSDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice,
164c75e3aaSDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation
174c75e3aaSDag-Erling Smørgrav * and/or other materials provided with the distribution.
184c75e3aaSDag-Erling Smørgrav *
194c75e3aaSDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may
204c75e3aaSDag-Erling Smørgrav * be used to endorse or promote products derived from this software without
214c75e3aaSDag-Erling Smørgrav * specific prior written permission.
224c75e3aaSDag-Erling Smørgrav *
234c75e3aaSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
244c75e3aaSDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
254c75e3aaSDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
264c75e3aaSDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
274c75e3aaSDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
284c75e3aaSDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
294c75e3aaSDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
304c75e3aaSDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
314c75e3aaSDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
324c75e3aaSDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
334c75e3aaSDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
344c75e3aaSDag-Erling Smørgrav */
354c75e3aaSDag-Erling Smørgrav
364c75e3aaSDag-Erling Smørgrav /**
374c75e3aaSDag-Erling Smørgrav * \file
384c75e3aaSDag-Erling Smørgrav *
394c75e3aaSDag-Erling Smørgrav * This file contains functions for base EDNS options.
404c75e3aaSDag-Erling Smørgrav */
414c75e3aaSDag-Erling Smørgrav
424c75e3aaSDag-Erling Smørgrav #include "config.h"
43e86b9096SDag-Erling Smørgrav #include "util/edns.h"
444c75e3aaSDag-Erling Smørgrav #include "util/config_file.h"
454c75e3aaSDag-Erling Smørgrav #include "util/netevent.h"
46c0caa2e2SCy Schubert #include "util/net_help.h"
474c75e3aaSDag-Erling Smørgrav #include "util/regional.h"
488f76bb7dSCy Schubert #include "util/rfc_1982.h"
498f76bb7dSCy Schubert #include "util/siphash.h"
504c75e3aaSDag-Erling Smørgrav #include "util/data/msgparse.h"
514c75e3aaSDag-Erling Smørgrav #include "util/data/msgreply.h"
528f76bb7dSCy Schubert #include "sldns/sbuffer.h"
534c75e3aaSDag-Erling Smørgrav
54c0caa2e2SCy Schubert #if 0
55c0caa2e2SCy Schubert /* XXX: remove me */
564c75e3aaSDag-Erling Smørgrav #include "edns.h"
57c0caa2e2SCy Schubert #endif
58c0caa2e2SCy Schubert
edns_strings_create(void)59369c6923SCy Schubert struct edns_strings* edns_strings_create(void)
60c0caa2e2SCy Schubert {
61369c6923SCy Schubert struct edns_strings* edns_strings = calloc(1,
62369c6923SCy Schubert sizeof(struct edns_strings));
63369c6923SCy Schubert if(!edns_strings)
64c0caa2e2SCy Schubert return NULL;
65369c6923SCy Schubert if(!(edns_strings->region = regional_create())) {
66369c6923SCy Schubert edns_strings_delete(edns_strings);
67c0caa2e2SCy Schubert return NULL;
68c0caa2e2SCy Schubert }
69369c6923SCy Schubert return edns_strings;
70c0caa2e2SCy Schubert }
71c0caa2e2SCy Schubert
edns_strings_delete(struct edns_strings * edns_strings)72369c6923SCy Schubert void edns_strings_delete(struct edns_strings* edns_strings)
73c0caa2e2SCy Schubert {
74369c6923SCy Schubert if(!edns_strings)
75c0caa2e2SCy Schubert return;
76369c6923SCy Schubert regional_destroy(edns_strings->region);
77369c6923SCy Schubert free(edns_strings);
78c0caa2e2SCy Schubert }
79c0caa2e2SCy Schubert
80c0caa2e2SCy Schubert static int
edns_strings_client_insert(struct edns_strings * edns_strings,struct sockaddr_storage * addr,socklen_t addrlen,int net,const char * string)81369c6923SCy Schubert edns_strings_client_insert(struct edns_strings* edns_strings,
82c0caa2e2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, int net,
83369c6923SCy Schubert const char* string)
84c0caa2e2SCy Schubert {
85369c6923SCy Schubert struct edns_string_addr* esa = regional_alloc_zero(edns_strings->region,
86369c6923SCy Schubert sizeof(struct edns_string_addr));
87369c6923SCy Schubert if(!esa)
88c0caa2e2SCy Schubert return 0;
89369c6923SCy Schubert esa->string_len = strlen(string);
90369c6923SCy Schubert esa->string = regional_alloc_init(edns_strings->region, string,
91369c6923SCy Schubert esa->string_len);
92369c6923SCy Schubert if(!esa->string)
93369c6923SCy Schubert return 0;
94369c6923SCy Schubert if(!addr_tree_insert(&edns_strings->client_strings, &esa->node, addr,
95369c6923SCy Schubert addrlen, net)) {
96369c6923SCy Schubert verbose(VERB_QUERY, "duplicate EDNS client string ignored.");
97c0caa2e2SCy Schubert }
98c0caa2e2SCy Schubert return 1;
99c0caa2e2SCy Schubert }
100c0caa2e2SCy Schubert
edns_strings_apply_cfg(struct edns_strings * edns_strings,struct config_file * config)101369c6923SCy Schubert int edns_strings_apply_cfg(struct edns_strings* edns_strings,
102c0caa2e2SCy Schubert struct config_file* config)
103c0caa2e2SCy Schubert {
104c0caa2e2SCy Schubert struct config_str2list* c;
105369c6923SCy Schubert regional_free_all(edns_strings->region);
106369c6923SCy Schubert addr_tree_init(&edns_strings->client_strings);
107c0caa2e2SCy Schubert
108369c6923SCy Schubert for(c=config->edns_client_strings; c; c=c->next) {
109c0caa2e2SCy Schubert struct sockaddr_storage addr;
110c0caa2e2SCy Schubert socklen_t addrlen;
111c0caa2e2SCy Schubert int net;
112c0caa2e2SCy Schubert log_assert(c->str && c->str2);
113c0caa2e2SCy Schubert
114c0caa2e2SCy Schubert if(!netblockstrtoaddr(c->str, UNBOUND_DNS_PORT, &addr, &addrlen,
115c0caa2e2SCy Schubert &net)) {
116369c6923SCy Schubert log_err("cannot parse EDNS client string IP netblock: "
117369c6923SCy Schubert "%s", c->str);
118c0caa2e2SCy Schubert return 0;
119c0caa2e2SCy Schubert }
120369c6923SCy Schubert if(!edns_strings_client_insert(edns_strings, &addr, addrlen,
121369c6923SCy Schubert net, c->str2)) {
122369c6923SCy Schubert log_err("out of memory while adding EDNS strings");
123c0caa2e2SCy Schubert return 0;
124c0caa2e2SCy Schubert }
125c0caa2e2SCy Schubert }
126369c6923SCy Schubert edns_strings->client_string_opcode = config->edns_client_string_opcode;
127c0caa2e2SCy Schubert
128369c6923SCy Schubert addr_tree_init_parents(&edns_strings->client_strings);
129c0caa2e2SCy Schubert return 1;
130c0caa2e2SCy Schubert }
131c0caa2e2SCy Schubert
132369c6923SCy Schubert struct edns_string_addr*
edns_string_addr_lookup(rbtree_type * tree,struct sockaddr_storage * addr,socklen_t addrlen)133369c6923SCy Schubert edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
134c0caa2e2SCy Schubert socklen_t addrlen)
135c0caa2e2SCy Schubert {
136369c6923SCy Schubert return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
137c0caa2e2SCy Schubert }
1384c75e3aaSDag-Erling Smørgrav
1398f76bb7dSCy Schubert uint8_t*
edns_cookie_server_hash(const uint8_t * in,const uint8_t * secret,int v4,uint8_t * hash)1408f76bb7dSCy Schubert edns_cookie_server_hash(const uint8_t* in, const uint8_t* secret, int v4,
1418f76bb7dSCy Schubert uint8_t* hash)
1428f76bb7dSCy Schubert {
1438f76bb7dSCy Schubert v4?siphash(in, 20, secret, hash, 8):siphash(in, 32, secret, hash, 8);
1448f76bb7dSCy Schubert return hash;
1458f76bb7dSCy Schubert }
1468f76bb7dSCy Schubert
1478f76bb7dSCy Schubert void
edns_cookie_server_write(uint8_t * buf,const uint8_t * secret,int v4,uint32_t timestamp)1488f76bb7dSCy Schubert edns_cookie_server_write(uint8_t* buf, const uint8_t* secret, int v4,
1498f76bb7dSCy Schubert uint32_t timestamp)
1508f76bb7dSCy Schubert {
1518f76bb7dSCy Schubert uint8_t hash[8];
1528f76bb7dSCy Schubert buf[ 8] = 1; /* Version */
1538f76bb7dSCy Schubert buf[ 9] = 0; /* Reserved */
1548f76bb7dSCy Schubert buf[10] = 0; /* Reserved */
1558f76bb7dSCy Schubert buf[11] = 0; /* Reserved */
1568f76bb7dSCy Schubert sldns_write_uint32(buf + 12, timestamp);
1578f76bb7dSCy Schubert (void)edns_cookie_server_hash(buf, secret, v4, hash);
1588f76bb7dSCy Schubert memcpy(buf + 16, hash, 8);
1598f76bb7dSCy Schubert }
1608f76bb7dSCy Schubert
1618f76bb7dSCy Schubert enum edns_cookie_val_status
edns_cookie_server_validate(const uint8_t * cookie,size_t cookie_len,const uint8_t * secret,size_t secret_len,int v4,const uint8_t * hash_input,uint32_t now)1628f76bb7dSCy Schubert edns_cookie_server_validate(const uint8_t* cookie, size_t cookie_len,
1638f76bb7dSCy Schubert const uint8_t* secret, size_t secret_len, int v4,
1648f76bb7dSCy Schubert const uint8_t* hash_input, uint32_t now)
1658f76bb7dSCy Schubert {
1668f76bb7dSCy Schubert uint8_t hash[8];
1678f76bb7dSCy Schubert uint32_t timestamp;
1688f76bb7dSCy Schubert uint32_t subt_1982 = 0; /* Initialize for the compiler; unused value */
1698f76bb7dSCy Schubert int comp_1982;
1708f76bb7dSCy Schubert if(cookie_len != 24)
1718f76bb7dSCy Schubert /* RFC9018 cookies are 24 bytes long */
1728f76bb7dSCy Schubert return COOKIE_STATUS_CLIENT_ONLY;
1738f76bb7dSCy Schubert if(secret_len != 16 || /* RFC9018 cookies have 16 byte secrets */
1748f76bb7dSCy Schubert cookie[8] != 1) /* RFC9018 cookies are cookie version 1 */
1758f76bb7dSCy Schubert return COOKIE_STATUS_INVALID;
1768f76bb7dSCy Schubert timestamp = sldns_read_uint32(cookie + 12);
1778f76bb7dSCy Schubert if((comp_1982 = compare_1982(now, timestamp)) > 0
1788f76bb7dSCy Schubert && (subt_1982 = subtract_1982(timestamp, now)) > 3600)
1798f76bb7dSCy Schubert /* Cookie is older than 1 hour (see RFC9018 Section 4.3.) */
1808f76bb7dSCy Schubert return COOKIE_STATUS_EXPIRED;
1818f76bb7dSCy Schubert if(comp_1982 <= 0 && subtract_1982(now, timestamp) > 300)
1828f76bb7dSCy Schubert /* Cookie time is more than 5 minutes in the future.
1838f76bb7dSCy Schubert * (see RFC9018 Section 4.3.) */
1848f76bb7dSCy Schubert return COOKIE_STATUS_FUTURE;
1858f76bb7dSCy Schubert if(memcmp(edns_cookie_server_hash(hash_input, secret, v4, hash),
1868f76bb7dSCy Schubert cookie + 16, 8) != 0)
1878f76bb7dSCy Schubert /* Hashes do not match */
1888f76bb7dSCy Schubert return COOKIE_STATUS_INVALID;
1898f76bb7dSCy Schubert if(comp_1982 > 0 && subt_1982 > 1800)
1908f76bb7dSCy Schubert /* Valid cookie but older than 30 minutes, so create a new one
1918f76bb7dSCy Schubert * anyway */
1928f76bb7dSCy Schubert return COOKIE_STATUS_VALID_RENEW;
1938f76bb7dSCy Schubert return COOKIE_STATUS_VALID;
1948f76bb7dSCy Schubert }
195*56850988SCy Schubert
196*56850988SCy Schubert struct cookie_secrets*
cookie_secrets_create(void)197*56850988SCy Schubert cookie_secrets_create(void)
198*56850988SCy Schubert {
199*56850988SCy Schubert struct cookie_secrets* cookie_secrets = calloc(1,
200*56850988SCy Schubert sizeof(*cookie_secrets));
201*56850988SCy Schubert if(!cookie_secrets)
202*56850988SCy Schubert return NULL;
203*56850988SCy Schubert lock_basic_init(&cookie_secrets->lock);
204*56850988SCy Schubert lock_protect(&cookie_secrets->lock, &cookie_secrets->cookie_count,
205*56850988SCy Schubert sizeof(cookie_secrets->cookie_count));
206*56850988SCy Schubert lock_protect(&cookie_secrets->lock, cookie_secrets->cookie_secrets,
207*56850988SCy Schubert sizeof(cookie_secret_type)*UNBOUND_COOKIE_HISTORY_SIZE);
208*56850988SCy Schubert return cookie_secrets;
209*56850988SCy Schubert }
210*56850988SCy Schubert
211*56850988SCy Schubert void
cookie_secrets_delete(struct cookie_secrets * cookie_secrets)212*56850988SCy Schubert cookie_secrets_delete(struct cookie_secrets* cookie_secrets)
213*56850988SCy Schubert {
214*56850988SCy Schubert if(!cookie_secrets)
215*56850988SCy Schubert return;
216*56850988SCy Schubert lock_basic_destroy(&cookie_secrets->lock);
217*56850988SCy Schubert explicit_bzero(cookie_secrets->cookie_secrets,
218*56850988SCy Schubert sizeof(cookie_secret_type)*UNBOUND_COOKIE_HISTORY_SIZE);
219*56850988SCy Schubert free(cookie_secrets);
220*56850988SCy Schubert }
221*56850988SCy Schubert
222*56850988SCy Schubert /** Read the cookie secret file */
223*56850988SCy Schubert static int
cookie_secret_file_read(struct cookie_secrets * cookie_secrets,char * cookie_secret_file)224*56850988SCy Schubert cookie_secret_file_read(struct cookie_secrets* cookie_secrets,
225*56850988SCy Schubert char* cookie_secret_file)
226*56850988SCy Schubert {
227*56850988SCy Schubert char secret[UNBOUND_COOKIE_SECRET_SIZE * 2 + 2/*'\n' and '\0'*/];
228*56850988SCy Schubert FILE* f;
229*56850988SCy Schubert int corrupt = 0;
230*56850988SCy Schubert size_t count;
231*56850988SCy Schubert
232*56850988SCy Schubert log_assert(cookie_secret_file != NULL);
233*56850988SCy Schubert cookie_secrets->cookie_count = 0;
234*56850988SCy Schubert f = fopen(cookie_secret_file, "r");
235*56850988SCy Schubert /* a non-existing cookie file is not an error */
236*56850988SCy Schubert if( f == NULL ) {
237*56850988SCy Schubert if(errno != EPERM) {
238*56850988SCy Schubert log_err("Could not read cookie-secret-file '%s': %s",
239*56850988SCy Schubert cookie_secret_file, strerror(errno));
240*56850988SCy Schubert return 0;
241*56850988SCy Schubert }
242*56850988SCy Schubert return 1;
243*56850988SCy Schubert }
244*56850988SCy Schubert /* cookie secret file exists and is readable */
245*56850988SCy Schubert for( count = 0; count < UNBOUND_COOKIE_HISTORY_SIZE; count++ ) {
246*56850988SCy Schubert size_t secret_len = 0;
247*56850988SCy Schubert ssize_t decoded_len = 0;
248*56850988SCy Schubert if( fgets(secret, sizeof(secret), f) == NULL ) { break; }
249*56850988SCy Schubert secret_len = strlen(secret);
250*56850988SCy Schubert if( secret_len == 0 ) { break; }
251*56850988SCy Schubert log_assert( secret_len <= sizeof(secret) );
252*56850988SCy Schubert secret_len = secret[secret_len - 1] == '\n' ? secret_len - 1 : secret_len;
253*56850988SCy Schubert if( secret_len != UNBOUND_COOKIE_SECRET_SIZE * 2 ) { corrupt++; break; }
254*56850988SCy Schubert /* needed for `hex_pton`; stripping potential `\n` */
255*56850988SCy Schubert secret[secret_len] = '\0';
256*56850988SCy Schubert decoded_len = hex_pton(secret, cookie_secrets->cookie_secrets[count].cookie_secret,
257*56850988SCy Schubert UNBOUND_COOKIE_SECRET_SIZE);
258*56850988SCy Schubert if( decoded_len != UNBOUND_COOKIE_SECRET_SIZE ) { corrupt++; break; }
259*56850988SCy Schubert cookie_secrets->cookie_count++;
260*56850988SCy Schubert }
261*56850988SCy Schubert fclose(f);
262*56850988SCy Schubert return corrupt == 0;
263*56850988SCy Schubert }
264*56850988SCy Schubert
265*56850988SCy Schubert int
cookie_secrets_apply_cfg(struct cookie_secrets * cookie_secrets,char * cookie_secret_file)266*56850988SCy Schubert cookie_secrets_apply_cfg(struct cookie_secrets* cookie_secrets,
267*56850988SCy Schubert char* cookie_secret_file)
268*56850988SCy Schubert {
269*56850988SCy Schubert if(!cookie_secrets) {
270*56850988SCy Schubert if(!cookie_secret_file || !cookie_secret_file[0])
271*56850988SCy Schubert return 1; /* There is nothing to read anyway */
272*56850988SCy Schubert log_err("Could not read cookie secrets, no structure alloced");
273*56850988SCy Schubert return 0;
274*56850988SCy Schubert }
275*56850988SCy Schubert if(!cookie_secret_file_read(cookie_secrets, cookie_secret_file))
276*56850988SCy Schubert return 0;
277*56850988SCy Schubert return 1;
278*56850988SCy Schubert }
279*56850988SCy Schubert
280*56850988SCy Schubert enum edns_cookie_val_status
cookie_secrets_server_validate(const uint8_t * cookie,size_t cookie_len,struct cookie_secrets * cookie_secrets,int v4,const uint8_t * hash_input,uint32_t now)281*56850988SCy Schubert cookie_secrets_server_validate(const uint8_t* cookie, size_t cookie_len,
282*56850988SCy Schubert struct cookie_secrets* cookie_secrets, int v4,
283*56850988SCy Schubert const uint8_t* hash_input, uint32_t now)
284*56850988SCy Schubert {
285*56850988SCy Schubert size_t i;
286*56850988SCy Schubert enum edns_cookie_val_status cookie_val_status,
287*56850988SCy Schubert last = COOKIE_STATUS_INVALID;
288*56850988SCy Schubert if(!cookie_secrets)
289*56850988SCy Schubert return COOKIE_STATUS_INVALID; /* There are no cookie secrets.*/
290*56850988SCy Schubert lock_basic_lock(&cookie_secrets->lock);
291*56850988SCy Schubert if(cookie_secrets->cookie_count == 0) {
292*56850988SCy Schubert lock_basic_unlock(&cookie_secrets->lock);
293*56850988SCy Schubert return COOKIE_STATUS_INVALID; /* There are no cookie secrets.*/
294*56850988SCy Schubert }
295*56850988SCy Schubert for(i=0; i<cookie_secrets->cookie_count; i++) {
296*56850988SCy Schubert cookie_val_status = edns_cookie_server_validate(cookie,
297*56850988SCy Schubert cookie_len,
298*56850988SCy Schubert cookie_secrets->cookie_secrets[i].cookie_secret,
299*56850988SCy Schubert UNBOUND_COOKIE_SECRET_SIZE, v4, hash_input, now);
300*56850988SCy Schubert if(cookie_val_status == COOKIE_STATUS_VALID ||
301*56850988SCy Schubert cookie_val_status == COOKIE_STATUS_VALID_RENEW) {
302*56850988SCy Schubert lock_basic_unlock(&cookie_secrets->lock);
303*56850988SCy Schubert /* For staging cookies, write a fresh cookie. */
304*56850988SCy Schubert if(i != 0)
305*56850988SCy Schubert return COOKIE_STATUS_VALID_RENEW;
306*56850988SCy Schubert return cookie_val_status;
307*56850988SCy Schubert }
308*56850988SCy Schubert if(last == COOKIE_STATUS_INVALID)
309*56850988SCy Schubert last = cookie_val_status; /* Store more interesting
310*56850988SCy Schubert failure to return. */
311*56850988SCy Schubert }
312*56850988SCy Schubert lock_basic_unlock(&cookie_secrets->lock);
313*56850988SCy Schubert return last;
314*56850988SCy Schubert }
315*56850988SCy Schubert
add_cookie_secret(struct cookie_secrets * cookie_secrets,uint8_t * secret,size_t secret_len)316*56850988SCy Schubert void add_cookie_secret(struct cookie_secrets* cookie_secrets,
317*56850988SCy Schubert uint8_t* secret, size_t secret_len)
318*56850988SCy Schubert {
319*56850988SCy Schubert log_assert(secret_len == UNBOUND_COOKIE_SECRET_SIZE);
320*56850988SCy Schubert (void)secret_len;
321*56850988SCy Schubert if(!cookie_secrets)
322*56850988SCy Schubert return;
323*56850988SCy Schubert
324*56850988SCy Schubert /* New cookie secret becomes the staging secret (position 1)
325*56850988SCy Schubert * unless there is no active cookie yet, then it becomes the active
326*56850988SCy Schubert * secret. If the UNBOUND_COOKIE_HISTORY_SIZE > 2 then all staging cookies
327*56850988SCy Schubert * are moved one position down.
328*56850988SCy Schubert */
329*56850988SCy Schubert if(cookie_secrets->cookie_count == 0) {
330*56850988SCy Schubert memcpy( cookie_secrets->cookie_secrets->cookie_secret
331*56850988SCy Schubert , secret, UNBOUND_COOKIE_SECRET_SIZE);
332*56850988SCy Schubert cookie_secrets->cookie_count = 1;
333*56850988SCy Schubert explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
334*56850988SCy Schubert return;
335*56850988SCy Schubert }
336*56850988SCy Schubert #if UNBOUND_COOKIE_HISTORY_SIZE > 2
337*56850988SCy Schubert memmove( &cookie_secrets->cookie_secrets[2], &cookie_secrets->cookie_secrets[1]
338*56850988SCy Schubert , sizeof(struct cookie_secret) * (UNBOUND_COOKIE_HISTORY_SIZE - 2));
339*56850988SCy Schubert #endif
340*56850988SCy Schubert memcpy( cookie_secrets->cookie_secrets[1].cookie_secret
341*56850988SCy Schubert , secret, UNBOUND_COOKIE_SECRET_SIZE);
342*56850988SCy Schubert cookie_secrets->cookie_count = cookie_secrets->cookie_count < UNBOUND_COOKIE_HISTORY_SIZE
343*56850988SCy Schubert ? cookie_secrets->cookie_count + 1 : UNBOUND_COOKIE_HISTORY_SIZE;
344*56850988SCy Schubert explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
345*56850988SCy Schubert }
346*56850988SCy Schubert
activate_cookie_secret(struct cookie_secrets * cookie_secrets)347*56850988SCy Schubert void activate_cookie_secret(struct cookie_secrets* cookie_secrets)
348*56850988SCy Schubert {
349*56850988SCy Schubert uint8_t active_secret[UNBOUND_COOKIE_SECRET_SIZE];
350*56850988SCy Schubert if(!cookie_secrets)
351*56850988SCy Schubert return;
352*56850988SCy Schubert /* The staging secret becomes the active secret.
353*56850988SCy Schubert * The active secret becomes a staging secret.
354*56850988SCy Schubert * If the UNBOUND_COOKIE_HISTORY_SIZE > 2 then all staging secrets are moved
355*56850988SCy Schubert * one position up and the previously active secret becomes the last
356*56850988SCy Schubert * staging secret.
357*56850988SCy Schubert */
358*56850988SCy Schubert if(cookie_secrets->cookie_count < 2)
359*56850988SCy Schubert return;
360*56850988SCy Schubert memcpy( active_secret, cookie_secrets->cookie_secrets[0].cookie_secret
361*56850988SCy Schubert , UNBOUND_COOKIE_SECRET_SIZE);
362*56850988SCy Schubert memmove( &cookie_secrets->cookie_secrets[0], &cookie_secrets->cookie_secrets[1]
363*56850988SCy Schubert , sizeof(struct cookie_secret) * (UNBOUND_COOKIE_HISTORY_SIZE - 1));
364*56850988SCy Schubert memcpy( cookie_secrets->cookie_secrets[cookie_secrets->cookie_count - 1].cookie_secret
365*56850988SCy Schubert , active_secret, UNBOUND_COOKIE_SECRET_SIZE);
366*56850988SCy Schubert explicit_bzero(active_secret, UNBOUND_COOKIE_SECRET_SIZE);
367*56850988SCy Schubert }
368*56850988SCy Schubert
drop_cookie_secret(struct cookie_secrets * cookie_secrets)369*56850988SCy Schubert void drop_cookie_secret(struct cookie_secrets* cookie_secrets)
370*56850988SCy Schubert {
371*56850988SCy Schubert if(!cookie_secrets)
372*56850988SCy Schubert return;
373*56850988SCy Schubert /* Drops a staging cookie secret. If there are more than one, it will
374*56850988SCy Schubert * drop the last staging secret. */
375*56850988SCy Schubert if(cookie_secrets->cookie_count < 2)
376*56850988SCy Schubert return;
377*56850988SCy Schubert explicit_bzero( cookie_secrets->cookie_secrets[cookie_secrets->cookie_count - 1].cookie_secret
378*56850988SCy Schubert , UNBOUND_COOKIE_SECRET_SIZE);
379*56850988SCy Schubert cookie_secrets->cookie_count -= 1;
380*56850988SCy Schubert }
381