OpenDNSSEC-enforcer  1.4.8.2
ksm_update.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /*+
28  * ksm_update.c - Update Times
29  *
30  * Description:
31  * Given a set of zones, this module updates all the estimated times in
32  * the keys associated with the zone.
33  *
34  * The estimated times are updated using the current state of the key and
35  * the actual time the key entered that state. The key is updated using
36  * the values of the various parameters.
37  *
38  * SO FAR, THIS ONLY APPLIES TO ZSKS
39 -*/
40 
41 #include <stdio.h>
42 #include <limits.h>
43 
44 #include "ksm/database.h"
45 #include "ksm/db_fields.h"
46 #include "ksm/debug.h"
47 #include "ksm/ksm.h"
48 #include "ksm/kmedef.h"
49 #include "ksm/ksmdef.h"
50 #include "ksm/message.h"
51 
52 #define MAX(a, b) ((a) > (b) ? (a) : (b))
53 #define MIN(a, b) ((a) < (b) ? (a) : (b))
54 
55 
56 /*+
57  * KsmUpdate - Update Times for Keys
58  *
59  * Description:
60  * Obtains the times for the specified zone and process each key in it.
61  *
62  * Arguments:
63  * None.
64  *
65  * Returns:
66  * int
67  * Always 0.
68 -*/
69 
70 int KsmUpdate(int policy_id, int zone_id)
71 {
72  KSM_PARCOLL collection; /* Collection of parameters for zone */
73  KSM_KEYDATA data; /* Data about the key */
74  DB_RESULT result; /* For iterating through keys */
75  int status = 0; /* Status return */
76  DQS_QUERY_CONDITION condition[2]; /* Condition codes */
77 
78  /* Set collection defaults */
79  KsmCollectionInit(&collection);
80 
81  /* Get the values of the parameters */
82  status = KsmParameterCollection(&collection, policy_id);
83  if (status == 0) {
84 
85  /*
86  * Iterate round, updating each key. As always, an error causes a
87  * message to be output, so we don't need to handle error conditions.
88  * Abandon updates if the update of a single key fails.
89  */
90 
91  /* zone_id of -1 means all zones */
92  if (zone_id == -1) {
93  status = KsmKeyInit(&result, NULL);
94  }
95  else {
96  condition[0].code = DB_KEYDATA_ZONE_ID;
97  condition[0].data.number = zone_id;
98  condition[0].compare = DQS_COMPARE_EQ;
99 
100  condition[1].compare = DQS_END_OF_LIST;
101 
102  status = KsmKeyInit(&result, condition);
103  }
104 
105  if (status == 0) {
106  /* Transaction handling is one level up (in KsmRequestKeys) */
107  status = KsmKey(result, &data);
108  while (status == 0) {
109  (void) KsmUpdateKey(&data, &collection, zone_id);
110  status = KsmKey(result, &data);
111  }
112  (void) KsmKeyEnd(result);
113 
114  /* Change end of list status to a success */
115 
116  if (status == -1) {
117  status = 0;
118  }
119  }
120  }
121  /*
122  * else {
123  * Unable to get parameter collection information. If we can't do
124  * this, something must be seriously wrong.
125  * }
126  */
127 
128  return status;
129 }
130 
131 
132 /*+
133  * KsmUpdateKey - Update Key Times
134  *
135  * Description:
136  * Updates the estimated times in a key based on the current state and the
137  * parameters.
138  *
139  * Arguments:
140  * KSM_KEYDATA* data
141  * Key to update.
142  *
143  * KSM_PARCOLL* collection
144  * Parameter collection.
145  *
146  * int zone_id
147  * zone we are looking at
148 -*/
149 
150 void KsmUpdateKey(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
151 {
152  /* check the argument */
153  if (data == NULL) {
154  MsgLog(KSM_INVARG, "NULL data");
155  return;
156  }
157 
158  switch (data->state) {
159  case KSM_STATE_GENERATE:
161  break;
162 
163  case KSM_STATE_PUBLISH:
164  KsmUpdatePublishKeyTime(data, collection, zone_id);
165  /* Fall through for 5011 keys, they skip ready state */
166  if (!data->rfc5011) break;
167 
168  case KSM_STATE_READY:
169  KsmUpdateReadyKeyTime(data, collection, zone_id);
170  break;
171 
172  case KSM_STATE_ACTIVE:
173  KsmUpdateActiveKeyTime(data, collection, zone_id);
174  break;
175 
176  case KSM_STATE_RETIRE:
177  KsmUpdateRetireKeyTime(data, collection, zone_id);
178  break;
179 
180  case KSM_STATE_DEAD:
181  KsmUpdateDeadKeyTime(data);
182  break;
183 
184  case KSM_STATE_DSSUB:
185  /* Do nothing, wait for ds-seen before moving to DSPUBLISH */
186  break;
187 
188  case KSM_STATE_DSPUBLISH:
189  KsmUpdateDSPublishKeyTime(data, collection, zone_id);
190  break;
191 
192  case KSM_STATE_DSREADY:
193  /* Do nothing, hold the standby key in this state */
194  break;
195 
197  KsmUpdateKEYPublishKeyTime(data, collection, zone_id);
198  break;
199  default:
200 
201  /* Should not have a key in an unknown state */
202 
203  MsgLog(KME_UNRKEYSTA, (int) data->keypair_id, data->state);
204  }
205 
206  return;
207 }
208 
209 
210 /*+
211  * KsmUpdateXxxxKeyTime - Update Key Time for Key In Xxxx State
212  *
213  * Description:
214  * Handles the update of a key in the specified state.
215  *
216  * Arguments:id
217  * KSM_KEYDATA* data
218  * Key to update.
219  *
220 -*/
221 
223 {
224  /*
225  * Keys in the generated state don't automatically change their state -
226  * they wait until a request is made to publish them.
227  */
228 
229  /* check the argument */
230  if (data == NULL) {
231  MsgLog(KSM_INVARG, "NULL data");
232  return;
233  }
234  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'generate' - not updated\n",
235  (int) data->keypair_id);
236 
237  return;
238 }
239 
240 void KsmUpdatePublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
241 {
242  int deltat = 0; /* Time interval */
243  int Ipc; /* Child zone publication interval */
244 
245  /* check the argument */
246  if (data == NULL || collection == NULL) {
247  MsgLog(KSM_INVARG, "NULL argument");
248  return;
249  }
250  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'publish' - updating\n",
251  (int) data->keypair_id);
252 
253  Ipc = collection->zskttl +
254  collection->propdelay + collection->pub_safety;
255  if (data->keytype == KSM_TYPE_ZSK) {
256  /*
257  * A key in the "publish" state moves into the "ready" state when it has
258  * been published for at least:
259  *
260  * Ipc = TTLkeyc + Dpc +Sp
261  *
262  * ... where:
263  *
264  * TTLkeyc = TTL of the ZSK DNSKEY record
265  * Dpc = Propagation delay
266  * Sp = Publish Safety Margin
267  *
268  */
269 
270  deltat = Ipc;
271  }
272  else if (data->keytype == KSM_TYPE_KSK) {
273  /*
274  * A key in the "publish" state moves into the "ready" state when it has
275  * been published for either:
276  *
277  * Ipc or Ipp, depending on the rollover scheme
278  * where
279  * Ipp = TTLdsp + Dpp + Dr +Sp
280  *
281  * ... where:
282  *
283  * TTLdsp = TTL of the DS record in the parent
284  * Dpp = Propagation delay
285  * Dr = Registration delay (Currently unused)
286  * Sp = Publish Safety Margin
287  *
288  */
289  if (collection->rfc5011) {
290  deltat = Ipc + MAX(collection->kskttl, RFC5011_ADD_HOLDDOWN_TIME);
291  } else if (collection->kskroll == KSM_ROLL_DNSKEY) {
292  deltat = Ipc;
293  } else if (collection->kskroll == KSM_ROLL_DS) {
294  deltat = collection->kskttl + collection->kskpropdelay +
295  collection->pub_safety; /* Ipp */
296  }
297  }
298  else {
299  return;
300  }
301 
302  (void) KsmUpdateKeyTime(data, "PUBLISH", "READY", deltat, zone_id);
303 }
304 
305 /*
306  * Normally keys in the ready state don't automatically move into the
307  * active state. They need to be explicitly activated. However in case
308  * of a 5011 rollover we can skip this step as there is no DS
309  * record involved.
310  */
311 void KsmUpdateReadyKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
312 {
313  (void)collection;
314  /* check the argument */
315  if (!data) {
316  MsgLog(KSM_INVARG, "NULL data");
317  } else if (data->rfc5011) {
318  if (KsmUpdateKeyTime(data, "READY", "ACTIVE", 0, zone_id)) {
319  /* The error has been logged already */
320  }
321  } else {
322  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'ready' - not updated\n",
323  (int) data->keypair_id);
324  }
325 }
326 
327 void KsmUpdateActiveKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
328 {
329  int deltat; /* Time interval */
330 
331  /* check the argument */
332  if (data == NULL || collection == NULL) {
333  MsgLog(KSM_INVARG, "NULL argument");
334  return;
335  }
336  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'active' - updating\n",
337  (int) data->keypair_id);
338 
339  /*
340  * A key in the "active" state moves into the "retire" state when it has
341  * been active for at least:
342  *
343  * Lz
344  *
345  * ... where
346  *
347  * Lz = Life time of a ZSK (i.e. how long it is used for)
348  */
349 
350  if (data->keytype == KSM_TYPE_ZSK) {
351  deltat = collection->zsklife;
352  }
353  else if (data->keytype == KSM_TYPE_KSK) {
354  deltat = collection->ksklife;
355  }
356  else {
357  return;
358  }
359 
360  /* "Infinite" lifetime */
361  if (deltat == 0) {
362  deltat = INT_MAX -1;
363  }
364 
365  /*
366  * Update the retire time if the key is not marked as fixedDate.
367  * If we asked for a rollover, but no keys were ready then a compromised key
368  * may still be active.
369  */
370  if (!data->fixedDate) {
371  (void) KsmUpdateKeyTime(data, "ACTIVE", "RETIRE", deltat, zone_id);
372  }
373 
374  return;
375 }
376 
377 void KsmUpdateRetireKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
378 {
379  int deltat = 0; /* Time interval */
380 
381  /* check the argument */
382  if (data == NULL || collection == NULL) {
383  MsgLog(KSM_INVARG, "NULL argument");
384  return;
385  }
386  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'retire' - updating\n",
387  (int) data->keypair_id);
388 
389  /*
390  * A key in the "retire" state moves into the "dead" state after a period
391  * of:
392  *
393  * TTLsig + Dp + St
394  *
395  * ... where
396  *
397  * TTLsig = Signature lifetime (how long a signature is valid for)
398  * Dp = Propagation delay
399  * St = Retire safety margin
400  */
401 
402  if (data->keytype == KSM_TYPE_ZSK) {
403  deltat = collection->zsksiglife + collection->propdelay + collection->ret_safety;
404  }
405  else if (data->keytype == KSM_TYPE_KSK) {
406  /*
407  * for a KSK this can be 0 (from the timings draft); are we happy with that?
408  * Might revisit this in the future as it might be a surprise for people
409  *
410  * Change of heart... make this as large as we can so that keys stay retired
411  * until some manual process tells us that its DS record has been removed.
412  *
413  * second change of heart:
414  * Don't do anything here, this time is set when the ksk-roll command is issued.
415  *
416  * Third change
417  */
418  deltat = collection->dsttl + collection->kskpropdelay +
419  collection->ret_safety; /* Ipp */
420  if (data->rfc5011)
421  deltat += RFC5011_REM_HOLDDOWN_TIME;
422  }
423  else {
424  return;
425  }
426  if (!data->fixedDate || data->dead == NULL || *data->dead == '\0') {
427  (void) KsmUpdateKeyTime(data, "RETIRE", "DEAD", deltat, zone_id);
428  }
429  return;
430 }
431 
433 {
434  /*
435  * Keys in the dead state don't automatically change their state - they
436  * are retained in the database for historical reasons or until they are
437  * explicitly deleted.
438  */
439 
440  /* check the argument */
441  if (data == NULL) {
442  MsgLog(KSM_INVARG, "NULL data");
443  return;
444  }
445  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'dead' - not updated\n",
446  (int) data->keypair_id);
447 
448  return;
449 }
450 
451 void KsmUpdateDSPublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
452 {
453  int deltat = 0; /* Time interval */
454 
455  /* check the argument */
456  if (data == NULL || collection == NULL) {
457  MsgLog(KSM_INVARG, "NULL argument");
458  return;
459  }
460  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'publish' - updating\n",
461  (int) data->keypair_id);
462 
463  if (data->keytype == KSM_TYPE_ZSK) {
464  /*
465  * This state should only be used by KSKs
466  */
467 
468  return;
469  }
470  else if (data->keytype == KSM_TYPE_KSK) {
471  /*
472  * A key in the "dspublish" state moves into the "dsready" state when it has
473  * been published for either:
474  *
475  * Ipp = TTLdsp + Dpp + Dr +Sp
476  *
477  * ... where:
478  *
479  * TTLdsp = TTL of the DS record in the parent
480  * Dpp = Propagation delay
481  * Dr = Registration delay (Currently unused)
482  * Sp = Publish Safety Margin
483  *
484  */
485  deltat = collection->kskttl + collection->kskpropdelay +
486  collection->pub_safety;
487  }
488  else {
489  return;
490  }
491 
492  (void) KsmUpdateKeyTime(data, "PUBLISH", "READY", deltat, zone_id);
493 
494  return;
495 }
496 
497 void KsmUpdateKEYPublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
498 {
499  int deltat = 0; /* Time interval */
500 
501  /* check the argument */
502  if (data == NULL || collection == NULL) {
503  MsgLog(KSM_INVARG, "NULL argument");
504  return;
505  }
506  DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'KEYpublish' - updating\n",
507  (int) data->keypair_id);
508 
509  /*
510  * A key in the "KEYpublish" state moves into the "active" state when it has
511  * been published for at least:
512  *
513  * Ipc = TTLkeyc + Dpc +Sp
514  *
515  * ... where:
516  *
517  * TTLkeyc = TTL of the ZSK DNSKEY record
518  * Dpc = Propagation delay
519  * Sp = Publish Safety Margin
520  *
521  */
522  deltat = collection->zskttl +
523  collection->propdelay + collection->pub_safety;
524 
525  (void) KsmUpdateKeyTime(data, "PUBLISH", "ACTIVE", deltat, zone_id);
526 
527  return;
528 }
529 
530 /*+
531  * KsmUpdateKeyTime - Update Key Time
532  *
533  * Description:
534  * Actually performs the update of the database. The update is
535  *
536  * destination_time = source_time + interval
537  *
538  * Arguments:
539  * const KSM_KEYDATA* data
540  * Data about the key to be updated. Note that this is NOT updated
541  * by the update.
542  *
543  * const char* source
544  * Source field.
545  *
546  * const char* destination
547  * Source field.
548  *
549  * int interval
550  * Interval (seconds) to update the source field with.
551  *
552  * int zone_id
553  * zone we are looking at
554  *
555  * Returns:
556  * int
557  * 0 Update successful
558  * Other Error. A message will have beeen output.
559 -*/
560 
561 int KsmUpdateKeyTime(const KSM_KEYDATA* data, const char* source,
562  const char* destination, int interval, int zone_id)
563 {
564  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
565  unsigned int nchar; /* Number of characters converted */
566  int status; /* Status return */
567 
568  /* check the argument */
569  if (data == NULL || source == NULL || destination == NULL) {
570  return MsgLog(KSM_INVARG, "NULL argument");
571  }
572 
573 #ifdef USE_MYSQL
574  nchar = snprintf(buffer, sizeof(buffer),
575  "UPDATE dnsseckeys SET %s = DATE_ADD(%s, INTERVAL %d SECOND) WHERE KEYPAIR_ID = %lu and zone_id = %d",
576  destination, source, interval, (unsigned long) data->keypair_id, zone_id);
577 #else
578  nchar = snprintf(buffer, sizeof(buffer),
579  "UPDATE dnsseckeys SET %s = DATETIME(%s, '+%d SECONDS') WHERE KEYPAIR_ID = %lu and zone_id = %d",
580  destination, source, interval, (unsigned long) data->keypair_id, zone_id);
581 #endif /* USE_MYSQL */
582 
583  if (nchar < sizeof(buffer)) {
584 
585  /* All OK, execute the statement */
586 
587  status = DbExecuteSqlNoResult(DbHandle(), buffer);
588  }
589  else {
590 
591  /* Unable to create update statement */
592 
593  status = MsgLog(KME_BUFFEROVF, "KsmUpdateKeyTime");
594  }
595 
596  return status;
597 }
#define RFC5011_REM_HOLDDOWN_TIME
Definition: ksm.h:71
char dead[KSM_TIME_LENGTH]
Definition: ksm.h:107
#define KSM_TYPE_ZSK
Definition: ksm.h:362
#define KSM_INVARG
Definition: ksmdef.h:66
void DbgOutput(unsigned int mask, const char *format,...)
Definition: debug.c:135
#define KSM_STATE_DEAD
Definition: ksm.h:377
union DQS_QUERY_CONDITION::@0 data
#define KSM_STATE_ACTIVE
Definition: ksm.h:373
int kskttl
Definition: ksm.h:492
void KsmUpdateDeadKeyTime(KSM_KEYDATA *data)
Definition: ksm_update.c:432
int pub_safety
Definition: ksm.h:495
#define KSM_STATE_READY
Definition: ksm.h:371
#define KSM_ROLL_DS
Definition: ksm.h:404
int state
Definition: ksm.h:102
int KsmParameterCollection(KSM_PARCOLL *data, int policy_id)
int rfc5011
Definition: ksm.h:501
DQS_COMPARISON compare
int dsttl
Definition: ksm.h:499
int zsksiglife
Definition: ksm.h:489
void KsmUpdatePublishKeyTime(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:240
#define DB_KEYDATA_ZONE_ID
Definition: db_fields.h:68
int MsgLog(int status,...)
Definition: message.c:335
int KsmUpdateKeyTime(const KSM_KEYDATA *data, const char *source, const char *destination, int interval, int zone_id)
Definition: ksm_update.c:561
#define KME_UNRKEYSTA
Definition: kmedef.h:70
int ret_safety
Definition: ksm.h:496
#define KSM_ROLL_DNSKEY
Definition: ksm.h:402
int ksklife
Definition: ksm.h:482
#define KSM_STATE_KEYPUBLISH
Definition: ksm.h:385
void KsmUpdateReadyKeyTime(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:311
#define RFC5011_ADD_HOLDDOWN_TIME
Definition: ksm.h:70
DB_HANDLE DbHandle(void)
#define KSM_STATE_DSPUBLISH
Definition: ksm.h:381
void KsmUpdateGenerateKeyTime(KSM_KEYDATA *data)
Definition: ksm_update.c:222
int KsmCollectionInit(KSM_PARCOLL *data)
int propdelay
Definition: ksm.h:485
int KsmKey(DB_RESULT result, KSM_KEYDATA *data)
Definition: ksm_key.c:368
int rfc5011
Definition: ksm.h:128
int keytype
Definition: ksm.h:103
#define KSM_SQL_SIZE
Definition: ksm.h:63
int KsmKeyInit(DB_RESULT *result, DQS_QUERY_CONDITION *condition)
Definition: ksm_key.c:251
int fixedDate
Definition: ksm.h:119
int zskttl
Definition: ksm.h:491
#define KSM_STATE_RETIRE
Definition: ksm.h:375
#define KSM_STATE_PUBLISH
Definition: ksm.h:369
#define DBG_M_UPDATE
Definition: debug.h:44
DB_ID keypair_id
Definition: ksm.h:101
int KsmUpdate(int policy_id, int zone_id)
Definition: ksm_update.c:70
void KsmUpdateActiveKeyTime(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:327
int kskpropdelay
Definition: ksm.h:493
#define KME_BUFFEROVF
Definition: kmedef.h:48
void KsmUpdateKey(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:150
#define MAX(a, b)
Definition: ksm_update.c:52
void KsmUpdateDSPublishKeyTime(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:451
int zsklife
Definition: ksm.h:490
#define KSM_STATE_DSSUB
Definition: ksm.h:379
#define KSM_TYPE_KSK
Definition: ksm.h:360
void KsmUpdateKEYPublishKeyTime(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:497
#define KSM_STATE_DSREADY
Definition: ksm.h:383
void KsmKeyEnd(DB_RESULT result)
Definition: ksm_key.c:478
#define KSM_STATE_GENERATE
Definition: ksm.h:367
void KsmUpdateRetireKeyTime(KSM_KEYDATA *data, KSM_PARCOLL *collection, int zone_id)
Definition: ksm_update.c:377
int DbExecuteSqlNoResult(DB_HANDLE handle, const char *stmt_str)
int kskroll
Definition: ksm.h:500