OpenDNSSEC-enforcer
1.3.8
|
00001 /* 00002 * $Id: ksm_update.c 4250 2010-12-06 08:56:44Z sion $ 00003 * 00004 * Copyright (c) 2008-2009 Nominet UK. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00029 /*+ 00030 * ksm_update.c - Update Times 00031 * 00032 * Description: 00033 * Given a set of zones, this module updates all the estimated times in 00034 * the keys associated with the zone. 00035 * 00036 * The estimated times are updated using the current state of the key and 00037 * the actual time the key entered that state. The key is updated using 00038 * the values of the various parameters. 00039 * 00040 * SO FAR, THIS ONLY APPLIES TO ZSKS 00041 -*/ 00042 00043 #include <stdio.h> 00044 #include <limits.h> 00045 00046 #include "ksm/database.h" 00047 #include "ksm/db_fields.h" 00048 #include "ksm/debug.h" 00049 #include "ksm/ksm.h" 00050 #include "ksm/kmedef.h" 00051 #include "ksm/ksmdef.h" 00052 #include "ksm/message.h" 00053 00054 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 00055 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 00056 00057 00058 /*+ 00059 * KsmUpdate - Update Times for Keys 00060 * 00061 * Description: 00062 * Obtains the times for the specified zone and process each key in it. 00063 * 00064 * Arguments: 00065 * None. 00066 * 00067 * Returns: 00068 * int 00069 * Always 0. 00070 -*/ 00071 00072 int KsmUpdate(int policy_id, int zone_id) 00073 { 00074 KSM_PARCOLL collection; /* Collection of parameters for zone */ 00075 KSM_KEYDATA data; /* Data about the key */ 00076 DB_RESULT result; /* For iterating through keys */ 00077 int status = 0; /* Status return */ 00078 DQS_QUERY_CONDITION condition[2]; /* Condition codes */ 00079 00080 /* Set collection defaults */ 00081 KsmCollectionInit(&collection); 00082 00083 /* Get the values of the parameters */ 00084 status = KsmParameterCollection(&collection, policy_id); 00085 if (status == 0) { 00086 00087 /* 00088 * Iterate round, updating each key. As always, an error causes a 00089 * message to be output, so we don't need to handle error conditions. 00090 * Abandon updates if the update of a single key fails. 00091 */ 00092 00093 /* zone_id of -1 means all zones */ 00094 if (zone_id == -1) { 00095 status = KsmKeyInit(&result, NULL); 00096 } 00097 else { 00098 condition[0].code = DB_KEYDATA_ZONE_ID; 00099 condition[0].data.number = zone_id; 00100 condition[0].compare = DQS_COMPARE_EQ; 00101 00102 condition[1].compare = DQS_END_OF_LIST; 00103 00104 status = KsmKeyInit(&result, condition); 00105 } 00106 00107 if (status == 0) { 00108 /* Transaction handling is one level up (in KsmRequestKeys) */ 00109 status = KsmKey(result, &data); 00110 while (status == 0) { 00111 (void) KsmUpdateKey(&data, &collection, zone_id); 00112 status = KsmKey(result, &data); 00113 } 00114 (void) KsmKeyEnd(result); 00115 00116 /* Change end of list status to a success */ 00117 00118 if (status == -1) { 00119 status = 0; 00120 } 00121 } 00122 } 00123 /* 00124 * else { 00125 * Unable to get parameter collection information. If we can't do 00126 * this, something must be seriously wrong. 00127 * } 00128 */ 00129 00130 return status; 00131 } 00132 00133 00134 /*+ 00135 * KsmUpdateKey - Update Key Times 00136 * 00137 * Description: 00138 * Updates the estimated times in a key based on the current state and the 00139 * parameters. 00140 * 00141 * Arguments: 00142 * KSM_KEYDATA* data 00143 * Key to update. 00144 * 00145 * KSM_PARCOLL* collection 00146 * Parameter collection. 00147 * 00148 * int zone_id 00149 * zone we are looking at 00150 -*/ 00151 00152 void KsmUpdateKey(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id) 00153 { 00154 /* check the argument */ 00155 if (data == NULL) { 00156 MsgLog(KSM_INVARG, "NULL data"); 00157 return; 00158 } 00159 00160 switch (data->state) { 00161 case KSM_STATE_GENERATE: 00162 KsmUpdateGenerateKeyTime(data); 00163 break; 00164 00165 case KSM_STATE_PUBLISH: 00166 KsmUpdatePublishKeyTime(data, collection, zone_id); 00167 break; 00168 00169 case KSM_STATE_READY: 00170 KsmUpdateReadyKeyTime(data); 00171 break; 00172 00173 case KSM_STATE_ACTIVE: 00174 KsmUpdateActiveKeyTime(data, collection, zone_id); 00175 break; 00176 00177 case KSM_STATE_RETIRE: 00178 KsmUpdateRetireKeyTime(data, collection, zone_id); 00179 break; 00180 00181 case KSM_STATE_DEAD: 00182 KsmUpdateDeadKeyTime(data); 00183 break; 00184 00185 case KSM_STATE_DSSUB: 00186 /* Do nothing, wait for ds-seen before moving to DSPUBLISH */ 00187 break; 00188 00189 case KSM_STATE_DSPUBLISH: 00190 KsmUpdateDSPublishKeyTime(data, collection, zone_id); 00191 break; 00192 00193 case KSM_STATE_DSREADY: 00194 /* Do nothing, hold the standby key in this state */ 00195 break; 00196 00197 case KSM_STATE_KEYPUBLISH: 00198 KsmUpdateKEYPublishKeyTime(data, collection, zone_id); 00199 break; 00200 default: 00201 00202 /* Should not have a key in an unknown state */ 00203 00204 MsgLog(KME_UNRKEYSTA, (int) data->keypair_id, data->state); 00205 } 00206 00207 return; 00208 } 00209 00210 00211 /*+ 00212 * KsmUpdateXxxxKeyTime - Update Key Time for Key In Xxxx State 00213 * 00214 * Description: 00215 * Handles the update of a key in the specified state. 00216 * 00217 * Arguments:id 00218 * KSM_KEYDATA* data 00219 * Key to update. 00220 * 00221 -*/ 00222 00223 void KsmUpdateGenerateKeyTime(KSM_KEYDATA* data) 00224 { 00225 /* 00226 * Keys in the generated state don't automatically change their state - 00227 * they wait until a request is made to publish them. 00228 */ 00229 00230 /* check the argument */ 00231 if (data == NULL) { 00232 MsgLog(KSM_INVARG, "NULL data"); 00233 return; 00234 } 00235 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'generate' - not updated\n", 00236 (int) data->keypair_id); 00237 00238 return; 00239 } 00240 00241 void KsmUpdatePublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id) 00242 { 00243 int deltat = 0; /* Time interval */ 00244 int Ipc; /* Child zone publication interval */ 00245 00246 /* check the argument */ 00247 if (data == NULL || collection == NULL) { 00248 MsgLog(KSM_INVARG, "NULL argument"); 00249 return; 00250 } 00251 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'publish' - updating\n", 00252 (int) data->keypair_id); 00253 00254 Ipc = collection->zskttl + 00255 collection->propdelay + collection->pub_safety; 00256 if (data->keytype == KSM_TYPE_ZSK) { 00257 /* 00258 * A key in the "publish" state moves into the "ready" state when it has 00259 * been published for at least: 00260 * 00261 * Ipc = TTLkeyc + Dpc +Sp 00262 * 00263 * ... where: 00264 * 00265 * TTLkeyc = TTL of the ZSK DNSKEY record 00266 * Dpc = Propagation delay 00267 * Sp = Publish Safety Margin 00268 * 00269 */ 00270 00271 deltat = Ipc; 00272 } 00273 else if (data->keytype == KSM_TYPE_KSK) { 00274 /* 00275 * A key in the "publish" state moves into the "ready" state when it has 00276 * been published for either: 00277 * 00278 * Ipc or Ipp, depending on the rollover scheme 00279 * where 00280 * Ipp = TTLdsp + Dpp + Dr +Sp 00281 * 00282 * ... where: 00283 * 00284 * TTLdsp = TTL of the DS record in the parent 00285 * Dpp = Propagation delay 00286 * Dr = Registration delay (Currently unused) 00287 * Sp = Publish Safety Margin 00288 * 00289 */ 00290 if (collection->kskroll == KSM_ROLL_DNSKEY) { 00291 deltat = Ipc; 00292 } 00293 else if (collection->kskroll == KSM_ROLL_DS) { 00294 deltat = collection->kskttl + collection->kskpropdelay + 00295 collection->pub_safety; /* Ipp */ 00296 } 00297 } 00298 else { 00299 return; 00300 } 00301 00302 (void) KsmUpdateKeyTime(data, "PUBLISH", "READY", deltat, zone_id); 00303 00304 return; 00305 } 00306 00307 void KsmUpdateReadyKeyTime(KSM_KEYDATA* data) 00308 { 00309 /* 00310 * Keys in the ready state don't automatically move into the active state. 00311 * They need to be explicitly activated. 00312 */ 00313 00314 /* check the argument */ 00315 if (data == NULL) { 00316 MsgLog(KSM_INVARG, "NULL data"); 00317 return; 00318 } 00319 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'ready' - not updated\n", 00320 (int) data->keypair_id); 00321 00322 return; 00323 } 00324 00325 void KsmUpdateActiveKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id) 00326 { 00327 int deltat; /* Time interval */ 00328 00329 /* check the argument */ 00330 if (data == NULL || collection == NULL) { 00331 MsgLog(KSM_INVARG, "NULL argument"); 00332 return; 00333 } 00334 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'active' - updating\n", 00335 (int) data->keypair_id); 00336 00337 /* 00338 * A key in the "active" state moves into the "retire" state when it has 00339 * been active for at least: 00340 * 00341 * Lz 00342 * 00343 * ... where 00344 * 00345 * Lz = Life time of a ZSK (i.e. how long it is used for) 00346 */ 00347 00348 if (data->keytype == KSM_TYPE_ZSK) { 00349 deltat = collection->zsklife; 00350 } 00351 else if (data->keytype == KSM_TYPE_KSK) { 00352 deltat = collection->ksklife; 00353 } 00354 else { 00355 return; 00356 } 00357 00358 /* "Infinite" lifetime */ 00359 if (deltat == 0) { 00360 deltat = INT_MAX -1; 00361 } 00362 00363 /* 00364 * Update the retire time if the key is not marked as fixedDate. 00365 * If we asked for a rollover, but no keys were ready then a compromised key 00366 * may still be active. 00367 */ 00368 if (!data->fixedDate) { 00369 (void) KsmUpdateKeyTime(data, "ACTIVE", "RETIRE", deltat, zone_id); 00370 } 00371 00372 return; 00373 } 00374 00375 void KsmUpdateRetireKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id) 00376 { 00377 int deltat = 0; /* Time interval */ 00378 00379 /* check the argument */ 00380 if (data == NULL || collection == NULL) { 00381 MsgLog(KSM_INVARG, "NULL argument"); 00382 return; 00383 } 00384 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'retire' - updating\n", 00385 (int) data->keypair_id); 00386 00387 /* 00388 * A key in the "retire" state moves into the "dead" state after a period 00389 * of: 00390 * 00391 * TTLsig + Dp + St 00392 * 00393 * ... where 00394 * 00395 * TTLsig = Signature lifetime (how long a signature is valid for) 00396 * Dp = Propagation delay 00397 * St = Retire safety margin 00398 */ 00399 00400 if (data->keytype == KSM_TYPE_ZSK) { 00401 deltat = collection->zsksiglife + collection->propdelay + collection->ret_safety; 00402 } 00403 else if (data->keytype == KSM_TYPE_KSK) { 00404 /* 00405 * for a KSK this can be 0 (from the timings draft); are we happy with that? 00406 * Might revisit this in the future as it might be a surprise for people 00407 * 00408 * Change of heart... make this as large as we can so that keys stay retired 00409 * until some manual process tells us that its DS record has been removed. 00410 * 00411 * second change of heart: 00412 * Don't do anything here, this time is set when the ksk-roll command is issued. 00413 * 00414 * Third change 00415 */ 00416 deltat = collection->dsttl + collection->kskpropdelay + 00417 collection->ret_safety; /* Ipp */ 00418 } 00419 else { 00420 return; 00421 } 00422 00423 (void) KsmUpdateKeyTime(data, "RETIRE", "DEAD", deltat, zone_id); 00424 00425 return; 00426 } 00427 00428 void KsmUpdateDeadKeyTime(KSM_KEYDATA* data) 00429 { 00430 /* 00431 * Keys in the dead state don't automatically change their state - they 00432 * are retained in the database for historical reasons or until they are 00433 * explicitly deleted. 00434 */ 00435 00436 /* check the argument */ 00437 if (data == NULL) { 00438 MsgLog(KSM_INVARG, "NULL data"); 00439 return; 00440 } 00441 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'dead' - not updated\n", 00442 (int) data->keypair_id); 00443 00444 return; 00445 } 00446 00447 void KsmUpdateDSPublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id) 00448 { 00449 int deltat = 0; /* Time interval */ 00450 00451 /* check the argument */ 00452 if (data == NULL || collection == NULL) { 00453 MsgLog(KSM_INVARG, "NULL argument"); 00454 return; 00455 } 00456 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'publish' - updating\n", 00457 (int) data->keypair_id); 00458 00459 if (data->keytype == KSM_TYPE_ZSK) { 00460 /* 00461 * This state should only be used by KSKs 00462 */ 00463 00464 return; 00465 } 00466 else if (data->keytype == KSM_TYPE_KSK) { 00467 /* 00468 * A key in the "dspublish" state moves into the "dsready" state when it has 00469 * been published for either: 00470 * 00471 * Ipp = TTLdsp + Dpp + Dr +Sp 00472 * 00473 * ... where: 00474 * 00475 * TTLdsp = TTL of the DS record in the parent 00476 * Dpp = Propagation delay 00477 * Dr = Registration delay (Currently unused) 00478 * Sp = Publish Safety Margin 00479 * 00480 */ 00481 deltat = collection->kskttl + collection->kskpropdelay + 00482 collection->pub_safety; 00483 } 00484 else { 00485 return; 00486 } 00487 00488 (void) KsmUpdateKeyTime(data, "PUBLISH", "READY", deltat, zone_id); 00489 00490 return; 00491 } 00492 00493 void KsmUpdateKEYPublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id) 00494 { 00495 int deltat = 0; /* Time interval */ 00496 00497 /* check the argument */ 00498 if (data == NULL || collection == NULL) { 00499 MsgLog(KSM_INVARG, "NULL argument"); 00500 return; 00501 } 00502 DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'KEYpublish' - updating\n", 00503 (int) data->keypair_id); 00504 00505 /* 00506 * A key in the "KEYpublish" state moves into the "active" state when it has 00507 * been published for at least: 00508 * 00509 * Ipc = TTLkeyc + Dpc +Sp 00510 * 00511 * ... where: 00512 * 00513 * TTLkeyc = TTL of the ZSK DNSKEY record 00514 * Dpc = Propagation delay 00515 * Sp = Publish Safety Margin 00516 * 00517 */ 00518 deltat = collection->zskttl + 00519 collection->propdelay + collection->pub_safety; 00520 00521 (void) KsmUpdateKeyTime(data, "PUBLISH", "ACTIVE", deltat, zone_id); 00522 00523 return; 00524 } 00525 00526 /*+ 00527 * KsmUpdateKeyTime - Update Key Time 00528 * 00529 * Description: 00530 * Actually performs the update of the database. The update is 00531 * 00532 * destination_time = source_time + interval 00533 * 00534 * Arguments: 00535 * const KSM_KEYDATA* data 00536 * Data about the key to be updated. Note that this is NOT updated 00537 * by the update. 00538 * 00539 * const char* source 00540 * Source field. 00541 * 00542 * const char* destination 00543 * Source field. 00544 * 00545 * int interval 00546 * Interval (seconds) to update the source field with. 00547 * 00548 * int zone_id 00549 * zone we are looking at 00550 * 00551 * Returns: 00552 * int 00553 * 0 Update successful 00554 * Other Error. A message will have beeen output. 00555 -*/ 00556 00557 int KsmUpdateKeyTime(const KSM_KEYDATA* data, const char* source, 00558 const char* destination, int interval, int zone_id) 00559 { 00560 char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */ 00561 unsigned int nchar; /* Number of characters converted */ 00562 int status; /* Status return */ 00563 00564 /* check the argument */ 00565 if (data == NULL || source == NULL || destination == NULL) { 00566 return MsgLog(KSM_INVARG, "NULL argument"); 00567 } 00568 00569 #ifdef USE_MYSQL 00570 nchar = snprintf(buffer, sizeof(buffer), 00571 "UPDATE dnsseckeys SET %s = DATE_ADD(%s, INTERVAL %d SECOND) WHERE KEYPAIR_ID = %lu and zone_id = %d", 00572 destination, source, interval, (unsigned long) data->keypair_id, zone_id); 00573 #else 00574 nchar = snprintf(buffer, sizeof(buffer), 00575 "UPDATE dnsseckeys SET %s = DATETIME(%s, '+%d SECONDS') WHERE KEYPAIR_ID = %lu and zone_id = %d", 00576 destination, source, interval, (unsigned long) data->keypair_id, zone_id); 00577 #endif /* USE_MYSQL */ 00578 00579 if (nchar < sizeof(buffer)) { 00580 00581 /* All OK, execute the statement */ 00582 00583 status = DbExecuteSqlNoResult(DbHandle(), buffer); 00584 } 00585 else { 00586 00587 /* Unable to create update statement */ 00588 00589 status = MsgLog(KME_BUFFEROVF, "KsmUpdateKeyTime"); 00590 } 00591 00592 return status; 00593 }