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