Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern struct file_info *file_info;
#define POLICY_TLSA_HOST 8
#define POLICY_KSK_EXISTS 9
#define POLICY_SMIMEA_HOST 10
#define POLICY_NSEC3_CONSISTENCY 11

#define MAX_TIMES_TO_CHECK 32

Expand Down
75 changes: 41 additions & 34 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,36 +423,38 @@ open_zone_file(char *fname)

void usage(char *err)
{
if (err)
fprintf(stderr, "%s\n", err);
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s -h\n", thisprogname());
fprintf(stderr, " %s [options] zone-file\n", thisprogname());
fprintf(stderr, "Usage parameters:\n");
fprintf(stderr, "\t-h\t\tproduce usage text and quit\n");
fprintf(stderr, "\t-f\t\tquit on first validation error\n");

fprintf(stderr, "\t-p name\tperform policy check <name>\n");
fprintf(stderr, "\t\t\tsingle-ns\n");
fprintf(stderr, "\t\t\tcname-other-data\n");
fprintf(stderr, "\t\t\tdname\n");
fprintf(stderr, "\t\t\tnsec3param-not-apex\n");
fprintf(stderr, "\t\t\tmx-alias\n");
fprintf(stderr, "\t\t\tns-alias\n");
fprintf(stderr, "\t\t\trp-txt-exists\n");
fprintf(stderr, "\t\t\ttlsa-host\n");
fprintf(stderr, "\t\t\tksk-exists\n");
fprintf(stderr, "\t\t\tsmimea-host\n");
fprintf(stderr, "\t\t\tall\n");

fprintf(stderr, "\t-n N\t\tuse N worker threads\n");
fprintf(stderr, "\t-q\t\tquiet - do not produce any output\n");
fprintf(stderr, "\t-s\t\tprint validation summary/stats\n");
fprintf(stderr, "\t-v\t\tbe extra verbose\n");
fprintf(stderr, "\t-I path\tuse this path for $INCLUDE files\n");
fprintf(stderr, "\t-z origin\tuse this origin as initial $ORIGIN\n");
fprintf(stderr, "\t-t epoch-time\tuse this time instead of \"now\"\n");
exit(1);
if (err)
fprintf(stderr, "%s\n", err);
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s -h\n", thisprogname());
fprintf(stderr, " %s [options] zone-file\n", thisprogname());
fprintf(stderr, "Usage parameters:\n");
fprintf(stderr, "\t-h\t\tproduce usage text and quit\n");
fprintf(stderr, "\t-f\t\tquit on first validation error\n");

fprintf(stderr, "\t-p name\tperform policy check <name>\n");
fprintf(stderr, "\t\t\tsingle-ns\n");
fprintf(stderr, "\t\t\tcname-other-data\n");
fprintf(stderr, "\t\t\tdname\n");
fprintf(stderr, "\t\t\tnsec3param-not-apex\n");
fprintf(stderr, "\t\t\tmx-alias\n");
fprintf(stderr, "\t\t\tns-alias\n");
fprintf(stderr, "\t\t\trp-txt-exists\n");
fprintf(stderr, "\t\t\ttlsa-host\n");
fprintf(stderr, "\t\t\tksk-exists\n");
fprintf(stderr, "\t\t\tnsec3-consistency\n");
fprintf(stderr, "\t\t\tsmimea-host\n");
fprintf(stderr, "\t\t\tall\n");

fprintf(stderr, "\t-n N\t\tuse N worker threads\n");
fprintf(stderr, "\t-q\t\tquiet - do not produce any output\n");
fprintf(stderr, "\t-s\t\tprint validation summary/stats\n");
fprintf(stderr, "\t-v\t\tbe extra verbose\n");
fprintf(stderr, "\t-I path\tuse this path for $INCLUDE files\n");
fprintf(stderr, "\t-z origin\tuse this origin as initial $ORIGIN\n");
fprintf(stderr, "\t-t epoch-time\tuse this time instead of \"now\"\n");
exit(1);

}

struct rr_methods rr_methods[T_MAX+1];
Expand Down Expand Up @@ -577,6 +579,8 @@ main(int argc, char **argv)
G.opt.policy_checks[POLICY_SMIMEA_HOST] = 1;
} else if (strcmp(optarg, "ksk-exists") == 0) {
G.opt.policy_checks[POLICY_KSK_EXISTS] = 1;
} else if (strcmp(optarg, "nsec3-consistency") == 0) {
G.opt.policy_checks[POLICY_NSEC3_CONSISTENCY] = 1;
} else {
usage("unknown policy name");
}
Expand Down Expand Up @@ -622,10 +626,13 @@ main(int argc, char **argv)
read_zone_file();
validate_zone();
verify_all_keys();
if (G.nsec3_present) {
if (first_nsec3) nsec3_validate(&first_nsec3->rr);
perform_remaining_nsec3checks();
}

if (G.nsec3_present) {
if (first_nsec3) nsec3_validate(&first_nsec3->rr);
perform_remaining_nsec3checks();
if (G.opt.policy_checks[POLICY_NSEC3_CONSISTENCY]) nsec3_consistency_policy_check();
}

if (G.dnssec_active && G.opt.policy_checks[POLICY_KSK_EXISTS]) {
dnskey_ksk_policy_check();
}
Expand Down
44 changes: 44 additions & 0 deletions nsec3checks.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,47 @@ void *check_typemap(struct binary_data type_bitmap, struct named_rr *named_rr, s
}
return reference_rr;
}


void nsec3_consistency_policy_check(void)
{
if (!first_nsec3) return;
struct rr_nsec3 *nsec3;
uint8_t first_hash_algorithm=first_nsec3->hash_algorithm;
uint8_t first_flags=first_nsec3->flags;
uint16_t first_iterations=first_nsec3->iterations;
struct binary_data first_salt;
first_salt.length=first_nsec3->salt.length;
if (first_nsec3->salt.data) {
first_salt.data=malloc(first_nsec3->salt.length);
if (first_salt.data==NULL) {
croak(1,"out of memory error");
}
memcpy(first_salt.data, first_nsec3->salt.data, first_nsec3->salt.length);
} else {
first_salt.data=NULL;
}
nsec3 = first_nsec3->next_nsec3;
while (nsec3) {
if (nsec3->hash_algorithm != first_hash_algorithm) {
moan(nsec3->rr.file_name, nsec3->rr.line,
"inconsistent NSEC3 hash algorithm");
}
if (nsec3->flags != first_flags) {
moan(nsec3->rr.file_name, nsec3->rr.line,
"inconsistent NSEC3 flags");
}
if (nsec3->iterations != first_iterations) {
moan(nsec3->rr.file_name, nsec3->rr.line,
"inconsistent NSEC3 iterations");
}
if (nsec3->salt.length != first_salt.length ||
nsec3->salt.data==NULL || first_salt.data==NULL ||
memcmp(nsec3->salt.data,first_salt.data,first_salt.length)!=0) {
moan(nsec3->rr.file_name, nsec3->rr.line,
"inconsistent NSEC3 salt");
}
nsec3 = nsec3->next_nsec3;
}
free(first_salt.data);
}
1 change: 1 addition & 0 deletions rr.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ extern void verify_all_keys(void);
extern void* nsec3_validate(struct rr *rrv);
extern void *remember_nsec3(char *name, struct rr_nsec3 *rr);
extern void perform_remaining_nsec3checks(void);
extern void nsec3_consistency_policy_check(void);
extern void *check_typemap(struct binary_data type_bitmap, struct named_rr *named_rr, struct rr *reference_rr);

#endif
1 change: 1 addition & 0 deletions t/issues/42-consistency-of-nsec3-chain/Kde.+008+05821.ds
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
de. IN DS 5821 8 2 53730e8e7e492d478091e0a4de40b13bd567be1d29b518a51c57eae40c928c8b
1 change: 1 addition & 0 deletions t/issues/42-consistency-of-nsec3-chain/Kde.+008+05821.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
de. IN DNSKEY 257 3 8 AwEAAchiXLkVWUzOZGSiQ2Dz4HRuRIZ5f09SoSFQ2zR+WSTxtxAlGt4+YPn58I5j9aCKXlQhJZWpHcpMKj0Bafqpxb4z/sDcD3QRtxpo8sPyh7Wq4j9SUINiSwq+JZjEewUqCMh9EEE2+sm0C/Dhpuqp5s0Oqy/mx9wbaokN1TbYlJ7MLV48t6Jxl5tkSOwMrLVARjp366J/MyWeHQDcBfUCTH0KJVr4JgaNSw0rvenYi9ms6lJ7MaaK5MA/Odem4/lvG02mN0XaB/LAI9EkgsxaPW1qc3KZlPBAigmo5ATgF+lhVgHpHzeGmDXYQ5JcWtNmxoA7qanGvoqEX5RR/WcrzsE= ;{id = 5821 (ksk), size = 2048b}
10 changes: 10 additions & 0 deletions t/issues/42-consistency-of-nsec3-chain/Kde.+008+05821.private
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: yGJcuRVZTM5kZKJDYPPgdG5Ehnl/T1KhIVDbNH5ZJPG3ECUa3j5g+fnwjmP1oIpeVCEllakdykwqPQFp+qnFvjP+wNwPdBG3Gmjyw/KHtariP1JQg2JLCr4lmMR7BSoIyH0QQTb6ybQL8OGm6qnmzQ6rL+bH3BtqiQ3VNtiUnswtXjy3onGXm2RI7AystUBGOnfron8zJZ4dANwF9QJMfQolWvgmBo1LDSu96diL2azqUnsxporkwD8516bj+W8bTaY3RdoH8sAj0SSCzFo9bWpzcpmU8ECKCajkBOAX6WFWAekfN4aYNdhDklxa02bGgDupqca+ioRflFH9ZyvOwQ==
PublicExponent: AQAB
PrivateExponent: dy5hncd/1HnRJjWIQ6rpbfaDlUPAH6qyoUEZD3CyjpGhYt3ezB5nyWYJ2HbFidWiYwFP/GKYkFCasqwbn3XIYedE9uor2soKkI+pDDg81SUs6aKItowIu/v6GpGJ5blpfe08dL1BjiQjEgL0JxAkcQPvd08YweYgiCGNFdDdHFCftQZ7N1nR8Ub4AiMAUFye3UYiqeKPkqHP4TsIUKyJpNXehIPh1ZeHs9kHyatJ78zU85DRc+W9YW1+BHl+C1MKZe7sEmjD/Lrq1N4iYxMT2hZAYuPKtOzDDRzJShMSFSm7nt7vhQheu/TqGoUg1CNUYFlfcaPuFZztOq2vsoNmkQ==
Prime1: 9h1k149kBgwK7bU1FmLlx/AgYTg2iRzm7rmP4dTu0sm3E5iJi3X1v2fEWDkyJWG/Q9ZQeWKPy2LFYfp/7PqyXYAQWaxZlvnWQTIleIbFwyXfukg8puXJzxXqYDqYxhVMfRDpgeFpLW2lD9pjBM08ktkQqSXoYy8OUnPVwpCPtQ0=
Prime2: 0G7BorvY/9EchLU3cgvWUW8iRV6ULrZUHHQioUsU+i/0iE82nMMJHiQxpLwafGJUMUhsBY4uR2PanUzqvHV6yNEyDPTpQ8ihA3r6w06dL9PfOC0WYFiOd0RRKuQ5l51ZEs+8f1Df6adOFT3wa+R/gxPbg+aQielk8ZCq7Fw7+4U=
Exponent1: bfnChwRfGMim1YOknkVBEm+9uFOrIufUVZZ7sdk5gt16Pnpp8/SZBJe0yAt+2e9szT5mJWeig6q2MssCAP4hV+CS7c8zFWC8mdNzpQDsPACfkZkX6ShDXpMXcTqd6922mShGf7AfFJqrKINYvduMFr6CUGNNDY0IZFW4jkGUxb0=
Exponent2: E4L6v3gkRTZXHBk2uodfJbpok+PZrVHGJ++7OiwkJ5OLqaL4ss4TMW4j847kT9aImSB1dEOuE2LGmUkVBFVfDCOBMvNOTtkeMYw2o0fdsRd9Yu3dlWFU3NdZXdGFjqrdJsSpmaWBgIb36UcmFYOLaELYns1bpH1jxLVNOtkbiF0=
Coefficient: oH7Esu0WXCXGVzSAITC4hTevv9kIoCQZcz7BMEMHsTmEVPGs4srwXwCML2HVrMuWFHndMoGZ/Q16UB5JDSIIA09dPJ6U70sD951vrczi+1yZqrufiEEiIdP7eDihFsgPTI7Rx8hr6NIII+UVC+TAbnmF/BFmsZdEDY/ltlWCxts=
1 change: 1 addition & 0 deletions t/issues/42-consistency-of-nsec3-chain/Kde.+008+11286.ds
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
de. IN DS 11286 8 2 a0c461942846d0458535d87fa980c97dfc2f134f6c5b3f65d388ab1bc84ce5d2
1 change: 1 addition & 0 deletions t/issues/42-consistency-of-nsec3-chain/Kde.+008+11286.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
de. IN DNSKEY 256 3 8 AwEAAaIvRZHdrSo8+jolmskEoENzJ76lXMQFOiA7TK3MFPsSyqYn7F7pvt1p22DwdgGEGHsRoxxuE4j+va/iEpLnUe7TQGLfByhkdTGR8ip0pZ9Fftv/U/d/18iLkj6a+bUnsKbmTbZpXG7E6gBRCAV9AlnA0HdZ/RDLRJiF3gebU0Dh ;{id = 11286 (zsk), size = 1024b}
10 changes: 10 additions & 0 deletions t/issues/42-consistency-of-nsec3-chain/Kde.+008+11286.private
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: oi9Fkd2tKjz6OiWayQSgQ3MnvqVcxAU6IDtMrcwU+xLKpifsXum+3WnbYPB2AYQYexGjHG4TiP69r+ISkudR7tNAYt8HKGR1MZHyKnSln0V+2/9T93/XyIuSPpr5tSewpuZNtmlcbsTqAFEIBX0CWcDQd1n9EMtEmIXeB5tTQOE=
PublicExponent: AQAB
PrivateExponent: AtkvsJsjEm3VuzWz3TnukqCwHwIKegrZdX11IExIRgyTcI2c8iHKz1qvlqlCeU5Xm7m4kqRARZSrwi4HQ3s6jh8OL4/5OIUhy5q2kxqnHW2EYBeTDIWCBEJuZVcIa72LSRoW9zZnUynswwDJtiFMiWgU05zcrZraFMAmV/qZYT0=
Prime1: 2DgMTz5yYEnub81/TKJviSNBQRnCekrVhyKW0P3AFvakhuPEr/6JjdBE2SdFYgyvsLhx6icxJcc7TJYQG0J5Tw==
Prime2: wAYy8JU5Ka/hYUT1nWYksmSWh0JqRwscSXYoBvqsV+TKr3fjoTn110GPh7ugEz/LSaXEj5N9cYOuIa8jjRu2zw==
Exponent1: lXdpSv5oIpf48+Cit18yqyJr4YzlG5TPtvL6Ps6rEzS812JsfR0ACcCHV3YGSJlsekWGuc8N8oefPnod+DojkQ==
Exponent2: B+V5XMlWI2+3He/fBcz4f1mBkyhZBHjhfefc94SBZ8/hwdt1QeEHSgXJKDS//WqnKm0lqx3Oj8dxdrMkDB5yow==
Coefficient: fMFqf/h0AeHrB3G5njdSj7qZ3g6rJbg4HZgVHhdrkftB6dRH/OfejMW2KN9RXDHxILjll/BAEqaUodF8u4wlUw==
Loading