private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >> "$infile"
cp $infile $zonefile
$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
+
+# Test #2375, the "three is a crowd" bug, where a new key is introduced but the
+# previous rollover has not finished yet. In other words, we have a key KEY2
+# that is the successor of key KEY1, and we introduce a new key KEY3 that is
+# the successor of key KEY2:
+#
+# KEY1 < KEY2 < KEY3.
+#
+# The expected behavior is that all three keys remain in the zone, and not
+# the bug behavior where KEY2 is removed and immediately replaced with KEY3.
+#
+# Set up a zone that has a KSK (KEY1) and have the successor key (KEY2)
+# published as well.
+setup three-is-a-crowd.kasp
+# These times are the same as step3.ksk-doubleksk.autosign.
+TactN="now-60d"
+TretN="now"
+TremN="now+50h"
+TpubN1="now-27h"
+TsbmN1="now"
+TactN1="${TretN}"
+TretN1="now+60d"
+TremN1="now+1490h"
+ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN} -D ${TremN}"
+newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TsbmN1} -I ${TretN1} -D ${TremN1}"
+zsktimes="-P ${TactN} -A ${TactN}"
+KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2> keygen.out.$zone.1)
+KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2> keygen.out.$zone.2)
+ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2> keygen.out.$zone.3)
+$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" > settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" > settime.out.$zone.2 2>&1
+$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" > settime.out.$zone.3 2>&1
+# Set key rollover relationship.
+key_successor $KSK1 $KSK2
+# Sign zone.
+cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" > "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >> "$infile"
+private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >> "$infile"
+cp $infile $zonefile
+$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile > signer.out.$zone.1 2>&1
#
# Test #2375: Scheduled rollovers are happening faster than they can finish
#
-set_zone "step1.three-is-a-crowd.kasp"
-set_policy "default" "1" "3600"
+set_zone "three-is-a-crowd.kasp"
+set_policy "ksk-doubleksk" "3" "7200"
set_server "ns3" "10.53.0.3"
-# TODO (GL #2471).
+CDNSKEY="no"
+# These are the same time values as calculated for ksk-doubleksk.
+Lksk=5184000
+Lzsk=31536000
+IretKSK=180000
+IretZSK=867600
+# KSK (KEY1) is outgoing.
+key_clear "KEY1"
+set_keyrole "KEY1" "ksk"
+set_keylifetime "KEY1" "${Lksk}"
+set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY1" "yes"
+set_zonesigning "KEY1" "yes"
+set_keystate "KEY1" "GOAL" "hidden"
+set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY1" "STATE_DS" "unretentive"
+# KSK (KEY2) is incoming.
+key_clear "KEY2"
+set_keyrole "KEY2" "ksk"
+set_keylifetime "KEY2" "${Lksk}"
+set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY2" "yes"
+set_zonesigning "KEY2" "no"
+set_keystate "KEY2" "GOAL" "omnipresent"
+set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY2" "STATE_KRRSIG" "omnipresent"
+set_keystate "KEY2" "STATE_DS" "rumoured"
+# We will introduce the third KSK shortly.
+key_clear "KEY3"
+# ZSK (KEY4).
+key_clear "KEY4"
+set_keyrole "KEY4" "zsk"
+set_keylifetime "KEY4" "${Lzsk}"
+set_keyalgorithm "KEY4" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY4" "no"
+set_zonesigning "KEY4" "yes"
+set_keystate "KEY4" "GOAL" "omnipresent"
+set_keystate "KEY4" "STATE_DNSKEY" "omnipresent"
+set_keystate "KEY4" "STATE_ZRRSIG" "omnipresent"
+# Run preliminary tests.
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
+# Roll over KEY2.
+# Set expected key lifetime, which is DNSKEY TTL plus the zone propagation delay,
+# plus the publish-safety: 7200s + 1h + 1d = 97200 seconds.
+set_keylifetime "KEY2" "97200"
+created=$(key_get KEY2 CREATED)
+rndc_rollover "$SERVER" "$DIR" $(key_get KEY2 ID) "${created}" "$ZONE"
+# Update expected number of keys and key states.
+set_keystate "KEY2" "GOAL" "hidden"
+set_policy "ksk-doubleksk" "4" "7200"
+CDNSKEY="no"
+# New KSK (KEY3) is introduced.
+set_keyrole "KEY3" "ksk"
+set_keylifetime "KEY3" "${Lksk}"
+set_keyalgorithm "KEY3" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
+set_keysigning "KEY3" "yes"
+set_zonesigning "KEY3" "no"
+set_keystate "KEY3" "GOAL" "omnipresent"
+set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
+set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
+set_keystate "KEY3" "STATE_DS" "hidden"
+# Run tests again. We now expect four keys (3x KSK, 1x ZSK).
+check_keys
+check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
+check_apex
+check_subdomain
+dnssec_verify
# Test dynamic zones that switch to inline-signing.
set_zone "dynamic2inline.kasp"