From 2dd79f4cf0a8caac29a215870e6bedc8ebf0bf00 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Thu, 3 Oct 2024 15:20:28 -0500 Subject: [PATCH] Update test for CA with sequential serial numbers pkispawn has been modified to provide more params to configure the sequential serial numbers in CA. The params can also be added for KRA if needed later. The test for CA with sequential serial numbers has been updated to perform more detailed steps and verification. The test will now use small ranges to make it easier to verify the changes in the CS.cfg and DS. The test will also use SerialNumberUpdateJob to update the ranges immediately instead of waiting for SerialNumberUpdateTask to run. A more complex test with CA clones will be added separately later. --- .github/workflows/ca-sequential-test.yml | 1209 ++++++++++++++++- base/server/etc/default.cfg | 8 + .../python/pki/server/deployment/__init__.py | 65 +- .../com/netscape/cmscore/dbs/Repository.java | 12 + .../server/cli/SubsystemRangeUpdateCLI.java | 21 +- 5 files changed, 1238 insertions(+), 77 deletions(-) diff --git a/.github/workflows/ca-sequential-test.yml b/.github/workflows/ca-sequential-test.yml index 740068d1089..985ce44a2d3 100644 --- a/.github/workflows/ca-sequential-test.yml +++ b/.github/workflows/ca-sequential-test.yml @@ -1,4 +1,8 @@ name: CA with Sequential Serial Numbers +# +# This test creates a CA subsystem with sequential serial numbers +# for certs and requests, performs enrollments, and verifies that +# the number ranges are maintained properly in CS.cfg and DS. on: workflow_call @@ -27,54 +31,1144 @@ jobs: - name: Create network run: docker network create example + #################################################################################################### + # Create CA with Sequential Serial Numbers + # + # requests: + # - range: 1 - 10 decimal + # - increment: 10 decimal + # - minimum: 5 decimal + # certs: + # - range: 1 - 10 hex (1 - 16 decimal) + # - increment: 10 hex (16 decimal) + # - minimum: 8 decimal + - name: Set up DS container run: | tests/bin/ds-create.sh \ --image=${{ env.DS_IMAGE }} \ --hostname=ds.example.com \ + --network=example \ + --network-alias=ds.example.com \ --password=Secret.123 \ ds - - name: Connect DS container to network - run: docker network connect example ds --alias ds.example.com - - name: Set up PKI container run: | - tests/bin/runner-init.sh pki - env: - HOSTNAME: pki.example.com - - - name: Connect PKI container to network - run: docker network connect example pki --alias pki.example.com + tests/bin/runner-init.sh \ + --hostname=pki.example.com \ + --network=example \ + --network-alias=pki.example.com \ + pki - - name: Install CA + - name: Create CA run: | docker exec pki pkispawn \ -f /usr/share/pki/server/examples/installation/ca.cfg \ -s CA \ -D pki_ds_url=ldap://ds.example.com:3389 \ - -D pki_cert_id_generator=legacy \ -D pki_request_id_generator=legacy \ + -D pki_request_number_range_start=1 \ + -D pki_request_number_range_end=10 \ + -D pki_request_number_range_increment=10 \ + -D pki_request_number_range_minimum=5 \ + -D pki_request_number_range_transfer=5 \ + -D pki_cert_id_generator=legacy \ + -D pki_serial_number_range_start=1 \ + -D pki_serial_number_range_end=10 \ + -D pki_serial_number_range_increment=10 \ + -D pki_serial_number_range_minimum=8 \ + -D pki_serial_number_range_transfer=8 \ -v - - name: Check CA certs and keys + - name: Check requests + run: | + docker exec pki pki-server ca-cert-request-find | tee output + + grep "Request ID:" output | wc -l > actual + + # there should be 6 requests + echo "6" > expected + diff expected actual + + - name: Check certs + run: | + docker exec pki pki-server ca-cert-find | tee output + + grep "Serial Number:" output | wc -l > actual + + # there should be 6 certs + echo "6" > expected + diff expected actual + + - name: Check request range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginRequestNumber \ + -e dbs.endRequestNumber \ + -e dbs.requestCloneTransferNumber \ + -e dbs.requestIncrement \ + -e dbs.requestLowWaterMark \ + | tee actual + + # request range should be 1 - 10 decimal (total: 10, remaining: 4) + cat > expected << EOF + dbs.beginRequestNumber=1 + dbs.endRequestNumber=10 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected actual + + - name: Check cert range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginSerialNumber \ + -e dbs.endSerialNumber \ + -e dbs.serialCloneTransferNumber \ + -e dbs.serialIncrement \ + -e dbs.serialLowWaterMark \ + | tee actual + + # cert range should be 1 - 10 hex (total: 16, remaining: 10) + cat > expected << EOF + dbs.beginSerialNumber=1 + dbs.endSerialNumber=10 + dbs.serialCloneTransferNumber=8 + dbs.serialIncrement=10 + dbs.serialLowWaterMark=8 + EOF + + diff expected actual + + - name: Check request repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=ca,ou=requests,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # request nextRange should be incremented by 10 decimal to 11 + cat > expected << EOF + nextRange: 11 + serialno: 010 + EOF + + diff expected actual + + - name: Check cert repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ca,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # ideally, cert nextRange should be incremented by 10 hex (16 decimal) + # to 11 hex (17 decimal), but currently the attribute is always read + # as decimal in: + # - Repository.getNextRange() + # - SubsystemRangeUpdateCLI.updateSerialNumberRange() + cat > expected << EOF + nextRange: 11 + serialno: 011 + EOF + + diff expected actual + + - name: Check request range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=requests,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # serial number management is disabled so there are no range objects created + diff /dev/null output + + - name: Check cert range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # serial number management is disabled so there are no range objects created + diff /dev/null output + + #################################################################################################### + # Enable serial number management + # + # Restarting PKI server with serial management enabled will trigger + # a new range allocation for requests since the remaining numbers in + # the current range (i.e. 4) is below the minimum (i.e. 5). + # + # For certs there is no new allocation since the remaining numbers + # in the current range (i.e. 10) is still above the minimum (i.e. 8). + + - name: Enable serial number management + run: | + docker exec pki pki-server ca-config-set dbs.enableSerialManagement true + + # disable serial number update background task + docker exec pki pki-server ca-config-set ca.serialNumberUpdateInterval 0 + + # enable serial number update manual job + docker exec pki pki-server ca-config-set jobsScheduler.enabled true + docker exec pki pki-server ca-config-set jobsScheduler.job.serialNumberUpdate.enabled true + + # restart CA subsystem + docker exec pki pki-server ca-redeploy --wait + + - name: Check request range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginRequestNumber \ + -e dbs.endRequestNumber \ + -e dbs.requestCloneTransferNumber \ + -e dbs.requestIncrement \ + -e dbs.requestLowWaterMark \ + | tee actual + + # request range should be 1 - 10 decimal (total: 10, remaining: 4) + cat > expected << EOF + dbs.beginRequestNumber=1 + dbs.endRequestNumber=10 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected actual + + - name: Check cert range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginSerialNumber \ + -e dbs.endSerialNumber \ + -e dbs.serialCloneTransferNumber \ + -e dbs.serialIncrement \ + -e dbs.serialLowWaterMark \ + | tee actual + + # cert range should be 1 - 10 hex (total: 16, remaining: 10) + cat > expected << EOF + dbs.beginSerialNumber=1 + dbs.endSerialNumber=10 + dbs.serialCloneTransferNumber=8 + dbs.serialIncrement=10 + dbs.serialLowWaterMark=8 + EOF + + diff expected actual + + - name: Check request repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=ca,ou=requests,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # request nextRange should be incremented by 10 decimal + cat > expected << EOF + nextRange: 21 + serialno: 010 + EOF + + diff expected actual + + - name: Check cert repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ca,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # cert nextRange should be the same + cat > expected << EOF + nextRange: 11 + serialno: 011 + EOF + + diff expected actual + + - name: Check request range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=requests,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + output \ + | sort > actual + + # new request range should be 11 - 20 decimal (total: 10) + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: pki.example.com + EOF + + diff expected actual + + - name: Check cert range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no new cert range + diff /dev/null output + + #################################################################################################### + # Enroll 10 certs + # + # This will create 10 requests and 10 certs. For requests, since + # the remaining numbers in the current range is below the minimum, + # it will automatically switch to the new range. + # + # For certs, it will exhaust the current range but not switch to a + # new range. + + - name: Install admin cert + run: | + docker exec pki pki-server cert-export \ + --cert-file ca_signing.crt \ + ca_signing + + docker exec pki pki nss-cert-import \ + --cert ca_signing.crt \ + --trust CT,C,C \ + ca_signing + + docker exec pki pki pkcs12-import \ + --pkcs12 /root/.dogtag/pki-tomcat/ca_admin_cert.p12 \ + --pkcs12-password Secret.123 + + - name: Enroll 10 certs + run: | + docker exec pki pki \ + nss-cert-request \ + --subject "uid=testuser" \ + --ext /usr/share/pki/tools/examples/certs/testuser.conf \ + --csr testuser.csr + + for i in $(seq 1 10); do + docker exec pki pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec pki openssl x509 -in testuser.crt -serial -noout + done + + - name: Check requests + run: | + docker exec pki pki-server ca-cert-request-find | tee output + + grep "Request ID:" output | wc -l > actual + + # there should be 16 requests + echo "16" > expected + diff expected actual + + - name: Check certs + run: | + docker exec pki pki-server ca-cert-find | tee output + + grep "Serial Number:" output | wc -l > actual + + # there should be 16 certs + echo "16" > expected + diff expected actual + + - name: Check request range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginRequestNumber \ + -e dbs.endRequestNumber \ + -e dbs.requestCloneTransferNumber \ + -e dbs.requestIncrement \ + -e dbs.requestLowWaterMark \ + | tee actual + + # request range should be 11 - 20 decimal (total: 10, remaining: 4) + cat > expected << EOF + dbs.beginRequestNumber=11 + dbs.endRequestNumber=20 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected actual + + - name: Check cert range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginSerialNumber \ + -e dbs.endSerialNumber \ + -e dbs.serialCloneTransferNumber \ + -e dbs.serialIncrement \ + -e dbs.serialLowWaterMark \ + | tee actual + + # cert range should be 1 - 10 hex (total: 16, remaining: 0) + cat > expected << EOF + dbs.beginSerialNumber=1 + dbs.endSerialNumber=10 + dbs.serialCloneTransferNumber=8 + dbs.serialIncrement=10 + dbs.serialLowWaterMark=8 + EOF + + diff expected actual + + - name: Check request repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=ca,ou=requests,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # request nextRange should be the same + cat > expected << EOF + nextRange: 21 + serialno: 010 + EOF + + diff expected actual + + - name: Check cert repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ca,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # cert nextRange should be the same + cat > expected << EOF + nextRange: 11 + serialno: 011 + EOF + + diff expected actual + + - name: Check request range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=requests,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + output \ + | sort > actual + + # request range objects should be the same + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: pki.example.com + EOF + + diff expected actual + + - name: Check cert range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # cert range objects should be the same + diff /dev/null output + + #################################################################################################### + # Enroll a cert when range is exhausted + # + # This will create one request but fails to create another cert. + # For some reason requests can switch to a new range automatically, + # but certs cannot. + + - name: Enroll a cert when range is exhausted + run: | + docker exec pki pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt \ + > >(tee stdout) 2> >(tee stderr >&2) || true + + # TODO: fix missing request ID and typo + cat > expected << EOF + PKIException: Server Internal Error: Request was completed with errors. + CA has exausted all available serial numbers + EOF + + diff expected stderr + + - name: Check requests + run: | + docker exec pki pki-server ca-cert-request-find | tee output + + grep "Request ID:" output | wc -l > actual + + # there should be 17 requests + echo "17" > expected + diff expected actual + + - name: Check certs run: | - # check certs - docker exec pki pki-server cert-find + docker exec pki pki-server ca-cert-find | tee output - # check keys - echo "Secret.123" > password.txt - docker cp password.txt pki:password.txt - docker exec pki certutil -K \ - -d /var/lib/pki/pki-tomcat/conf/alias \ - -f password.txt | tee output + grep "Serial Number:" output | wc -l > actual - # there should be no orphaned keys - echo "0" > expected - grep "(orphan)" output | wc -l > actual + # there should be 16 certs + echo "16" > expected diff expected actual - # https://github.com/dogtagpki/pki/wiki/Configuring-CA-with-Random-Serial-Numbers-v3 + - name: Check request range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginRequestNumber \ + -e dbs.endRequestNumber \ + -e dbs.requestCloneTransferNumber \ + -e dbs.requestIncrement \ + -e dbs.requestLowWaterMark \ + | tee actual + + # request range should be 11 - 20 decimal (total: 10, remaining: 3) + cat > expected << EOF + dbs.beginRequestNumber=11 + dbs.endRequestNumber=20 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected actual + + - name: Check cert range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginSerialNumber \ + -e dbs.endSerialNumber \ + -e dbs.serialCloneTransferNumber \ + -e dbs.serialIncrement \ + -e dbs.serialLowWaterMark \ + | tee actual + + # cert range should be 1 - 10 hex (total: 16, remaining: 0) + cat > expected << EOF + dbs.beginSerialNumber=1 + dbs.endSerialNumber=10 + dbs.serialCloneTransferNumber=8 + dbs.serialIncrement=10 + dbs.serialLowWaterMark=8 + EOF + + diff expected actual + + - name: Check request repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=ca,ou=requests,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # request nextRange should be the same + cat > expected << EOF + nextRange: 21 + serialno: 010 + EOF + + diff expected actual + + - name: Check cert repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ca,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # cert nextRange should be the same + cat > expected << EOF + nextRange: 11 + serialno: 011 + EOF + + diff expected actual + + - name: Check request range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=requests,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + output \ + | sort > actual + + # request range objects should be the same + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: pki.example.com + EOF + + diff expected actual + + - name: Check cert range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # cert range objects should be the same + diff /dev/null output + + #################################################################################################### + # Update serial numbers + # + # This will allocate new ranges for requests and certs since + # the remaining numbers in their ranges are below the minimum. + + - name: Update serial numbers + run: | + docker exec pki pki -n caadmin ca-job-start serialNumberUpdate + + - name: Check request range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginRequestNumber \ + -e dbs.endRequestNumber \ + -e dbs.requestCloneTransferNumber \ + -e dbs.requestIncrement \ + -e dbs.requestLowWaterMark \ + | tee actual + + # request range should be 11 - 20 decimal (total: 10, remaining: 3) + cat > expected << EOF + dbs.beginRequestNumber=11 + dbs.endRequestNumber=20 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected actual + + - name: Check cert range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginSerialNumber \ + -e dbs.endSerialNumber \ + -e dbs.serialCloneTransferNumber \ + -e dbs.serialIncrement \ + -e dbs.serialLowWaterMark \ + | tee actual + + # cert range should be 1 - 10 hex (total: 16, remaining: 0) + cat > expected << EOF + dbs.beginSerialNumber=1 + dbs.endSerialNumber=10 + dbs.serialCloneTransferNumber=8 + dbs.serialIncrement=10 + dbs.serialLowWaterMark=8 + EOF + + diff expected actual + + - name: Check request repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=ca,ou=requests,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # request nextRange should be incremented by 10 decimal to 31 decimal + cat > expected << EOF + nextRange: 31 + serialno: 010 + EOF + + diff expected actual + + - name: Check cert repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ca,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # cert nextRequest should incremented by 10 hex (16 decimal) to 27 decimal + cat > expected << EOF + nextRange: 27 + serialno: 011 + EOF + + diff expected actual + + - name: Check request range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=requests,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + rm -f actual + + for DN in $(sed -n 's/^dn: *\(.*\)$/\1/p' output) + do + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b $DN \ + -s base \ + -o ldif_wrap=no \ + -LLL \ + | grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + | sort >> actual + + echo >> actual + done + + # new request range should be 21 - 30 decimal (total: 10) + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: pki.example.com + + SecurePort: 8443 + beginRange: 21 + endRange: 30 + host: pki.example.com + + EOF + + diff expected actual + + - name: Check cert range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + output \ + | sort > actual + + # new request range should be 11 - 26 decimal (total: 16) + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 26 + host: pki.example.com + EOF + + diff expected actual + + #################################################################################################### + # Enroll a cert after updating serial numbers + # + # This should create one request and one cert. For certs, + # it should switch to a new range. For requests, there + # should be no changes. + + - name: Enroll a cert after updating serial numbers + run: | + docker exec pki pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec pki openssl x509 -in testuser.crt -text -noout + + - name: Check requests + run: | + docker exec pki pki-server ca-cert-request-find | tee output + + grep "Request ID:" output | wc -l > actual + + # there should be 18 requests + echo "18" > expected + diff expected actual + + - name: Check certs + run: | + docker exec pki pki-server ca-cert-find | tee output + + grep "Serial Number:" output | wc -l > actual + + # there should be 17 certs + echo "17" > expected + diff expected actual + + - name: Check request range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginRequestNumber \ + -e dbs.endRequestNumber \ + -e dbs.requestCloneTransferNumber \ + -e dbs.requestIncrement \ + -e dbs.requestLowWaterMark \ + | tee actual + + # request range should be 11 - 20 decimal (total: 10, remaining: 2) + cat > expected << EOF + dbs.beginRequestNumber=11 + dbs.endRequestNumber=20 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected actual + + - name: Check cert range config + run: | + docker exec pki pki-server ca-config-find \ + | grep \ + -e dbs.beginSerialNumber \ + -e dbs.endSerialNumber \ + -e dbs.serialCloneTransferNumber \ + -e dbs.serialIncrement \ + -e dbs.serialLowWaterMark \ + | tee actual + + # cert range should be 11 - 20 hex (total: 16, remaining: 15) + cat > expected << EOF + dbs.beginSerialNumber=11 + dbs.endSerialNumber=20 + dbs.serialCloneTransferNumber=8 + dbs.serialIncrement=10 + dbs.serialLowWaterMark=8 + EOF + + diff expected actual + + - name: Check request repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=ca,ou=requests,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # request nextRange should be the same + cat > expected << EOF + nextRange: 31 + serialno: 010 + EOF + + diff expected actual + + - name: Check cert repository + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ca,dc=ca,dc=pki,dc=example,dc=com \ + -s base \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e serialno: \ + -e nextRange: \ + output \ + | sort > actual + + # cert nextRange should be the same + cat > expected << EOF + nextRange: 27 + serialno: 011 + EOF + + diff expected actual + + - name: Check request range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=requests,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + rm -f actual + + for DN in $(sed -n 's/^dn: *\(.*\)$/\1/p' output) + do + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b $DN \ + -s base \ + -o ldif_wrap=no \ + -LLL \ + | grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + | sort >> actual + + echo >> actual + done + + # request range objects should be the same + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: pki.example.com + + SecurePort: 8443 + beginRange: 21 + endRange: 30 + host: pki.example.com + + EOF + + diff expected actual + + - name: Check cert range objects + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificateRepository,ou=ranges,dc=ca,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + grep \ + -e SecurePort: \ + -e beginRange: \ + -e endRange: \ + -e host: \ + output \ + | sort > actual + + # cert range objects should be the same + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 26 + host: pki.example.com + EOF + + diff expected actual + + #################################################################################################### + # Enroll a cert with RSNv3 + # + # This should create a request and a cert. The cert + # should be issued with a non-sequential serial number. + - name: Switch to RSNv3 run: | # switch cert request ID generator to RSNv3 @@ -100,29 +1194,47 @@ jobs: # restart CA subsystem docker exec pki pki-server ca-redeploy --wait - - name: Run PKI healthcheck - run: docker exec pki pki-healthcheck --failures-only - - - name: Initialize PKI client + - name: Enroll a cert with RSNv3 run: | - docker exec pki pki-server cert-export ca_signing --cert-file ca_signing.crt + docker exec pki pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt - docker exec pki pki nss-cert-import \ - --cert ca_signing.crt \ - --trust CT,C,C \ - ca_signing + docker exec pki openssl x509 -in testuser.crt -serial -noout | tee output - docker exec pki pki pkcs12-import \ - --pkcs12 /root/.dogtag/pki-tomcat/ca_admin_cert.p12 \ - --pkcs12-password Secret.123 + # serial number should not be 12 hex (18 decimal) + echo "serial=12" >> expected + + rc=0 + diff expected output || rc=$? - - name: Check cert requests in CA + [ $rc -ne 0 ] + + - name: Check requests run: | - docker exec pki pki -n caadmin ca-cert-request-find + docker exec pki pki-server ca-cert-request-find | tee output + + grep "Request ID:" output | wc -l > actual - - name: Check certs in CA + # there should be 19 requests + echo "19" > expected + diff expected actual + + - name: Check certs run: | - docker exec pki pki ca-cert-find + docker exec pki pki-server ca-cert-find | tee output + + grep "Serial Number:" output | wc -l > actual + + # there should be 18 certs + echo "18" > expected + diff expected actual + + #################################################################################################### + # Cleanup - name: Remove CA run: docker exec pki pkidestroy -s CA -v @@ -142,21 +1254,12 @@ jobs: run: | docker exec pki journalctl -x --no-pager -u pki-tomcatd@pki-tomcat.service - - name: Check CA debug log + - name: Check PKI server access log if: always() run: | - docker exec pki find /var/lib/pki/pki-tomcat/logs/ca -name "debug.*" -exec cat {} \; + docker exec pki find /var/log/pki/pki-tomcat -name "localhost_access_log.*" -exec cat {} \; - - name: Gather artifacts + - name: Check CA debug log if: always() run: | - tests/bin/ds-artifacts-save.sh ds - tests/bin/pki-artifacts-save.sh pki - continue-on-error: true - - - name: Upload artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: ca-sequential - path: /tmp/artifacts + docker exec pki find /var/lib/pki/pki-tomcat/logs/ca -name "debug.*" -exec cat {} \; diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg index fa2e8928865..f73cb60fd69 100644 --- a/base/server/etc/default.cfg +++ b/base/server/etc/default.cfg @@ -351,8 +351,16 @@ pki_default_ocsp_uri= pki_serial_number_range_start= pki_serial_number_range_end= +pki_serial_number_range_increment= +pki_serial_number_range_minimum= +pki_serial_number_range_transfer= + pki_request_number_range_start= pki_request_number_range_end= +pki_request_number_range_increment= +pki_request_number_range_minimum= +pki_request_number_range_transfer= + pki_replica_number_range_start= pki_replica_number_range_end= diff --git a/base/server/python/pki/server/deployment/__init__.py b/base/server/python/pki/server/deployment/__init__.py index af2ae196020..2929ad4e4da 100644 --- a/base/server/python/pki/server/deployment/__init__.py +++ b/base/server/python/pki/server/deployment/__init__.py @@ -1180,11 +1180,11 @@ def configure_ca(self, subsystem): subsystem.set_config('dbs.request.id.length', self.mdict['pki_request_id_length']) else: # legacy - subsystem.set_config('dbs.beginRequestNumber', '1') - subsystem.set_config('dbs.endRequestNumber', '10000000') - subsystem.set_config('dbs.requestIncrement', '10000000') - subsystem.set_config('dbs.requestLowWaterMark', '2000000') - subsystem.set_config('dbs.requestCloneTransferNumber', '10000') + subsystem.set_config('dbs.beginRequestNumber', '1') # decimal + subsystem.set_config('dbs.endRequestNumber', '10000000') # decimal + subsystem.set_config('dbs.requestIncrement', '10000000') # decimal + subsystem.set_config('dbs.requestLowWaterMark', '2000000') # decimal + subsystem.set_config('dbs.requestCloneTransferNumber', '10000') # decimal subsystem.set_config('dbs.requestRangeDN', 'ou=requests,ou=ranges') request_number_range_start = self.mdict.get('pki_request_number_range_start') @@ -1195,6 +1195,18 @@ def configure_ca(self, subsystem): if request_number_range_end: subsystem.set_config('dbs.endRequestNumber', request_number_range_end) + request_increment = self.mdict.get('pki_request_number_range_increment') + if request_increment: + subsystem.set_config('dbs.requestIncrement', request_increment) + + request_minimum = self.mdict.get('pki_request_number_range_minimum') + if request_minimum: + subsystem.set_config('dbs.requestLowWaterMark', request_minimum) + + request_transfer = self.mdict.get('pki_request_number_range_transfer') + if request_transfer: + subsystem.set_config('dbs.requestCloneTransferNumber', request_transfer) + cert_id_generator = self.mdict['pki_cert_id_generator'] if cert_id_generator == 'random': @@ -1202,12 +1214,13 @@ def configure_ca(self, subsystem): subsystem.set_config('dbs.cert.id.length', self.mdict['pki_cert_id_length']) else: # legacy - subsystem.set_config('dbs.beginSerialNumber', '1') - subsystem.set_config('dbs.endSerialNumber', '10000000') - subsystem.set_config('dbs.serialIncrement', '10000000') - subsystem.set_config('dbs.serialLowWaterMark', '2000000') - subsystem.set_config('dbs.serialCloneTransferNumber', '10000') + subsystem.set_config('dbs.beginSerialNumber', '1') # hex + subsystem.set_config('dbs.endSerialNumber', '10000000') # hex + subsystem.set_config('dbs.serialIncrement', '10000000') # hex + subsystem.set_config('dbs.serialLowWaterMark', '2000000') # hex + subsystem.set_config('dbs.serialCloneTransferNumber', '10000') # hex subsystem.set_config('dbs.serialRangeDN', 'ou=certificateRepository,ou=ranges') + if config.str2bool(self.mdict['pki_random_serial_numbers_enable']): subsystem.set_config('dbs.enableRandomSerialNumbers', 'true') subsystem.set_config('dbs.randomSerialNumberCounter', '0') @@ -1220,6 +1233,18 @@ def configure_ca(self, subsystem): if serial_number_range_end: subsystem.set_config('dbs.endSerialNumber', serial_number_range_end) + serial_increment = self.mdict.get('pki_serial_number_range_increment') + if serial_increment: + subsystem.set_config('dbs.serialIncrement', serial_increment) + + serial_minimum = self.mdict.get('pki_serial_number_range_minimum') + if serial_minimum: + subsystem.set_config('dbs.serialLowWaterMark', serial_minimum) + + serial_transfer = self.mdict.get('pki_serial_number_range_transfer') + if serial_transfer: + subsystem.set_config('dbs.serialCloneTransferNumber', serial_transfer) + replica_number_range_start = self.mdict.get('pki_replica_number_range_start') if replica_number_range_start: subsystem.set_config('dbs.beginReplicaNumber', replica_number_range_start) @@ -1244,11 +1269,11 @@ def configure_kra(self, subsystem): subsystem.set_config('dbs.request.id.length', self.mdict['pki_request_id_length']) else: # legacy - subsystem.set_config('dbs.beginRequestNumber', '1') - subsystem.set_config('dbs.endRequestNumber', '10000000') - subsystem.set_config('dbs.requestIncrement', '10000000') - subsystem.set_config('dbs.requestLowWaterMark', '2000000') - subsystem.set_config('dbs.requestCloneTransferNumber', '10000') + subsystem.set_config('dbs.beginRequestNumber', '1') # decimal + subsystem.set_config('dbs.endRequestNumber', '10000000') # decimal + subsystem.set_config('dbs.requestIncrement', '10000000') # decimal + subsystem.set_config('dbs.requestLowWaterMark', '2000000') # decimal + subsystem.set_config('dbs.requestCloneTransferNumber', '10000') # decimal subsystem.set_config('dbs.requestRangeDN', 'ou=requests,ou=ranges') key_id_generator = self.mdict['pki_key_id_generator'] @@ -1258,11 +1283,11 @@ def configure_kra(self, subsystem): subsystem.set_config('dbs.key.id.length', self.mdict['pki_key_id_length']) else: # legacy - subsystem.set_config('dbs.beginSerialNumber', '1') - subsystem.set_config('dbs.endSerialNumber', '10000000') - subsystem.set_config('dbs.serialIncrement', '10000000') - subsystem.set_config('dbs.serialLowWaterMark', '2000000') - subsystem.set_config('dbs.serialCloneTransferNumber', '10000') + subsystem.set_config('dbs.beginSerialNumber', '1') # hex + subsystem.set_config('dbs.endSerialNumber', '10000000') # hex + subsystem.set_config('dbs.serialIncrement', '10000000') # hex + subsystem.set_config('dbs.serialLowWaterMark', '2000000') # hex + subsystem.set_config('dbs.serialCloneTransferNumber', '10000') # hex subsystem.set_config('dbs.serialRangeDN', 'ou=keyRepository,ou=ranges') if config.str2bool(self.mdict['pki_kra_ephemeral_requests']): diff --git a/base/server/src/main/java/com/netscape/cmscore/dbs/Repository.java b/base/server/src/main/java/com/netscape/cmscore/dbs/Repository.java index 7e837d815a2..90b905b6dce 100644 --- a/base/server/src/main/java/com/netscape/cmscore/dbs/Repository.java +++ b/base/server/src/main/java/com/netscape/cmscore/dbs/Repository.java @@ -539,9 +539,16 @@ public String getNextRange() throws EBaseException { } String nextRange = attr.getStringValues().nextElement(); + + // parse nextRange as decimal BigInteger nextRangeNo = new BigInteger(nextRange); + BigInteger newNextRangeNo = nextRangeNo.add(mIncrementNo); + + // generate new nextRange in decimal String newNextRange = newNextRangeNo.toString(); + + // generate endRange in decimal String endRange = newNextRangeNo.subtract(BigInteger.ONE).toString(); logger.info("Repository: Updating " + DBSubsystem.PROP_NEXT_RANGE + " from " + nextRange + " to " + newNextRange); @@ -563,8 +570,13 @@ public String getNextRange() throws EBaseException { LDAPAttributeSet attrs = new LDAPAttributeSet(); attrs.add(new LDAPAttribute("objectClass", "top")); attrs.add(new LDAPAttribute("objectClass", "pkiRange")); + + // store beginRange as decimal attrs.add(new LDAPAttribute("beginRange", nextRange)); + + // store endRange as decimal attrs.add(new LDAPAttribute("endRange", endRange)); + attrs.add(new LDAPAttribute("cn", nextRange)); attrs.add(new LDAPAttribute("host", cs.getHostname())); attrs.add(new LDAPAttribute("securePort", engine.getEESSLPort())); diff --git a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemRangeUpdateCLI.java b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemRangeUpdateCLI.java index 8268986378c..90ce9ca8ab9 100644 --- a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemRangeUpdateCLI.java +++ b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemRangeUpdateCLI.java @@ -109,11 +109,18 @@ public void updateSerialNumberRange( LdapBoundConnection conn = new LdapBoundConnection(socketFactory, connInfo, authInfo); try { + // parse the end of current cert range as decimal + // NOTE: this is a bug, cert range is stored as hex in CS.cfg BigInteger endSerialNumber = new BigInteger(dbConfig.getEndSerialNumber()); - BigInteger nextSerialNumber = endSerialNumber.add(BigInteger.ONE); + + // generate nextRange in decimal + String nextSerialNumber = endSerialNumber.add(BigInteger.ONE).toString(); String serialDN = dbConfig.getSerialDN() + "," + baseDN; - LDAPAttribute attrSerialNextRange = new LDAPAttribute("nextRange", nextSerialNumber.toString()); + + // store nextRange as decimal + LDAPAttribute attrSerialNextRange = new LDAPAttribute("nextRange", nextSerialNumber); + LDAPModification serialmod = new LDAPModification(LDAPModification.REPLACE, attrSerialNextRange); conn.modify(serialDN, serialmod); @@ -145,11 +152,17 @@ public void updateRequestNumberRange( try { logger.info("Updating request ID range"); + // parse the end of current range as decimal BigInteger endRequestNumber = new BigInteger(dbConfig.getEndRequestNumber()); - BigInteger nextRequestNumber = endRequestNumber.add(BigInteger.ONE); + + // generate nextRange in decimal + String nextRequestNumber = endRequestNumber.add(BigInteger.ONE).toString(); String requestDN = dbConfig.getRequestDN() + "," + baseDN; - LDAPAttribute attrRequestNextRange = new LDAPAttribute("nextRange", nextRequestNumber.toString()); + + // store nextRange as decimal + LDAPAttribute attrRequestNextRange = new LDAPAttribute("nextRange", nextRequestNumber); + LDAPModification requestmod = new LDAPModification(LDAPModification.REPLACE, attrRequestNextRange); conn.modify(requestDN, requestmod);