OpenDNSSEC-enforcer  1.4.9
ksm_key.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  * KsmKey - Manipulation of Key Information
29  *
30  * Description:
31  * Holds the functions needed to manipulate the KEYDATA table.
32  *
33  * N.B. The table is the KEYDATA table - rather than the KEY table - as
34  * KEY is a reserved word in SQL.
35 -*/
36 
37 #include <assert.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 
43 #include "ksm/database.h"
44 #include "ksm/database_statement.h"
45 #include "ksm/datetime.h"
46 #include "ksm/db_fields.h"
47 #include "ksm/debug.h"
48 #include "ksm/kmedef.h"
49 #include "ksm/ksm.h"
50 #include "ksm/ksmdef.h"
51 #include "ksm/ksm_internal.h"
52 #include "ksm/message.h"
53 #include "ksm/string_util.h"
54 #include "ksm/string_util2.h"
55 
56 /*+
57  * KsmKeyPairCreate - Create Entry in the KeyPairs table
58  * (i.e. key creation in the HSM)
59  *
60  * Description:
61  * Creates a key in the database.
62  *
63  * Arguments:
64  * policy_id
65  * policy that the key is created for
66  * HSMKeyID
67  * ID the key is refered to in the HSM
68  * smID
69  * security module ID
70  * size
71  * size of key
72  * alg
73  * algorithm used
74  * generate
75  * timestamp of generation
76  *
77  * DB_ID* id (returned)
78  * ID of the created entry. This will be undefined on error.
79  *
80  * Returns:
81  * int
82  * Status return. 0=> Success, non-zero => error.
83 -*/
84 int KsmKeyPairCreate(int policy_id, const char* HSMKeyID, int smID, int size, int alg, const char* generate, DB_ID* id)
85 {
86  unsigned long rowid; /* ID of last inserted row */
87  int status = 0; /* Status return */
88  char* sql = NULL; /* SQL Statement */
89 
90  /* Check arguments */
91  if (id == NULL) {
92  return MsgLog(KSM_INVARG, "NULL id");
93  }
94 
95  sql = DisSpecifyInit("keypairs", "policy_id, HSMkey_id, securitymodule_id, size, algorithm, generate");
96  DisAppendInt(&sql, policy_id);
97  DisAppendString(&sql, HSMKeyID);
98  DisAppendInt(&sql, smID);
99  DisAppendInt(&sql, size);
100  DisAppendInt(&sql, alg);
101  DisAppendString(&sql, generate);
102  DisEnd(&sql);
103 
104  /* Execute the statement */
105 
106  status = DbExecuteSqlNoResult(DbHandle(), sql);
107  DisFree(sql);
108 
109  if (status == 0) {
110 
111  /* Succcess, get the ID of the inserted record */
112 
113  status = DbLastRowId(DbHandle(), &rowid);
114  if (status == 0) {
115  *id = (DB_ID) rowid;
116  }
117  }
118 
119  return status;
120 }
121 
122 /*+
123  * KsmDnssecKeyCreate - Create Entry in Dnsseckeys table
124  * (i.e. when a key is assigned to a policy/zone)
125  *
126  * Description:
127  * Allocates a key in the database.
128  *
129  * Arguments:
130  * KSM_KEY* data
131  * Data to insert into the database. The ID argument is ignored.
132  *
133  * DB_ID* id (returned)
134  * ID of the created entry. This will be undefined on error.
135  *
136  * Returns:
137  * int
138  * Status return. 0=> Success, non-zero => error.
139 -*/
140 
141 int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, int rfc5011, const char* time, const char* retTime, DB_ID* id)
142 {
143  unsigned long rowid; /* ID of last inserted row */
144  int status = 0; /* Status return */
145  char* sql = NULL; /* SQL Statement */
146  char* columns = NULL; /* what columns are we setting */
147 
148  /* Check arguments */
149  if (id == NULL) {
150  return MsgLog(KSM_INVARG, "NULL id");
151  }
152 
153  StrAppend(&columns, "zone_id, keypair_id, keytype, state, rfc5011, revoked");
154  if (state != KSM_STATE_GENERATE) {
155  StrAppend(&columns, ", ");
156  StrAppend(&columns, KsmKeywordStateValueToName(state));
157  }
158  if (state == KSM_STATE_ACTIVE && (retTime != NULL && retTime[0] != '\0')) {
159  StrAppend(&columns, ", retire");
160  }
161 
162  sql = DisSpecifyInit("dnsseckeys", columns);
163  DisAppendInt(&sql, zone_id);
164  DisAppendInt(&sql, keypair_id);
165  DisAppendInt(&sql, keytype);
166  DisAppendInt(&sql, state);
167  DisAppendInt(&sql, rfc5011 && (keytype==KSM_TYPE_KSK));
168  DisAppendInt(&sql, 0); /* revoke */
169  if (state != KSM_STATE_GENERATE) {
170  DisAppendString(&sql, time);
171  }
172  if (state == KSM_STATE_ACTIVE && (retTime != NULL && retTime[0] != '\0')) {
173  DisAppendString(&sql, retTime);
174  }
175  DisEnd(&sql);
176 
177  /* Execute the statement */
178 
179  status = DbExecuteSqlNoResult(DbHandle(), sql);
180  DisFree(sql);
181  StrFree(columns);
182 
183  if (status == 0) {
184 
185  /* Succcess, get the ID of the inserted record */
186 
187  status = DbLastRowId(DbHandle(), &rowid);
188  if (status == 0) {
189  *id = (DB_ID) rowid;
190  }
191  }
192 
193  return status;
194 }
195 
196 /*+
197  * KsmKeyInitSql - Query for Key Information With Sql Query
198  *
199  * Description:
200  * Performs a query for keys in the keydata table that match the given
201  * conditions.
202  *
203  * Arguments:
204  * DB_RESULT* result
205  * Pointer to a result to be used for information retrieval. Will
206  * be NULL on error.
207  *
208  * const char* sql
209  * SQL statement to select keys.
210  *
211  * (Actually, the statement could be anything, but it is assumed
212  * that it is an SQL statement starting "SELECT xxx FROM KEYDATA".)
213  *
214  * Returns:
215  * int
216  * Status return. 0 on success.
217 -*/
218 
219 int KsmKeyInitSql(DB_RESULT* result, const char* sql)
220 {
221  return DbExecuteSql(DbHandle(), sql, result);
222 }
223 
224 
225 
226 
227 /*+
228  * KsmKeyInit - Query for Key Information
229  *
230  * Description:
231  * Performs a query for keys in the keydata table that match the given
232  * conditions.
233  *
234  * Arguments:
235  * DB_RESULT* result
236  * Pointer to a result to be used for information retrieval. Will
237  * be NULL on error.
238  *
239  * DQS_QUERY_CONDITION* condition
240  * Array of condition objects, each defining a condition. The
241  * conditions are ANDed together. The array should end with an object
242  * with a condition code of 0.
243  *
244  * If NULL, all objects are selected.
245  *
246  * Returns:
247  * int
248  * Status return. 0 on success.
249 -*/
250 
251 int KsmKeyInit(DB_RESULT* result, DQS_QUERY_CONDITION* condition)
252 {
253  int i; /* Condition index */
254  char* sql = NULL; /* SQL query */
255  int status = 0; /* Status return */
256 
257  /* Construct the query */
258 
259  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
260  if (condition) {
261  for (i = 0; condition[i].compare != DQS_END_OF_LIST; ++i) {
262  switch (condition[i].code) {
264  DqsConditionInt(&sql, "ALGORITHM", condition[i].compare,
265  condition[i].data.number, i);
266  break;
267 
268  case DB_KEYDATA_ID:
269  DqsConditionInt(&sql, "ID", condition[i].compare,
270  condition[i].data.number, i);
271  break;
272 
273  case DB_KEYDATA_KEYTYPE:
274  DqsConditionInt(&sql, "KEYTYPE", condition[i].compare,
275  condition[i].data.number, i);
276  break;
277 
278  case DB_KEYDATA_STATE:
279  DqsConditionInt(&sql, "STATE", condition[i].compare,
280  condition[i].data.number, i);
281  break;
282 
283  case DB_KEYDATA_ZONE_ID:
284  DqsConditionInt(&sql, "ZONE_ID", condition[i].compare,
285  condition[i].data.number, i);
286  break;
287 
288  default:
289 
290  /* Warn about unrecognised condition code */
291 
292  MsgLog(KME_UNRCONCOD, condition[i].code);
293  }
294  }
295  }
296  DqsEnd(&sql);
297 
298  /* Execute query and free up the query string */
299 
300  status = KsmKeyInitSql(result, sql);
301  DqsFree(sql);
302 
303  return status;
304 }
305 
306 
307 
308 /*+
309  * KsmKeyInitId - Query for Key Information by ID
310  *
311  * Description:
312  * Performs a query for a key in the zone table that matches the
313  * given ID.
314  *
315  * Arguments:
316  * DB_RESULT* result
317  * Pointer to a result to be used for information retrieval. Will
318  * be NULL on error.
319  *
320  * DB_ID id
321  * ID of the object.
322  *
323  * Returns:
324  * int
325  * Status return. 0 on success.
326 -*/
327 
328 int KsmKeyInitId(DB_RESULT* result, DB_ID id)
329 {
330  DQS_QUERY_CONDITION condition[2]; /* Condition for query */
331 
332  /* Initialize */
333 
334  condition[0].code = DB_KEYDATA_ID;
335  condition[0].compare = DQS_COMPARE_EQ;
336  condition[0].data.number = (int) id;
337 
338  condition[1].compare = DQS_END_OF_LIST;
339 
340  return KsmKeyInit(result, condition);
341 }
342 
343 
344 
345 /*+
346  * KsmKey - Return Key Information
347  *
348  * Description:
349  * Returns information about the next key in the result set.
350  *
351  * Arguments:
352  * DB_RESULT result
353  * Handle from KsmKeyInit
354  *
355  * KSM_KEYDATA* data
356  * Data is returned in here.
357  *
358  * Returns:
359  * int
360  * Status return:
361  * 0 success
362  * -1 end of record set reached
363  * non-zero some error occurred and a message has been output.
364  *
365  * If the status is non-zero, the returned data is meaningless.
366 -*/
367 
368 int KsmKey(DB_RESULT result, KSM_KEYDATA* data)
369 {
370  DB_ROW row = NULL; /* Row data */
371  int status = 0; /* Return status */
372 
373  /* Check arguments */
374  if (data == NULL) {
375  return MsgLog(KSM_INVARG, "NULL data");
376  }
377 
378  /* Initialize */
379 
380  memset(data, 0, sizeof(KSM_KEYDATA));
381 
382  /* Get the next row from the data and copy data across */
383 
384  status = DbFetchRow(result, &row);
385 
386  if (status == 0) {
387  status = DbUnsignedLong(row, DB_KEYDATA_ID, &(data->keypair_id));
388  }
389 
390  if (status == 0) {
391  status = DbInt(row, DB_KEYDATA_STATE, &(data->state));
392  }
393 
394  if (status == 0) {
395  status = DbStringBuffer(row, DB_KEYDATA_GENERATE,
396  data->generate, sizeof(data->generate));
397  }
398 
399  if (status == 0) {
400  status = DbStringBuffer(row, DB_KEYDATA_PUBLISH,
401  data->publish, sizeof(data->publish));
402  }
403 
404  if (status == 0) {
405  status = DbStringBuffer(row, DB_KEYDATA_READY,
406  data->ready, sizeof(data->ready));
407  }
408 
409  if (status == 0) {
410  status = DbStringBuffer(row, DB_KEYDATA_ACTIVE,
411  data->active, sizeof(data->active));
412  }
413 
414  if (status == 0) {
415  status = DbStringBuffer(row, DB_KEYDATA_RETIRE,
416  data->retire, sizeof(data->retire));
417  }
418 
419  if (status == 0) {
420  status = DbStringBuffer(row, DB_KEYDATA_DEAD,
421  data->dead, sizeof(data->dead));
422  }
423 
424  if (status == 0) {
425  status = DbInt(row, DB_KEYDATA_KEYTYPE, &(data->keytype));
426  }
427 
428  if (status == 0) {
429  status = DbInt(row, DB_KEYDATA_ALGORITHM, &(data->algorithm));
430  }
431 
432 /* if (status == 0) {
433  status = DbInt(row, DB_KEYDATA_SIGLIFETIME, &(data->siglifetime));
434  }
435 */
436  if (status == 0) {
437  status = DbStringBuffer(row, DB_KEYDATA_LOCATION,
438  data->location, sizeof(data->location));
439  }
440 
441  if (status == 0) {
442  status = DbInt(row, DB_KEYDATA_ZONE_ID, &(data->zone_id));
443  }
444 
445  if (status == 0) {
446  status = DbInt(row, DB_KEYDATA_FIXED_DATE, &(data->fixedDate));
447  }
448 
449  if (status == 0) {
450  status = DbInt(row, DB_KEYDATA_RFC5011, &(data->rfc5011));
451  }
452  if (status == 0) {
453  status = DbInt(row, DB_KEYDATA_REVOKE, &(data->revoke));
454  }
455 
456  DbFreeRow(row);
457 
458  return status;
459 }
460 
461 
462 /*+
463  * KsmKeyEnd - End Key Information
464  *
465  * Description:
466  * Called at the end of a ksm_key cycle, frees up the stored
467  * result set.
468  *
469  * N.B. This does not clear stored error information, so allowing it
470  * to be called after a failure return from KsmKey to free up database
471  * context whilst preserving the reason for the error.
472  *
473  * Arguments:
474  * DB_RESULT result
475  * Handle from KsmKeyInit
476 -*/
477 
478 void KsmKeyEnd(DB_RESULT result)
479 {
480  DbFreeResult(result);
481 }
482 
483 
484 
485 /*+
486  * KsmKeyData - Return Data for Key
487  *
488  * Description:
489  * Returns data for the named Key.
490  *
491  * Arguments:
492  * DB_ID id
493  * Name/ID of the Key.
494  *
495  * KSM_GROUP* data
496  * Data for the Key.
497  *
498  * Returns:
499  * int
500  * Status return. One of:
501  *
502  * 0 Success
503  * -1 Key not found
504  * Other Error
505 -*/
506 
508 {
509  DB_RESULT result; /* Handle to the data */
510  int status; /* Status return code */
511 
512  status = KsmKeyInitId(&result, id);
513  if (status == 0) {
514 
515  /* Retrieve the key data */
516 
517  status = KsmKey(result, data);
518  (void) KsmKeyEnd(result);
519  }
520  /*
521  * else {
522  * On error, a message will have been output
523  * }
524  */
525 
526  return status;
527 }
528 
529 /*+
530  * KsmKeyPredict - predict how many keys are needed
531  *
532  * Description:
533  * Given a policy and a keytype work out how many keys will be required
534  * during the timeinterval specified (in seconds).
535  *
536  * We assume no emergency rollover and that a key has just been published
537  *
538  * Dt = interval
539  * Sp = safety margin
540  * Lk = lifetime of the key (either KSK or ZSK)
541  * Ek = no of standby keys
542  *
543  * no of keys = ( (Dt + Sp)/Lk ) + Ek
544  *
545  * (rounded up)
546  *
547  * Arguments:
548  * int policy_id
549  * The policy in question
550  * KSM_TYPE key_type
551  * KSK or ZSK
552  * int shared_keys
553  * 0 if keys not shared between zones
554  * int interval
555  * timespan (in seconds)
556  * int *count
557  * (OUT) the number of keys (-1 on error)
558  * int rollover_scheme
559  * KSK rollover scheme in use
560  * int zone_count
561  * Number of zones on this policy
562  *
563  * Returns:
564  * int
565  * Status return. One of:
566  *
567  * 0 Success
568  * Other Error
569 -*/
570 
571 int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count)
572 {
573  int status = 0; /* Status return */
574  KSM_PARCOLL coll; /* Parameters collection */
575 
576  /* Check arguments */
577  if (count == NULL) {
578  return MsgLog(KSM_INVARG, "NULL count");
579  }
580 
581  /* make sure that we have at least one zone */
582  if (zone_count == 0) {
583  *count = 0;
584  return status;
585  }
586 
587  /* Check that we have a valid key type */
588  if ((keytype != KSM_TYPE_KSK) && (keytype != KSM_TYPE_ZSK)) {
589  status = MsgLog(KME_UNKEYTYPE, keytype);
590  return status;
591  }
592 
593  /* Get list of parameters */
594  status = KsmParameterCollection(&coll, policy_id);
595  if (status != 0) {
596  *count = -1;
597  return status;
598  }
599 
600  /* We should have the policy now */
601  if (keytype == KSM_TYPE_KSK)
602  {
603  if (coll.ksklife == 0) {
604  *count = coll.standbyksks + 1;
605  }
606  else if (rollover_scheme == KSM_ROLL_DNSKEY) {
607  *count = ((interval + coll.pub_safety + coll.propdelay + coll.kskttl)/coll.ksklife) + coll.standbyksks + 1;
608  }
609  else if (rollover_scheme == KSM_ROLL_DS) {
610  *count = ((interval + coll.pub_safety + coll.kskpropdelay + coll.dsttl)/coll.ksklife) + coll.standbyksks + 1;
611  }
612  /* YBS: I don't think 5011 affects the number of keys needed. It
613  * does not affect lifetime, just the time the keys are published.*/
614 /* else if (rollover_scheme == KSM_ROLL_RRSET) {
615  temp = MAX((propdelay + kskttl), (kskpropdelay + dsttl));
616  if (RFC5011) {
617  temp = max(temp, 30*24*60*60);
618  }
619  *count = ((interval + coll.pub_safety + temp)/coll.ksklife) + coll.standbyksks + 1;
620  } */
621 
622  }
623  else if (keytype == KSM_TYPE_ZSK)
624  {
625  if (coll.zsklife == 0) {
626  *count = coll.standbyzsks + 1;
627  } else {
628  *count = ((interval + coll.pub_safety)/coll.zsklife) + coll.standbyzsks + 1;
629  }
630  }
631 
632  if (shared_keys == KSM_KEYS_NOT_SHARED) {
633  *count *= zone_count;
634  }
635 
636  return status;
637 }
638 
639 /*+
640  * KsmKeyCountQueue - Return Number of Keys in the queue before active state
641  *
642  * Description:
643  * Returns the number of keys in the KSM_STATE_GENERATE, KSM_STATE_PUBLISH,
644  * KSM_STATE_READY and KSM_STATE_ACTIVE state.
645  * (plus KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY
646  * for standby KSKs)
647  *
648  * Arguments:
649  * int keytype
650  * Key type, KSK or ZSK
651  *
652  * int* count (returned)
653  * Number of keys in the que.
654  *
655  * int zone_id
656  * ID of zone that we are looking at (-1 == all zones)
657  *
658  * Returns:
659  * int
660  * Status return. 0 => success, Other implies error, in which case a
661  * message will have been output.
662 -*/
663 
664 int KsmKeyCountQueue(int keytype, int* count, int zone_id)
665 {
666  int clause = 0; /* Clause count */
667  char* sql = NULL; /* SQL to interrogate database */
668  int status = 0; /* Status return */
669  char in[128]; /* Easily large enought for 7 keys */
670  size_t nchar; /* Number of output characters */
671 
672  /* Create the SQL command to interrogate the database */
673 
674  nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d, %d, %d)",
676  if (nchar >= sizeof(in)) {
677  status = MsgLog(KME_BUFFEROVF, "KsmKeyCountQueue");
678  return status;
679  }
680 
681  sql = DqsCountInit("KEYDATA_VIEW");
682  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
683  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, in, clause++);
684  if (zone_id != -1) {
685  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
686  }
687  DqsEnd(&sql);
688 
689  /* Execute the query and free resources */
690 
691  status = DbIntQuery(DbHandle(), count, sql);
692  DqsFree(sql);
693 
694  /* Report any errors */
695 
696  if (status != 0) {
697  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
698  }
699 
700  return status;
701 }
702 
703 /*+
704  * KsmKeyCountStillGood - Return Number of Keys that will still be usable at a particular
705  * time given a number of parameters
706  *
707  * Description:
708  * Returns the number of keys in the KSM_STATE_GENERATE, KSM_STATE_PUBLISH,
709  * KSM_STATE_READY, KSM_STATE_ACTIVE (or KSM_STATE_DSSUB,
710  * KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY for standby KSKs) state after
711  * the given interval.
712  *
713  * Arguments:
714  * int policy_id
715  * id of the policy for which they key must have been created
716  * (-1 == all policies)
717  * int sm
718  * id of security module
719  * (-1 == all modules)
720  * int bits
721  * size of key desired
722  * (-1 == all sizes)
723  * int algorithm
724  * algorithm of key desired
725  * (-1 == all algorithms`)
726  * int interval
727  * how many seconds in the future we are talking about
728  * const char* datetime
729  * string describing when this calculation is being run
730  *
731  * int* count (returned)
732  * Number of keys in the que.
733  *
734  * int keytype
735  * Key type, KSK or ZSK
736  *
737  * Returns:
738  * int
739  * Status return. 0 => success, Other implies error, in which case a
740  * message will have been output.
741 -*/
742 
743 int KsmKeyCountStillGood(int policy_id, int sm, int bits, int algorithm, int interval, const char* datetime, int *count, int keytype)
744 {
745  int where = 0; /* WHERE clause value */
746  char* sql = NULL; /* SQL to interrogate database */
747  int status = 0; /* Status return */
748  char in[128]; /* Easily large enought for three keys */
749  char buffer[512]; /* For constructing part of the command */
750  size_t nchar; /* Number of output characters */
751  int total_interval; /* interval plus retirement time */
752  KSM_PARCOLL collection; /* Parameters collection */
753 
754  /*
755  * Construct the "IN" statement listing the states of the keys that
756  * are included in the output.
757  */
758 
759  /* Get list of parameters */
760  status = KsmParameterCollection(&collection, policy_id);
761  if (status != 0) {
762  return status;
763  }
764 
765  if (keytype == KSM_TYPE_ZSK)
766  {
767  total_interval = KsmParameterZskTtl(&collection) +
768  KsmParameterPropagationDelay(&collection) +
769  KsmParameterPubSafety(&collection) +
770  interval;
771  } else {
772  total_interval = KsmParameterKskTtl(&collection) +
773  KsmParameterKskPropagationDelay(&collection) +
774  KsmParameterPubSafety(&collection) +
775  interval;
776  }
777 
778  nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d, %d, %d)",
780  if (nchar >= sizeof(in)) {
781  status = MsgLog(KME_BUFFEROVF, "KsmKeyCountStillGood");
782  return status;
783  }
784 
785  /*
786  * TODO is there an alternative to DATE_ADD which is more generic?
787  */
788 #ifdef USE_MYSQL
789  nchar = snprintf(buffer, sizeof(buffer),
790  "DATE_ADD('%s', INTERVAL %d SECOND)", datetime, total_interval);
791 #else
792  nchar = snprintf(buffer, sizeof(buffer),
793  "DATETIME('%s', '+%d SECONDS')", datetime, total_interval);
794 #endif /* USE_MYSQL */
795  if (nchar >= sizeof(buffer)) {
796  status = MsgLog(KME_BUFFEROVF, "KsmKeyCountStillGood");
797  return status;
798  }
799 
800  /* Create the SQL command to interrogate the database */
801 
802  /* Use 'distinct location' here so we don't count multiple entries for zones which share keys*/
803  sql = StrStrdup("SELECT COUNT(DISTINCT location) FROM KEYDATA_VIEW");
804  if (policy_id != -1) {
805  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
806  }
807  if (sm != -1) {
808  DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++);
809  }
810  if (bits != -1) {
811  DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++);
812  }
813  if (algorithm != -1) {
814  DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++);
815  }
816 
817  DqsConditionKeyword(&sql, "(STATE", DQS_COMPARE_IN, in, where++);
818  StrAppend(&sql, " or STATE is NULL)");
819 
820  /* Can't use our generic functions for this aggregated clause */
821 #ifdef USE_MYSQL
822  StrAppend(&sql, " and (RETIRE > ");
823 #else
824  StrAppend(&sql, " and (DATETIME(RETIRE) > ");
825 #endif /* USE_MYSQL */
826  StrAppend(&sql, buffer);
827  StrAppend(&sql, " or RETIRE is NULL)");
828 
829  /*DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);*/
830  DqsEnd(&sql);
831 
832  /* Execute the query and free resources */
833 
834  status = DbIntQuery(DbHandle(), count, sql);
835  DqsFree(sql);
836 
837  /* Report any errors */
838 
839  if (status != 0) {
840  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
841  }
842 
843  return status;
844 }
845 
846 /*+
847  * KsmKeyGetUnallocated
848  *
849  * Description:
850  * Given a set of policy values get the next unallocated keypair
851  * Executes:
852  * select min(id) from keydata
853  * where policy_id = policy_id
854  * and securitymodule_id = sm
855  * and size = bits
856  * and algorithm = algorithm
857  * and state is KSM_STATE_GENERATE
858  *
859  * Arguments:
860  * int policy_id
861  * id of the policy for which they key must have been created
862  * int sm
863  * id of security module
864  * int bits
865  * size of key desired
866  * int algorithm
867  * algorithm of key desired
868  * int zone_id
869  * zone we are allocating to
870  * int share_keys
871  * 0 if keys are not shared; 1 if they are
872  * int *keypair_id (out)
873  * id of next keypair
874  *
875  * Returns:
876  * int
877  * Status return. 0=> Success, non-zero => error.
878  * -1 == no free keys on that policy
879  */
880 
881 int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id)
882 {
883 
884  int where = 0; /* WHERE clause value */
885  char* sql = NULL; /* SQL query */
886  DB_RESULT result; /* Handle converted to a result object */
887  DB_ROW row = NULL; /* Row data */
888  int status = 0; /* Status return */
889  char in_sql[1024];
890  char in_sql2[1024];
891 
892  if (share_keys == KSM_KEYS_NOT_SHARED) {
893  /* Construct the query */
894  sql = DqsSpecifyInit("KEYDATA_VIEW","min(id)");
895  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
896  DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++);
897  DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++);
898  DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++);
899  DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);
900  } else {
901  snprintf(in_sql, 1024, "(select id from KEYALLOC_VIEW where zone_id = %d)", zone_id);
902  snprintf(in_sql2, 1024, "(select distinct id from KEYDATA_VIEW where policy_id = %d and state in (%d, %d))", policy_id, KSM_STATE_RETIRE, KSM_STATE_DEAD);
903 
904  /* Construct the query */
905  sql = DqsSpecifyInit("KEYALLOC_VIEW","min(id)");
906  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
907  DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++);
908  DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++);
909  DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++);
910  DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);
911  DqsConditionKeyword(&sql, "id", DQS_COMPARE_NOT_IN, in_sql, where++);
912  DqsConditionKeyword(&sql, "id", DQS_COMPARE_NOT_IN, in_sql2, where++);
913  }
914  /* Execute query and free up the query string */
915  status = DbExecuteSql(DbHandle(), sql, &result);
916  DqsFree(sql);
917 
918  if (status != 0)
919  {
920  status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle()));
921  DbFreeResult(result);
922  return status;
923  }
924 
925  /* Get the next row from the data */
926  status = DbFetchRow(result, &row);
927  if (status == 0) {
928  DbInt(row, DB_KEYDATA_ID, keypair_id);
929  }
930  else if (status == -1) {}
931  /* No rows to return (but no DB error) */
932  else {
933  status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle()));
934  }
935 
936  DbFreeRow(row);
937  DbFreeResult(result);
938  return status;
939 }
940 
941 /*+
942  * KsmMarkKeysAsDead - When deleting zones we may need to indicate that keys are now dead
943  * (i.e. when keysharing is turned off or if we removed is the last zone on a policy)
944  *
945  * Description:
946  * Marks selected keys as dead in the database.
947  *
948  * Arguments:
949  * int zone_id
950  * ID of the zone (-1 if all zones are being removed)
951  *
952  * Returns:
953  * int
954  * Status return. 0=> Success, non-zero => error.
955 -*/
956 
957 int KsmMarkKeysAsDead(int zone_id)
958 {
959  int status = 0;
960 
961  DB_RESULT result; /* Result of query */
962  KSM_KEYDATA data; /* key information */
963  char* sql = NULL; /* SQL query */
964  int clause = 0;
965 
966  /* Find all the keys which are on that zone but are not already dead */
967  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
968  DqsConditionInt(&sql, "state", DQS_COMPARE_LT, KSM_STATE_DEAD, clause++);
969  DqsConditionInt(&sql, "state", DQS_COMPARE_GT, KSM_STATE_GENERATE, clause++);
970  if (zone_id != -1) {
971  DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, clause++);
972  }
973  DqsEnd(&sql);
974 
975  /* Now iterate round the keys meeting the condition and print them */
976 
977  status = KsmKeyInitSql(&result, sql);
978  if (status == 0) {
979  status = KsmKey(result, &data);
980  while (status == 0) {
981 
982  /* Kill the Key */
983  status = KsmKillKey(data.keypair_id, zone_id);
984  if (status == 0) {
985  status = KsmKey(result, &data);
986  }
987  }
988 
989  /* Convert EOF status to success */
990 
991  if (status == -1) {
992  status = 0;
993  }
994 
995  KsmKeyEnd(result);
996  }
997 
998  DqsFree(sql);
999  return 0;
1000 }
1001 
1002 /*+
1003  * KsmKillKey - Update key status to "dead"
1004  *
1005  * Description:
1006  * Changes a keys status to dead (from any state)
1007  *
1008  * Arguments:
1009  * int keypair_id
1010  * Which key to process
1011  * int zone_id
1012  * Which zone to process
1013  *
1014  * Returns:
1015  * int
1016  * Status return. 0=> Success, non-zero => error.
1017 -*/
1018 
1019 int KsmKillKey(int keypair_id, int zone_id)
1020 {
1021  int status = 0; /* Status return */
1022  char* sql = NULL; /* SQL Statement */
1023  int set = 0;
1024  char* now = DtParseDateTimeString("now");
1025 
1026  /* Check datetime in case it came back NULL */
1027  if (now == NULL) {
1028  printf("Couldn't turn \"now\" into a date, quitting...\n");
1029  exit(1);
1030  }
1031 
1032  sql = DusInit("dnsseckeys");
1033  DusSetInt(&sql, "STATE", KSM_STATE_DEAD, set++);
1034  DusSetString(&sql, "DEAD", now, set++);
1035  DusConditionInt(&sql, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0);
1036  if (zone_id != -1) {
1037  DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, 1);
1038  }
1039  DusEnd(&sql);
1040 
1041  /* Execute the statement */
1042 
1043  status = DbExecuteSqlNoResult(DbHandle(), sql);
1044  DusFree(sql);
1045 
1046  StrFree(now);
1047 
1048  return status;
1049 }
1050 
void DbFreeResult(DB_RESULT result)
#define DB_KEYDATA_ACTIVE
Definition: db_fields.h:62
int zone_id
Definition: ksm.h:118
char ready[KSM_TIME_LENGTH]
Definition: ksm.h:110
char dead[KSM_TIME_LENGTH]
Definition: ksm.h:107
#define DB_KEYDATA_PUBLISH
Definition: db_fields.h:60
#define KSM_TYPE_ZSK
Definition: ksm.h:362
#define StrFree(x)
Definition: string_util.h:66
#define KSM_INVARG
Definition: ksmdef.h:66
int DbFetchRow(DB_RESULT result, DB_ROW *row)
#define KSM_SQLFAIL
Definition: ksmdef.h:67
#define KSM_STATE_DEAD
Definition: ksm.h:377
int KsmKeyCountStillGood(int policy_id, int sm, int bits, int algorithm, int interval, const char *datetime, int *count, int keytype)
Definition: ksm_key.c:743
union DQS_QUERY_CONDITION::@0 data
char * DqsSpecifyInit(const char *table, const char *fields)
Definition: dq_string.c:117
#define KSM_STATE_ACTIVE
Definition: ksm.h:373
int kskttl
Definition: ksm.h:492
char location[KSM_NAME_LENGTH]
Definition: ksm.h:112
int pub_safety
Definition: ksm.h:495
int KsmKillKey(int keypair_id, int zone_id)
Definition: ksm_key.c:1019
#define DB_KEYDATA_ID
Definition: db_fields.h:57
#define KSM_STATE_READY
Definition: ksm.h:371
int KsmParameterZskTtl(KSM_PARCOLL *collection)
#define KSM_ROLL_DS
Definition: ksm.h:404
int state
Definition: ksm.h:102
int KsmParameterCollection(KSM_PARCOLL *data, int policy_id)
#define KSM_KEYS_NOT_SHARED
Definition: ksm.h:397
void DusFree(char *sql)
Definition: du_string.c:223
DQS_COMPARISON compare
char retire[KSM_TIME_LENGTH]
Definition: ksm.h:111
void DqsConditionKeyword(char **query, const char *field, DQS_COMPARISON compare, const char *value, int index)
Definition: dq_string.c:251
int dsttl
Definition: ksm.h:499
char * DisSpecifyInit(const char *table, const char *cols)
Definition: di_string.c:99
#define DB_KEYDATA_ZONE_ID
Definition: db_fields.h:68
int MsgLog(int status,...)
Definition: message.c:335
int KsmKeyPairCreate(int policy_id, const char *HSMKeyID, int smID, int size, int alg, const char *generate, DB_ID *id)
Definition: ksm_key.c:84
void DusSetInt(char **sql, const char *field, int data, int clause)
Definition: du_string.c:97
void DqsFree(char *query)
Definition: dq_string.c:320
#define KSM_ROLL_DNSKEY
Definition: ksm.h:402
int ksklife
Definition: ksm.h:482
int KsmParameterKskTtl(KSM_PARCOLL *collection)
void DusConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int clause)
Definition: du_string.c:170
const char * KsmKeywordStateValueToName(int value)
Definition: ksm_keyword.c:242
char * DqsCountInit(const char *table)
Definition: dq_string.c:90
int KsmMarkKeysAsDead(int zone_id)
Definition: ksm_key.c:957
DB_HANDLE DbHandle(void)
int KsmParameterKskPropagationDelay(KSM_PARCOLL *collection)
char * StrStrdup(const char *string)
Definition: string_util.c:124
int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count)
Definition: ksm_key.c:571
void DqsConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int index)
Definition: dq_string.c:224
#define DB_KEYDATA_READY
Definition: db_fields.h:61
char * DtParseDateTimeString(const char *string)
Definition: datetime.c:614
#define KSM_STATE_DSPUBLISH
Definition: ksm.h:381
#define DB_KEYDATA_STATE
Definition: db_fields.h:58
int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, int rfc5011, const char *time, const char *retTime, DB_ID *id)
Definition: ksm_key.c:141
int DbLastRowId(DB_HANDLE handle, DB_ID *id)
int KsmKeyInitSql(DB_RESULT *result, const char *sql)
Definition: ksm_key.c:219
unsigned long DB_ID
Definition: database.h:78
int revoke
Definition: ksm.h:129
#define DB_KEYDATA_FIELDS
Definition: db_fields.h:56
const char * DbErrmsg(DB_HANDLE handle)
void DisAppendString(char **sql, const char *what)
Definition: di_string.c:142
int propdelay
Definition: ksm.h:485
#define DB_KEYDATA_FIXED_DATE
Definition: db_fields.h:69
void DbFreeRow(DB_ROW row)
int KsmParameterPropagationDelay(KSM_PARCOLL *collection)
int KsmKeyCountQueue(int keytype, int *count, int zone_id)
Definition: ksm_key.c:664
#define DB_KEYDATA_GENERATE
Definition: db_fields.h:59
int rfc5011
Definition: ksm.h:128
int DbExecuteSql(DB_HANDLE handle, const char *stmt_str, DB_RESULT *result)
int keytype
Definition: ksm.h:103
void DisEnd(char **sql)
Definition: di_string.c:170
int DbStringBuffer(DB_ROW row, int field_index, char *buffer, size_t buflen)
#define KME_SQLFAIL
Definition: kmedef.h:67
int KsmKeyInitId(DB_RESULT *result, DB_ID id)
Definition: ksm_key.c:328
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:76
int fixedDate
Definition: ksm.h:119
int algorithm
Definition: ksm.h:104
void DusEnd(char **sql)
Definition: du_string.c:202
int DbIntQuery(DB_HANDLE handle, int *value, const char *query)
#define DB_KEYDATA_REVOKE
Definition: db_fields.h:71
int KsmKeyInit(DB_RESULT *result, DQS_QUERY_CONDITION *condition)
Definition: ksm_key.c:251
char generate[KSM_TIME_LENGTH]
Definition: ksm.h:108
#define KSM_STATE_RETIRE
Definition: ksm.h:375
#define KSM_STATE_PUBLISH
Definition: ksm.h:369
int DbUnsignedLong(DB_ROW row, int field_index, unsigned long *value)
#define DB_KEYDATA_RFC5011
Definition: db_fields.h:70
char * DusInit(const char *table)
Definition: du_string.c:60
int KsmParameterPubSafety(KSM_PARCOLL *collection)
int standbyzsks
Definition: ksm.h:484
DB_ID keypair_id
Definition: ksm.h:101
void DisFree(char *sql)
Definition: di_string.c:191
int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id)
Definition: ksm_key.c:881
int kskpropdelay
Definition: ksm.h:493
#define KME_BUFFEROVF
Definition: kmedef.h:48
#define DB_KEYDATA_RETIRE
Definition: db_fields.h:63
#define DB_KEYDATA_KEYTYPE
Definition: db_fields.h:65
int KsmKeyData(DB_ID id, KSM_KEYDATA *data)
Definition: ksm_key.c:507
char publish[KSM_TIME_LENGTH]
Definition: ksm.h:109
int zsklife
Definition: ksm.h:490
#define KSM_STATE_DSSUB
Definition: ksm.h:379
#define KME_UNRCONCOD
Definition: kmedef.h:69
#define KSM_TYPE_KSK
Definition: ksm.h:360
int DbInt(DB_ROW row, int field_index, int *value)
#define DB_KEYDATA_DEAD
Definition: db_fields.h:64
void DisAppendInt(char **sql, int what)
Definition: di_string.c:131
#define DB_KEYDATA_ALGORITHM
Definition: db_fields.h:66
#define KSM_STATE_DSREADY
Definition: ksm.h:383
int standbyksks
Definition: ksm.h:483
#define KME_UNKEYTYPE
Definition: kmedef.h:68
int KsmKey(DB_RESULT result, KSM_KEYDATA *data)
Definition: ksm_key.c:368
#define KSM_STATE_GENERATE
Definition: ksm.h:367
void DusSetString(char **sql, const char *field, const char *data, int clause)
Definition: du_string.c:113
void DqsEnd(char **query)
Definition: dq_string.c:299
int DbExecuteSqlNoResult(DB_HANDLE handle, const char *stmt_str)
void KsmKeyEnd(DB_RESULT result)
Definition: ksm_key.c:478
#define DB_KEYDATA_LOCATION
Definition: db_fields.h:67
char active[KSM_TIME_LENGTH]
Definition: ksm.h:106