diff --git a/.github/workflows/ca-clone-sequential-test.yml b/.github/workflows/ca-clone-sequential-test.yml index 447f243cd1c..47bb5e053eb 100644 --- a/.github/workflows/ca-clone-sequential-test.yml +++ b/.github/workflows/ca-clone-sequential-test.yml @@ -984,6 +984,537 @@ jobs: diff expected output + #################################################################################################### + # Switch cert request ID generator to legacy2 and verify if serials + # have gaps when range is updated + # + # It should work like the legacy but with correct range. + - name: Stop the CAs + run: | + docker exec primary pki-server stop + docker exec secondary pki-server stop + + - name: Switch primary to legacy2 + run: | + docker exec primary pki-server ca-id-generator-update --type request legacy2 + docker exec primary pki-server ca-id-generator-update --type cert legacy2 + + - name: Check request range objects + run: | + tests/ca/bin/ca-request-range-objects.sh primaryds | tee output + + # request ranges should remain the same + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: primary.example.com + + SecurePort: 8443 + beginRange: 21 + endRange: 30 + host: secondary.example.com + + EOF + + diff expected output + + - name: Check request next range + run: | + tests/ca/bin/ca-request-next-range.sh primaryds | tee output + + # request nextRange should remain the same + cat > expected << EOF + nextRange: 31 + EOF + + diff expected output + + - name: Check cert range objects + run: | + tests/ca/bin/ca-cert-range-objects.sh primaryds | tee output + + # cert ranges should remain the same but converted from hex to decimal + # the range value for the primary move from 13-30 (hex) to 19-48 (dec) + cat > expected << EOF + SecurePort: 8443 + beginRange: 31 + endRange: 48 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 19 + endRange: 48 + host: primary.example.com + + EOF + + diff expected output + + - name: Check cert next range + run: | + tests/ca/bin/ca-cert-next-range.sh primaryds | tee output + + # cert nextRange should remain the same + cat > expected << EOF + nextRange: 49 + EOF + + diff expected output + + - name: Switch secondary to legacy2 + run: | + docker exec secondary pki-server ca-id-generator-update --type request legacy2 + docker exec secondary pki-server ca-id-generator-update --type cert legacy2 + + - name: Start the CAs + run: | + docker exec primary pki-server start --wait + docker exec secondary pki-server start --wait + + - name: Check request range config in primary CA + run: | + tests/ca/bin/ca-request-range-config.sh primary | tee output + + cat > expected << EOF + dbs.beginRequestNumber=11 + dbs.endRequestNumber=15 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected output + + - name: Check request range config in secondary CA + run: | + tests/ca/bin/ca-request-range-config.sh secondary | tee output + + cat > expected << EOF + dbs.beginRequestNumber=21 + dbs.endRequestNumber=30 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected output + + - name: Check the radix for the new generator in all CAs + run: | + docker exec primary pki-server ca-config-show dbs.request.id.radix | tee output + docker exec secondary pki-server ca-config-show dbs.request.id.radix | tee -a output + docker exec primary pki-server ca-config-show dbs.cert.id.radix | tee -a output + docker exec secondary pki-server ca-config-show dbs.cert.id.radix | tee -a output + + cat > expected < expected << EOF + dbs.beginSerialNumber=0x13 + dbs.endSerialNumber=0x30 + dbs.serialCloneTransferNumber=0x9 + dbs.serialIncrement=0x12 + dbs.serialLowWaterMark=0x9 + EOF + + diff expected output + + - name: Check cert range config in secondary CA + run: | + tests/ca/bin/ca-cert-range-config.sh secondary | tee output + + cat > expected << EOF + dbs.beginSerialNumber=0x31 + dbs.endSerialNumber=0x48 + dbs.serialCloneTransferNumber=0x9 + dbs.serialIncrement=0x12 + dbs.serialLowWaterMark=0x9 + EOF + + diff expected output + + - name: Check request range objects + run: | + tests/ca/bin/ca-request-range-objects.sh primaryds | tee output + + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: primary.example.com + + SecurePort: 8443 + beginRange: 21 + endRange: 30 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 31 + endRange: 40 + host: primary.example.com + + SecurePort: 8443 + beginRange: 41 + endRange: 50 + host: secondary.example.com + + EOF + + diff expected output + + - name: Check cert range objects + run: | + tests/ca/bin/ca-cert-range-objects.sh primaryds | tee output + + # cert ranges should remain the same but in dec. + # the range value for the primary move from 13-30 (hex) to 19-48 (dec) + # the range value for the secondary move from 31-48 (hex) to 49-72 (dec) + cat > expected << EOF + SecurePort: 8443 + beginRange: 19 + endRange: 48 + host: primary.example.com + + SecurePort: 8443 + beginRange: 49 + endRange: 72 + host: secondary.example.com + + EOF + + diff expected output + + - name: Check request repository + run: | + tests/ca/bin/ca-request-next-range.sh primaryds | tee output + + cat > expected << EOF + nextRange: 51 + EOF + + diff expected output + + - name: Check cert repository + run: | + tests/ca/bin/ca-cert-next-range.sh primaryds | tee output + + cat > expected << EOF + nextRange: 73 + EOF + + diff expected output + + #################################################################################################### + # Enroll additional certs updating the range + # + + - name: Enroll certs in primary and secondary + run: | + # Enroll until request range exhausted + for i in $(seq 1 10); do + docker exec primary pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec primary openssl x509 -in testuser.crt -serial -noout + done + + for i in $(seq 1 10); do + docker exec secondary pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec secondary openssl x509 -in testuser.crt -serial -noout + done + + - name: Allocate new ranges + run: | + docker exec primary pki \ + -n caadmin \ + ca-job-start \ + serialNumberUpdate + + docker exec secondary pki \ + -n caadmin \ + ca-job-start \ + serialNumberUpdate + + # wait for DS replication + sleep 5 + + + - name: Enroll certs in primary and secondary + run: | + # Enroll until request range exhausted + for i in $(seq 1 10); do + docker exec primary pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec primary openssl x509 -in testuser.crt -serial -noout + done + + for i in $(seq 1 10); do + docker exec secondary pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec secondary openssl x509 -in testuser.crt -serial -noout + done + + - name: Allocate new ranges + run: | + docker exec secondary pki \ + -n caadmin \ + ca-job-start \ + serialNumberUpdate + + docker exec primary pki \ + -n caadmin \ + ca-job-start \ + serialNumberUpdate + + - name: Enroll certs in secondary + run: | + # Enroll until request range exhausted + for i in $(seq 1 10); do + docker exec secondary pki \ + -n caadmin \ + ca-cert-issue \ + --profile caUserCert \ + --csr-file testuser.csr \ + --output-file testuser.crt + + docker exec secondary openssl x509 -in testuser.crt -serial -noout + done + + - name: Allocate new ranges + run: | + docker exec secondary pki \ + -n caadmin \ + ca-job-start \ + serialNumberUpdate + # wait for DS replication + sleep 5 + + - name: Check request range config in primary CA + run: | + tests/ca/bin/ca-request-range-config.sh primary | tee output + + cat > expected << EOF + dbs.beginRequestNumber=51 + dbs.endRequestNumber=60 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected output + + - name: Check request range config in secondary CA + run: | + tests/ca/bin/ca-request-range-config.sh secondary | tee output + + cat > expected << EOF + dbs.beginRequestNumber=71 + dbs.endRequestNumber=80 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected output + + - name: Check cert range config in primary CA + run: | + tests/ca/bin/ca-cert-range-config.sh primary | tee output + + cat > expected << EOF + dbs.beginSerialNumber=0x13 + dbs.endSerialNumber=0x30 + dbs.serialCloneTransferNumber=0x9 + dbs.serialIncrement=0x12 + dbs.serialLowWaterMark=0x9 + EOF + + diff expected output + + - name: Check cert range config in secondary CA + run: | + tests/ca/bin/ca-cert-range-config.sh secondary | tee output + + cat > expected << EOF + dbs.beginSerialNumber=0x49 + dbs.endSerialNumber=0x5a + dbs.serialCloneTransferNumber=0x9 + dbs.serialIncrement=0x12 + dbs.serialLowWaterMark=0x9 + EOF + + diff expected output + + - name: Check request range objects + run: | + tests/ca/bin/ca-request-range-objects.sh primaryds | tee output + + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: primary.example.com + + SecurePort: 8443 + beginRange: 21 + endRange: 30 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 31 + endRange: 40 + host: primary.example.com + + SecurePort: 8443 + beginRange: 41 + endRange: 50 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 51 + endRange: 60 + host: primary.example.com + + SecurePort: 8443 + beginRange: 61 + endRange: 70 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 71 + endRange: 80 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 81 + endRange: 90 + host: primary.example.com + + SecurePort: 8443 + beginRange: 91 + endRange: 100 + host: secondary.example.com + + EOF + + diff expected output + + - name: Check cert range objects + run: | + tests/ca/bin/ca-cert-range-objects.sh primaryds | tee output + + cat > expected << EOF + SecurePort: 8443 + beginRange: 19 + endRange: 48 + host: primary.example.com + + SecurePort: 8443 + beginRange: 49 + endRange: 72 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 73 + endRange: 90 + host: secondary.example.com + + SecurePort: 8443 + beginRange: 91 + endRange: 108 + host: primary.example.com + + SecurePort: 8443 + beginRange: 109 + endRange: 126 + host: secondary.example.com + + EOF + + diff expected output + + - name: Check request repository + run: | + tests/ca/bin/ca-request-next-range.sh primaryds | tee output + + cat > expected << EOF + nextRange: 101 + EOF + + diff expected output + + - name: Check cert repository + run: | + tests/ca/bin/ca-cert-next-range.sh primaryds | tee output + + cat > expected << EOF + nextRange: 127 + EOF + + diff expected output + + - name: Check requests + run: | + docker exec secondary pki-server ca-cert-request-find | tee output + sed -n "s/^ *Request ID: *\(.*\)$/\1/p" output > actual + + # there should be 25 requests + seq 1 9 > expected # primary CA + seq 16 20 >> expected # secondary CA + seq 10 15 >> expected # primary CA + seq 21 30 >> expected # secondary CA + seq 31 40 >> expected # primary CA + seq 41 50 >> expected # secondary CA + seq 51 60 >> expected # primary CA + seq 61 70 >> expected # secondary CA + seq 71 80 >> expected # secondary CA + + diff expected actual + + - name: Check certs + run: | + docker exec primary pki-server ca-cert-find | tee output + sed -n "s/^ *Serial Number: *\(.*\)$/\1/p" output > actual + + + # There is only a permanent gap generated with legagy id generator + + seq 1 43 | while read n; do printf "0x%x\n" $n; done > expected + seq 49 84 | while read n; do printf "0x%x\n" $n; done >> expected + + diff expected actual + #################################################################################################### # Cleanup diff --git a/.github/workflows/ca-sequential-test.yml b/.github/workflows/ca-sequential-test.yml index 3a826ca53f3..372102c1e65 100644 --- a/.github/workflows/ca-sequential-test.yml +++ b/.github/workflows/ca-sequential-test.yml @@ -1143,6 +1143,363 @@ jobs: diff expected output + #################################################################################################### + # Switch cert request ID generator to legacy2 and verify if serials + # have gaps when range is updated + # + # It should work like the legacy but with correct range. + - name: Switch to legacy2 + run: | + docker exec pki pki-server stop + docker exec pki pki-server ca-id-generator-update --type request legacy2 + docker exec pki pki-server ca-id-generator-update --type cert legacy2 + docker exec pki pki-server start --wait + + + - name: Check request range config + run: | + tests/ca/bin/ca-request-range-config.sh pki | tee output + # request range should be the same + cat > expected << EOF + dbs.beginRequestNumber=31 + dbs.endRequestNumber=40 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected output + + - name: Check cert range config + run: | + tests/ca/bin/ca-cert-range-config.sh pki | tee output + + cat > expected << EOF + dbs.beginSerialNumber=0x37 + dbs.endSerialNumber=0x54 + dbs.serialCloneTransferNumber=0x9 + dbs.serialIncrement=0x12 + dbs.serialLowWaterMark=0x9 + EOF + + diff expected output + + - name: Check the radix in for the new generator + run: | + docker exec pki pki-server ca-config-show dbs.request.id.radix | tee output + docker exec pki pki-server ca-config-show dbs.cert.id.radix | tee -a output + + cat > expected < expected << EOF + nextRange: 51 + EOF + + diff expected output + + - name: Check cert repository + run: | + tests/ca/bin/ca-cert-next-range.sh ds | tee output + + cat > expected << EOF + nextRange: 85 + EOF + + diff expected output + + - name: Check request range objects + run: | + tests/ca/bin/ca-request-range-objects.sh ds | tee output + + # new request range should be 31 - 40 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 + + SecurePort: 8443 + beginRange: 31 + endRange: 40 + host: pki.example.com + + SecurePort: 8443 + beginRange: 41 + endRange: 50 + host: pki.example.com + + EOF + + diff expected output + + - name: Check cert range objects + run: | + tests/ca/bin/ca-cert-range-objects.sh ds | tee output + + # new cert range should be the same but converted to decimal + # first range move from 19-36 (hex) to 25-54 (dec) + # second range move from 37-54 (hex) to 55-84 (dec) + cat > expected << EOF + SecurePort: 8443 + beginRange: 25 + endRange: 54 + host: pki.example.com + + SecurePort: 8443 + beginRange: 55 + endRange: 84 + host: pki.example.com + + EOF + + diff expected output + + #################################################################################################### + # Enroll additional certs updating the range + # + + - name: Enroll additional certs + run: | + # Enroll until request range exhausted + for i in $(seq 1 9); 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 + docker exec pki pki -n caadmin ca-job-start serialNumberUpdate + # Enroll until request range exhausted + 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 + docker exec pki pki -n caadmin ca-job-start serialNumberUpdate + # Enroll until request range exhausted + 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 + docker exec pki pki -n caadmin ca-job-start serialNumberUpdate + # Enroll until request range exhausted + 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 + docker exec pki pki -n caadmin ca-job-start serialNumberUpdate + # Enroll until request range exhausted + 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 + docker exec pki pki -n caadmin ca-job-start serialNumberUpdate + + - name: Check request range config + run: | + tests/ca/bin/ca-request-range-config.sh pki | tee output + + cat > expected << EOF + dbs.beginRequestNumber=81 + dbs.endRequestNumber=90 + dbs.requestCloneTransferNumber=5 + dbs.requestIncrement=10 + dbs.requestLowWaterMark=5 + EOF + + diff expected output + + - name: Check cert range config + run: | + tests/ca/bin/ca-cert-range-config.sh pki | tee output + + cat > expected << EOF + dbs.beginSerialNumber=0x67 + dbs.endSerialNumber=0x78 + dbs.serialCloneTransferNumber=0x9 + dbs.serialIncrement=0x12 + dbs.serialLowWaterMark=0x9 + EOF + + diff expected output + + - name: Check request repository + run: | + tests/ca/bin/ca-request-next-range.sh ds | tee output + + cat > expected << EOF + nextRange: 101 + EOF + + diff expected output + + - name: Check cert repository + run: | + tests/ca/bin/ca-cert-next-range.sh ds | tee output + + cat > expected << EOF + nextRange: 121 + EOF + + diff expected output + + - name: Check request range objects + run: | + tests/ca/bin/ca-request-range-objects.sh ds | tee output + + cat > expected << EOF + SecurePort: 8443 + beginRange: 11 + endRange: 20 + host: pki.example.com + + SecurePort: 8443 + beginRange: 21 + endRange: 30 + host: pki.example.com + + SecurePort: 8443 + beginRange: 31 + endRange: 40 + host: pki.example.com + + SecurePort: 8443 + beginRange: 41 + endRange: 50 + host: pki.example.com + + SecurePort: 8443 + beginRange: 51 + endRange: 60 + host: pki.example.com + + SecurePort: 8443 + beginRange: 61 + endRange: 70 + host: pki.example.com + + SecurePort: 8443 + beginRange: 71 + endRange: 80 + host: pki.example.com + + SecurePort: 8443 + beginRange: 81 + endRange: 90 + host: pki.example.com + + SecurePort: 8443 + beginRange: 91 + endRange: 100 + host: pki.example.com + + EOF + + diff expected output + + - name: Check cert range objects + run: | + tests/ca/bin/ca-cert-range-objects.sh ds | tee output + + cat > expected << EOF + SecurePort: 8443 + beginRange: 25 + endRange: 54 + host: pki.example.com + + SecurePort: 8443 + beginRange: 55 + endRange: 84 + host: pki.example.com + + SecurePort: 8443 + beginRange: 85 + endRange: 102 + host: pki.example.com + + SecurePort: 8443 + beginRange: 103 + endRange: 120 + host: pki.example.com + + EOF + + diff expected output + + #################################################################################################### + # Checking request no gap should be present after switching to legacy2 + # + - name: Check requests + run: | + docker exec pki pki-server ca-cert-request-find | tee output + + sed -n "s/^ *Request ID: *\(.*\)$/\1/p" output > actual + + # there should be 40 requests (30 existing + 10 new) + seq 1 89 > expected + + diff expected actual + + #################################################################################################### + # Checking certs no gap should be present after switching to legacy2 + # so the last gap is between 32 and 39 + # + - name: Check certs + run: | + docker exec pki pki-server ca-cert-find | tee output + + sed -n "s/^ *Serial Number: *\(.*\)$/\1/p" output > actual + + # there should be 39 certs (29 existing + 10 new) + # but due to a bug the serial numbers have a gap + + # seq 1 39 | while read n; do printf "0x%x\n" $n; done > expected + seq 9 42 | while read n; do printf "0x%x\n" $n; done > expected + seq 55 108 | while read n; do printf "0x%x\n" $n; done >> expected + + diff expected actual + #################################################################################################### # Enroll a cert with RSNv3 # diff --git a/base/ca/src/main/java/com/netscape/cmscore/dbs/CRLRepository.java b/base/ca/src/main/java/com/netscape/cmscore/dbs/CRLRepository.java index e740cee279f..b510adbdaa6 100644 --- a/base/ca/src/main/java/com/netscape/cmscore/dbs/CRLRepository.java +++ b/base/ca/src/main/java/com/netscape/cmscore/dbs/CRLRepository.java @@ -49,7 +49,7 @@ public class CRLRepository extends Repository { * Constructs a CRL repository. */ public CRLRepository(DBSubsystem dbSubsystem) { - super(dbSubsystem, 10); + super(dbSubsystem, DEC); } @Override @@ -67,18 +67,10 @@ public void init() throws Exception { rangeDN = dbConfig.getRequestRangeDN() + "," + dbSubsystem.getBaseDN(); logger.info("CRLRepository: - range DN: " + rangeDN); - minSerialName = DatabaseConfig.MIN_REQUEST_NUMBER; - String minSerial = dbConfig.getBeginRequestNumber(); - if (minSerial != null) { - mMinSerialNo = new BigInteger(minSerial, mRadix); - } + mMinSerialNo = dbConfig.getBigInteger(DatabaseConfig.MIN_REQUEST_NUMBER, null); logger.info("CRLRepository: - min serial: " + mMinSerialNo); - maxSerialName = DatabaseConfig.MAX_REQUEST_NUMBER; - String maxSerial = dbConfig.getEndRequestNumber(); - if (maxSerial != null) { - mMaxSerialNo = new BigInteger(maxSerial, mRadix); - } + mMaxSerialNo = dbConfig.getBigInteger(DatabaseConfig.MAX_REQUEST_NUMBER, null); logger.info("CRLRepository: - max serial: " + mMaxSerialNo); nextMinSerialName = DatabaseConfig.NEXT_MIN_REQUEST_NUMBER; @@ -86,7 +78,7 @@ public void init() throws Exception { if (nextMinSerial == null || nextMinSerial.equals("-1")) { mNextMinSerialNo = null; } else { - mNextMinSerialNo = new BigInteger(nextMinSerial, mRadix); + mNextMinSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MIN_REQUEST_NUMBER, null); } logger.info("CRLRepository: - next min serial: " + mNextMinSerialNo); @@ -95,19 +87,15 @@ public void init() throws Exception { if (nextMaxSerial == null || nextMaxSerial.equals("-1")) { mNextMaxSerialNo = null; } else { - mNextMaxSerialNo = new BigInteger(nextMaxSerial, mRadix); + mNextMaxSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MAX_REQUEST_NUMBER, null); } logger.info("CRLRepository: - next max serial: " + mNextMaxSerialNo); - String lowWaterMark = dbConfig.getRequestLowWaterMark(); - if (lowWaterMark != null) { - mLowWaterMarkNo = new BigInteger(lowWaterMark, mRadix); - } - - String incrementNo = dbConfig.getRequestIncrement(); - if (incrementNo != null) { - mIncrementNo = new BigInteger(incrementNo, mRadix); - } + mLowWaterMarkNo = dbConfig.getBigInteger(DatabaseConfig.REQUEST_LOW_WATER_MARK, null); + logger.debug("CRLRepository: - low water mark serial: " + mNextMaxSerialNo); + + mIncrementNo = dbConfig.getBigInteger(DatabaseConfig.REQUEST_INCREMENT, null); + logger.debug("CRLRepository: - increment serial: " + mIncrementNo); /* DBRegistry reg = dbService.getRegistry(); diff --git a/base/ca/src/main/java/com/netscape/cmscore/dbs/CertificateRepository.java b/base/ca/src/main/java/com/netscape/cmscore/dbs/CertificateRepository.java index 471e160d699..4ec6e31d7fd 100644 --- a/base/ca/src/main/java/com/netscape/cmscore/dbs/CertificateRepository.java +++ b/base/ca/src/main/java/com/netscape/cmscore/dbs/CertificateRepository.java @@ -80,6 +80,7 @@ public class CertificateRepository extends Repository { private static final BigInteger BI_MINUS_ONE = BigInteger.ONE.negate(); public static final String PROP_CERT_ID_GENERATOR = "cert.id.generator"; + public static final String PROP_CERT_ID_RADIX = "cert.id.radix"; public static final String DEFAULT_CERT_ID_GENERATOR = "legacy"; public static final String PROP_CERT_ID_LENGTH = "cert.id.length"; @@ -103,8 +104,15 @@ public CertificateRepository( SecureRandom secureRandom, DBSubsystem dbSubsystem) { - super(dbSubsystem, 16); - + super(dbSubsystem, HEX); + DatabaseConfig dbc = dbSubsystem.getDBConfigStore(); + try { + this.mRadix = dbc.getInteger(PROP_CERT_ID_RADIX, HEX); + logger.debug("CertificateRepository: number radix {}", this.mRadix); + + } catch (EBaseException ex) { + logger.debug("CertificateRepository: error reading number radix config, using default {} for ", HEX); + } this.secureRandom = secureRandom; } @@ -126,12 +134,51 @@ public void init() throws Exception { idLength = mDBConfig.getInteger(PROP_CERT_ID_LENGTH, DEFAULT_CERT_ID_LENGTH); logger.debug("CertificateRepository: - cert ID length: " + idLength); - + } else if (idGenerator == IDGenerator.LEGACY_2) { + initLegacy2Generator(); } else { initLegacyGenerator(); } } + protected void initLegacy2Generator() throws EBaseException { + + rangeDN = mDBConfig.getSerialRangeDN() + "," + dbSubsystem.getBaseDN(); + logger.debug("CertificateRepository: - range DN: " + rangeDN); + + minSerialName = DatabaseConfig.MIN_SERIAL_NUMBER; + mMinSerialNo = mDBConfig.getBigInteger(minSerialName, null); + logger.debug("CertificateRepository: - min serial: " + mMinSerialNo); + + maxSerialName = DatabaseConfig.MAX_SERIAL_NUMBER; + mMaxSerialNo = mDBConfig.getBigInteger(maxSerialName, null); + logger.debug("CertificateRepository: - max serial: " + mMaxSerialNo); + + nextMinSerialName = DatabaseConfig.NEXT_MIN_SERIAL_NUMBER; + String nextMinSerial = mDBConfig.getNextBeginSerialNumber(); + if (nextMinSerial == null || nextMinSerial.equals("-1")) { + mNextMinSerialNo = null; + } else { + mNextMinSerialNo = mDBConfig.getBigInteger(DatabaseConfig.NEXT_MIN_SERIAL_NUMBER, null); + } + logger.debug("CertificateRepository: - next min serial: " + mNextMinSerialNo); + + nextMaxSerialName = DatabaseConfig.NEXT_MAX_SERIAL_NUMBER; + String nextMaxSerial = mDBConfig.getNextEndSerialNumber(); + if (nextMaxSerial == null || nextMaxSerial.equals("-1")) { + mNextMaxSerialNo = null; + } else { + mNextMaxSerialNo = mDBConfig.getBigInteger(DatabaseConfig.NEXT_MAX_SERIAL_NUMBER, null); + } + logger.debug("CertificateRepository: - next max serial: " + mNextMaxSerialNo); + + mLowWaterMarkNo = mDBConfig.getBigInteger(DatabaseConfig.SERIAL_LOW_WATER_MARK, null); + logger.debug("CertificateRepository: - low water mark serial: " + mNextMaxSerialNo); + + mIncrementNo = mDBConfig.getBigInteger(DatabaseConfig.SERIAL_INCREMENT, null); + logger.debug("CertificateRepository: - increment serial: " + mIncrementNo); + } + public void initLegacyGenerator() throws Exception { rangeDN = mDBConfig.getSerialRangeDN() + "," + dbSubsystem.getBaseDN(); diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CACLI.java b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CACLI.java index 6c32799000b..0adb076183e 100644 --- a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CACLI.java +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CACLI.java @@ -36,6 +36,7 @@ public CACLI(CLI parent) { addModule(new SubsystemGroupCLI(this)); addModule(new CAProfileCLI(this)); addModule(new CARangeCLI(this)); + addModule(new CAIdCLI(this)); addModule(new SubsystemUserCLI(this)); addModule(new SDCLI(this)); } diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdCLI.java b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdCLI.java new file mode 100644 index 00000000000..899e7bb77d2 --- /dev/null +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdCLI.java @@ -0,0 +1,19 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.ca.cli; + +import org.dogtagpki.cli.CLI; + +/** + * @author Marco Fargetta {@literal } + */ +public class CAIdCLI extends CLI { + public CAIdCLI(CLI parent) { + super("id", "CA id generator management commands", parent); + + addModule(new CAIdGeneratorCLI(this)); + } +} diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdGeneratorCLI.java b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdGeneratorCLI.java new file mode 100644 index 00000000000..b74b8832414 --- /dev/null +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdGeneratorCLI.java @@ -0,0 +1,21 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.ca.cli; + +import org.dogtagpki.cli.CLI; + +/** + * @author Marco Fargetta {@literal } + */ +public class CAIdGeneratorCLI extends CLI { + + public CAIdGeneratorCLI(CLI parent) { + super("generator", "CA id generator commands", parent); + + addModule(new CAIdGeneratorUpdateCLI(this)); + } + +} diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdGeneratorUpdateCLI.java b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdGeneratorUpdateCLI.java new file mode 100644 index 00000000000..3bea7671761 --- /dev/null +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CAIdGeneratorUpdateCLI.java @@ -0,0 +1,53 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.ca.cli; + +import com.netscape.cmscore.apps.DatabaseConfig; +import com.netscape.cmscore.dbs.CertificateRepository; +import com.netscape.cmscore.dbs.Repository; +import com.netscape.cmscore.dbs.Repository.IDGenerator; +import com.netscape.cmscore.ldapconn.LdapAuthInfo; +import com.netscape.cmscore.ldapconn.LdapConnInfo; +import com.netscape.cmscore.ldapconn.PKISocketFactory; +import org.dogtagpki.cli.CLI; +import org.dogtagpki.server.cli.SubsystemIdGeneratorUpdateCLI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Marco Fargetta {@literal } + */ +public class CAIdGeneratorUpdateCLI extends SubsystemIdGeneratorUpdateCLI { + private static final Logger logger = LoggerFactory.getLogger(CAIdGeneratorUpdateCLI.class); + + public CAIdGeneratorUpdateCLI(CLI parent) { + super(parent); + } + + @Override + protected void updateSerialNumberRangeGenerator(PKISocketFactory socketFactory, LdapConnInfo connInfo, + LdapAuthInfo authInfo, DatabaseConfig dbConfig, String baseDN, IDGenerator newGenerator, String hostName, String securePort) throws Exception { + String value = dbConfig.getString( + CertificateRepository.PROP_CERT_ID_GENERATOR, + CertificateRepository.DEFAULT_CERT_ID_GENERATOR); + idGenerator = IDGenerator.fromString(value); + + if (newGenerator == IDGenerator.RANDOM && idGenerator != IDGenerator.RANDOM) { + dbConfig.put(CertificateRepository.PROP_CERT_ID_GENERATOR, newGenerator.toString()); + dbConfig.put(CertificateRepository.PROP_CERT_ID_LENGTH, "128"); + dbConfig.remove("enableRandomSerialNumbers"); + dbConfig.remove("randomSerialNumberCounter"); + } + if (newGenerator == IDGenerator.LEGACY_2 && idGenerator == IDGenerator.LEGACY) { + dbConfig.put(CertificateRepository.PROP_CERT_ID_GENERATOR, newGenerator.toString()); + dbConfig.put(CertificateRepository.PROP_CERT_ID_RADIX, Integer.toString(Repository.HEX)); + } + + super.updateSerialNumberRangeGenerator(socketFactory, connInfo, authInfo, dbConfig, baseDN, newGenerator, hostName, securePort); + } + + +} diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CARangeUpdateCLI.java b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CARangeUpdateCLI.java index 5628173fbc0..1f10bd92fe3 100644 --- a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CARangeUpdateCLI.java +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CARangeUpdateCLI.java @@ -39,9 +39,9 @@ public void updateSerialNumberRange( String value = dbConfig.getString( CertificateRepository.PROP_CERT_ID_GENERATOR, CertificateRepository.DEFAULT_CERT_ID_GENERATOR); - IDGenerator idGenerator = IDGenerator.fromString(value); + idGenerator = IDGenerator.fromString(value); - if (idGenerator != IDGenerator.LEGACY) { + if (idGenerator == IDGenerator.RANDOM) { logger.info("No need to update certificate ID range"); return; } diff --git a/base/kra/src/main/java/com/netscape/cmscore/dbs/KeyRepository.java b/base/kra/src/main/java/com/netscape/cmscore/dbs/KeyRepository.java index dbc87cc0fc4..48d869025b7 100644 --- a/base/kra/src/main/java/com/netscape/cmscore/dbs/KeyRepository.java +++ b/base/kra/src/main/java/com/netscape/cmscore/dbs/KeyRepository.java @@ -45,6 +45,7 @@ public class KeyRepository extends Repository { public static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(KeyRepository.class); public static final String PROP_KEY_ID_GENERATOR = "key.id.generator"; + public static final String PROP_KEY_ID_RADIX = "key.id.radix"; public static final String DEFAULT_KEY_ID_GENERATOR = "legacy"; public static final String PROP_KEY_ID_LENGTH = "key.id.length"; @@ -62,7 +63,15 @@ public KeyRepository( SecureRandom secureRandom, DBSubsystem dbSubsystem) { - super(dbSubsystem, 16); + super(dbSubsystem, HEX); + DatabaseConfig dbc = dbSubsystem.getDBConfigStore(); + try { + this.mRadix = dbc.getInteger(PROP_KEY_ID_RADIX, HEX); + logger.debug("KeyRepository: number radix {}", this.mRadix); + + } catch (EBaseException ex) { + logger.debug("KeyRepository: error reading number radix config, using default {} for ", HEX); + } this.secureRandom = secureRandom; } @@ -85,7 +94,8 @@ public void init() throws Exception { idLength = dbConfig.getInteger(PROP_KEY_ID_LENGTH, DEFAULT_KEY_ID_LENGTH); logger.info("KeyRepository: - key ID length: {}", idLength); - + } else if (idGenerator == IDGenerator.LEGACY_2) { + initLegacy2Generator(); } else { initLegacyGenerator(); } @@ -168,6 +178,45 @@ public void init() throws Exception { } + protected void initLegacy2Generator() throws EBaseException { + DatabaseConfig dbConfig = dbSubsystem.getDBConfigStore(); + + rangeDN = dbConfig.getSerialRangeDN() + "," + dbSubsystem.getBaseDN(); + logger.debug("KeyRepository: - range DN: " + rangeDN); + + minSerialName = DatabaseConfig.MIN_SERIAL_NUMBER; + mMinSerialNo = dbConfig.getBigInteger(minSerialName, null); + logger.debug("KeyRepository: - min serial: " + mMinSerialNo); + + maxSerialName = DatabaseConfig.MAX_SERIAL_NUMBER; + mMaxSerialNo = dbConfig.getBigInteger(maxSerialName, null); + logger.debug("KeyRepository: - max serial: " + mMaxSerialNo); + + nextMinSerialName = DatabaseConfig.NEXT_MIN_SERIAL_NUMBER; + String nextMinSerial = dbConfig.getNextBeginSerialNumber(); + if (nextMinSerial == null || nextMinSerial.equals("-1")) { + mNextMinSerialNo = null; + } else { + mNextMinSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MIN_SERIAL_NUMBER, null); + } + logger.debug("KeyRepository: - next min serial: " + mNextMinSerialNo); + + nextMaxSerialName = DatabaseConfig.NEXT_MAX_SERIAL_NUMBER; + String nextMaxSerial = dbConfig.getNextEndSerialNumber(); + if (nextMaxSerial == null || nextMaxSerial.equals("-1")) { + mNextMaxSerialNo = null; + } else { + mNextMaxSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MAX_SERIAL_NUMBER, null); + } + logger.debug("KeyRepository: - next max serial: " + mNextMaxSerialNo); + + mLowWaterMarkNo = dbConfig.getBigInteger(DatabaseConfig.SERIAL_LOW_WATER_MARK, null); + logger.debug("KeyRepository: - low water mark serial: " + mNextMaxSerialNo); + + mIncrementNo = dbConfig.getBigInteger(DatabaseConfig.SERIAL_INCREMENT, null); + logger.debug("KeyRepository: - increment serial: " + mIncrementNo); + } + public void initLegacyGenerator() throws Exception { DatabaseConfig dbConfig = dbSubsystem.getDBConfigStore(); diff --git a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRACLI.java b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRACLI.java index 4861c02d4ec..08c2427866b 100644 --- a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRACLI.java +++ b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRACLI.java @@ -35,6 +35,7 @@ public KRACLI(CLI parent) { addModule(new SubsystemDBCLI(this)); addModule(new SubsystemGroupCLI(this)); addModule(new KRARangeCLI(this)); + addModule(new KRAIdCLI(this)); addModule(new SubsystemUserCLI(this)); addModule(new SDCLI(this)); } diff --git a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRAIdCLI.java b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRAIdCLI.java new file mode 100644 index 00000000000..1e8cd8ef601 --- /dev/null +++ b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRAIdCLI.java @@ -0,0 +1,19 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.kra.cli; + +import org.dogtagpki.cli.CLI; + +/** + * @author Marco Fargetta {@literal } + */ +public class KRAIdCLI extends CLI { + public KRAIdCLI(CLI parent) { + super("id", "CA id generator management commands", parent); + + addModule(new KRAIdGeneratorCLI(this)); + } +} diff --git a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRAIdGeneratorCLI.java b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRAIdGeneratorCLI.java new file mode 100644 index 00000000000..8ebd8385bd2 --- /dev/null +++ b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRAIdGeneratorCLI.java @@ -0,0 +1,18 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.kra.cli; + +import org.dogtagpki.cli.CLI; +/** + * @author Marco Fargetta {@literal } + */ +public class KRAIdGeneratorCLI extends CLI { + public KRAIdGeneratorCLI(CLI parent) { + super("generator", "kra range generator commands", parent); + + addModule(new kraIdGeneratorUpdateCLI(this)); + } +} diff --git a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRARangeUpdateCLI.java b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRARangeUpdateCLI.java index de387086285..d5b7ea09dd7 100644 --- a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRARangeUpdateCLI.java +++ b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/KRARangeUpdateCLI.java @@ -41,7 +41,7 @@ public void updateSerialNumberRange( KeyRepository.DEFAULT_KEY_ID_GENERATOR); IDGenerator idGenerator = IDGenerator.fromString(value); - if (idGenerator != IDGenerator.LEGACY) { + if (idGenerator == IDGenerator.RANDOM) { logger.info("No need to update key ID range"); return; } diff --git a/base/kra/src/main/java/org/dogtagpki/server/kra/cli/kraIdGeneratorUpdateCLI.java b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/kraIdGeneratorUpdateCLI.java new file mode 100644 index 00000000000..bd5c5e72d78 --- /dev/null +++ b/base/kra/src/main/java/org/dogtagpki/server/kra/cli/kraIdGeneratorUpdateCLI.java @@ -0,0 +1,45 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.kra.cli; + +import com.netscape.cmscore.apps.DatabaseConfig; +import com.netscape.cmscore.dbs.KeyRepository; +import com.netscape.cmscore.dbs.Repository; +import com.netscape.cmscore.ldapconn.LdapAuthInfo; +import com.netscape.cmscore.ldapconn.LdapConnInfo; +import com.netscape.cmscore.ldapconn.PKISocketFactory; +import org.dogtagpki.cli.CLI; +import org.dogtagpki.server.cli.SubsystemIdGeneratorUpdateCLI; + +/** + * @author Marco Fargetta {@literal } + */ +public class kraIdGeneratorUpdateCLI extends SubsystemIdGeneratorUpdateCLI { + + public kraIdGeneratorUpdateCLI(CLI parent) { + super(parent); + } + + @Override + protected void updateSerialNumberRangeGenerator(PKISocketFactory socketFactory, LdapConnInfo connInfo, + LdapAuthInfo authInfo, DatabaseConfig dbConfig, String baseDN, Repository.IDGenerator newGenerator, String hostName, String securePort) throws Exception { + String value = dbConfig.getString( + KeyRepository.PROP_KEY_ID_GENERATOR, + KeyRepository.DEFAULT_KEY_ID_GENERATOR); + idGenerator = Repository.IDGenerator.fromString(value); + + if (newGenerator == Repository.IDGenerator.RANDOM && idGenerator != Repository.IDGenerator.RANDOM) { + dbConfig.put(KeyRepository.PROP_KEY_ID_GENERATOR, newGenerator.toString()); + dbConfig.put(KeyRepository.PROP_KEY_ID_LENGTH, "128"); + } + if (newGenerator == Repository.IDGenerator.LEGACY_2 && idGenerator == Repository.IDGenerator.LEGACY) { + dbConfig.put(KeyRepository.PROP_KEY_ID_GENERATOR, newGenerator.toString()); + dbConfig.put(KeyRepository.PROP_KEY_ID_RADIX, Integer.toString(Repository.HEX)); + } + + super.updateSerialNumberRangeGenerator(socketFactory, connInfo, authInfo, dbConfig, baseDN, newGenerator, hostName, securePort); + } +} diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg index f73cb60fd69..745d1278792 100644 --- a/base/server/etc/default.cfg +++ b/base/server/etc/default.cfg @@ -364,13 +364,13 @@ pki_request_number_range_transfer= pki_replica_number_range_start= pki_replica_number_range_end= -# Cert cert ID generator: legacy, random +# Cert cert ID generator: legacy, legacy2, random pki_cert_id_generator=random # Cert cert ID length in bits pki_cert_id_length=128 -# Cert request ID generator: legacy, random +# Cert request ID generator: legacy, legacy2, random pki_request_id_generator=random # Cert request ID length in bits @@ -475,7 +475,7 @@ pki_key_id_generator=random # Key ID length in bits pki_key_id_length=128 -# Key request ID generator: legacy, random +# Key request ID generator: legacy, legacy2, random pki_request_id_generator=random # Key request ID length in bits diff --git a/base/server/python/pki/server/cli/ca.py b/base/server/python/pki/server/cli/ca.py index a96d3213abe..a8b4a9d892f 100644 --- a/base/server/python/pki/server/cli/ca.py +++ b/base/server/python/pki/server/cli/ca.py @@ -36,6 +36,7 @@ import pki.server.cli.config import pki.server.cli.db import pki.server.cli.group +import pki.server.cli.id import pki.server.cli.range import pki.server.cli.subsystem import pki.server.cli.user @@ -61,6 +62,7 @@ def __init__(self): self.add_module(pki.server.cli.group.GroupCLI(self)) self.add_module(CAProfileCLI()) self.add_module(pki.server.cli.range.RangeCLI(self)) + self.add_module(pki.server.cli.id.IdCLI(self)) self.add_module(pki.server.cli.user.UserCLI(self)) diff --git a/base/server/python/pki/server/cli/id.py b/base/server/python/pki/server/cli/id.py new file mode 100644 index 00000000000..05f7d0d555a --- /dev/null +++ b/base/server/python/pki/server/cli/id.py @@ -0,0 +1,187 @@ +# +# Copyright Red Hat, Inc. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +from __future__ import absolute_import +from __future__ import print_function +import getopt +import logging +import sys + +import pki.cli + +logger = logging.getLogger(__name__) + + +class IdCLI(pki.cli.CLI): + + def __init__(self, parent): + super().__init__( + 'id', + '%s id configuration management commands' % parent.name.upper()) + + self.parent = parent + self.add_module(IdGeneratorCLI(self)) + + +class IdGeneratorCLI(pki.cli.CLI): + + def __init__(self, parent): + super().__init__('generator', + '%s id generator configuration' % parent.parent.name.upper()) + + self.parent = parent + self.add_module(IdGeneratorShowCLI(self)) + self.add_module(IdGeneratorUpdateCLI(self)) + + +class IdGeneratorShowCLI(pki.cli.CLI): + + def __init__(self, parent): + super().__init__('show', 'Display %s id generator' % parent.parent.parent.name.upper()) + + self.parent = parent + + def print_help(self): + print('Usage: pki-server %s-id-generator-show [OPTIONS]' % + self.parent.parent.parent.name) + print() + print(' -i, --instance Instance ID (default: pki-tomcat).') + print(' -v, --verbose Run in verbose mode.') + print(' --debug Run in debug mode.') + print(' --help Show help message.') + print() + + def execute(self, argv): + try: + opts, _ = getopt.gnu_getopt(argv, 'i:v', [ + 'instance=', + 'verbose', 'debug', 'help']) + + except getopt.GetoptError as e: + logger.error(e) + self.print_help() + sys.exit(1) + + instance_name = 'pki-tomcat' + subsystem_name = self.parent.parent.parent.name + + for o, a in opts: + if o in ('-i', '--instance'): + instance_name = a + + elif o in ('-v', '--verbose'): + logging.getLogger().setLevel(logging.INFO) + + elif o == '--debug': + logging.getLogger().setLevel(logging.DEBUG) + + elif o == '--help': + self.print_help() + sys.exit() + + else: + logger.error('Invalid option: %s', o) + self.print_help() + sys.exit(1) + + instance = pki.server.PKIServerFactory.create(instance_name) + if not instance.exists(): + logger.error('Invalid instance: %s', instance_name) + sys.exit(1) + + instance.load() + + subsystem = instance.get_subsystem(subsystem_name) + + if not subsystem: + logger.error('No %s subsystem in instance %s', + subsystem_name.upper(), instance_name) + sys.exit(1) + + print(' Request ID generator: %s' % subsystem.config.get('dbs.request.id.generator')) + print(' Cert ID generator: %s' % subsystem.config.get('dbs.cert.id.generator')) + + +class IdGeneratorUpdateCLI(pki.cli.CLI): + + def __init__(self, parent): + super().__init__('update', 'Update %s id generator' % parent.parent.parent.name.upper()) + + self.parent = parent + + def print_help(self): + print('Usage: pki-server %s-id-generator-update [OPTIONS] ' % + self.parent.parent.parent.name) + print() + print(' -t, --type Type for the generator (request or cert).') + print(' -i, --instance Instance ID (default: pki-tomcat).') + print(' -v, --verbose Run in verbose mode.') + print(' --debug Run in debug mode.') + print(' --help Show help message.') + print() + + def execute(self, argv): + try: + opts, args = getopt.gnu_getopt(argv, 'i:t:v', [ + 'instance=', 'type=', + 'verbose', 'debug', 'help']) + + except getopt.GetoptError as e: + logger.error(e) + self.print_help() + sys.exit(1) + + if len(args) != 1: + logger.error('Missing new generator') + self.print_help() + sys.exit(1) + + new_generator = args[0] + instance_name = 'pki-tomcat' + subsystem_name = self.parent.parent.parent.name + generator_type = None + + for o, a in opts: + if o in ('-t', '--type'): + generator_type = a + + elif o in ('-i', '--instance'): + instance_name = a + + elif o in ('-v', '--verbose'): + logging.getLogger().setLevel(logging.INFO) + + elif o == '--debug': + logging.getLogger().setLevel(logging.DEBUG) + + elif o == '--help': + self.print_help() + sys.exit() + + else: + logger.error('Invalid option: %s', o) + self.print_help() + sys.exit(1) + + if not generator_type: + logger.error('No specified') + self.print_help() + sys.exit(1) + + instance = pki.server.PKIServerFactory.create(instance_name) + if not instance.exists(): + logger.error('Invalid instance: %s', instance_name) + sys.exit(1) + + instance.load() + + subsystem = instance.get_subsystem(subsystem_name) + + if not subsystem: + logger.error('No %s subsystem in instance %s', + subsystem_name.upper(), instance_name) + sys.exit(1) + + subsystem.update_id_generator(new_generator, generator_type) diff --git a/base/server/python/pki/server/deployment/__init__.py b/base/server/python/pki/server/deployment/__init__.py index 2929ad4e4da..7ec81f72c20 100644 --- a/base/server/python/pki/server/deployment/__init__.py +++ b/base/server/python/pki/server/deployment/__init__.py @@ -1175,8 +1175,9 @@ def configure_ca(self, subsystem): request_id_generator = self.mdict['pki_request_id_generator'] + subsystem.set_config('dbs.request.id.generator', request_id_generator) + if request_id_generator == 'random': - subsystem.set_config('dbs.request.id.generator', request_id_generator) subsystem.set_config('dbs.request.id.length', self.mdict['pki_request_id_length']) else: # legacy @@ -1209,8 +1210,9 @@ def configure_ca(self, subsystem): cert_id_generator = self.mdict['pki_cert_id_generator'] + subsystem.set_config('dbs.cert.id.generator', cert_id_generator) + if cert_id_generator == 'random': - subsystem.set_config('dbs.cert.id.generator', cert_id_generator) subsystem.set_config('dbs.cert.id.length', self.mdict['pki_cert_id_length']) else: # legacy @@ -1264,8 +1266,9 @@ def configure_kra(self, subsystem): request_id_generator = self.mdict['pki_request_id_generator'] + subsystem.set_config('dbs.request.id.generator', request_id_generator) + if request_id_generator == 'random': - subsystem.set_config('dbs.request.id.generator', request_id_generator) subsystem.set_config('dbs.request.id.length', self.mdict['pki_request_id_length']) else: # legacy @@ -1278,8 +1281,9 @@ def configure_kra(self, subsystem): key_id_generator = self.mdict['pki_key_id_generator'] + subsystem.set_config('dbs.key.id.generator', key_id_generator) + if key_id_generator == 'random': - subsystem.set_config('dbs.key.id.generator', key_id_generator) subsystem.set_config('dbs.key.id.length', self.mdict['pki_key_id_length']) else: # legacy @@ -1862,7 +1866,7 @@ def is_using_legacy_id_generator(self, subsystem): request_id_generator = subsystem.config.get('dbs.request.id.generator', 'legacy') logger.info('Request ID generator: %s', request_id_generator) - if request_id_generator == 'legacy': + if request_id_generator != 'random': return True if subsystem.type == 'CA': @@ -1870,7 +1874,7 @@ def is_using_legacy_id_generator(self, subsystem): cert_id_generator = subsystem.config.get('dbs.cert.id.generator', 'legacy') logger.info('Certificate ID generator: %s', cert_id_generator) - if cert_id_generator == 'legacy': + if cert_id_generator != 'random': return True elif subsystem.type == 'KRA': @@ -1878,7 +1882,7 @@ def is_using_legacy_id_generator(self, subsystem): key_id_generator = subsystem.config.get('dbs.key.id.generator', 'legacy') logger.info('Key ID generator: %s', key_id_generator) - if key_id_generator == 'legacy': + if key_id_generator != 'random': return True return False @@ -2876,7 +2880,7 @@ def import_cert_request(self, subsystem, tag, request): request_id_generator = subsystem.config.get('dbs.request.id.generator', 'legacy') - if request_id_generator == 'legacy': + if request_id_generator != 'random': # call the server to generate legacy request ID logger.info('Creating request ID for %s cert', tag) request.systemCert.requestID = self.client.createRequestID(request) @@ -2895,7 +2899,7 @@ def import_cert_request(self, subsystem, tag, request): dns_names=request.systemCert.dnsNames, adjust_validity=request.systemCert.adjustValidity) - if request_id_generator != 'legacy': + if request_id_generator == 'random': # get the request ID generated by pki-server ca-cert-request-import request.systemCert.requestID = result['requestID'] logger.info('- request ID: %s', request.systemCert.requestID) @@ -3347,7 +3351,7 @@ def create_cert_id(self, subsystem, tag, request): cert_id_generator = subsystem.config.get('dbs.cert.id.generator', 'legacy') - if cert_id_generator == 'legacy': + if cert_id_generator != 'random': # call the server to generate legacy cert ID logger.info('Creating cert ID for %s cert', tag) cert_id = self.client.createCertID(request) diff --git a/base/server/python/pki/server/subsystem.py b/base/server/python/pki/server/subsystem.py index 9ca4516110f..8c5382d97f9 100644 --- a/base/server/python/pki/server/subsystem.py +++ b/base/server/python/pki/server/subsystem.py @@ -1515,7 +1515,7 @@ def request_ranges(self, master_url, session_id=None, install_token=None): # request cert/key request ID range if it uses legacy generator if self.type in ['CA', 'KRA'] and \ - self.config.get('dbs.request.id.generator', 'legacy') == 'legacy': + self.config.get('dbs.request.id.generator', 'legacy') != 'random': logger.info('Requesting request ID range') @@ -1527,9 +1527,9 @@ def request_ranges(self, master_url, session_id=None, install_token=None): # request cert/key ID range if it uses legacy generator if self.type == 'CA' and \ - self.config.get('dbs.cert.id.generator', 'legacy') == 'legacy' or \ + self.config.get('dbs.cert.id.generator', 'legacy') != 'random' or \ self.type == 'KRA' \ - and self.config.get('dbs.key.id.generator', 'legacy') == 'legacy': + and self.config.get('dbs.key.id.generator', 'legacy') != 'random': logger.info('Requesting serial number range') @@ -1563,6 +1563,22 @@ def update_ranges(self, as_current_user=False): self.run(cmd, as_current_user=as_current_user) + def update_id_generator(self, generator, generator_type, as_current_user=False): + + cmd = [self.name + '-id-generator-update'] + + if logger.isEnabledFor(logging.DEBUG): + cmd.append('--debug') + + elif logger.isEnabledFor(logging.INFO): + cmd.append('--verbose') + + cmd.append('--type') + cmd.append(generator_type) + cmd.append(generator) + + self.run(cmd, as_current_user=as_current_user) + def retrieve_config(self, master_url, names, substores, session_id=None, install_token=None): tmpdir = tempfile.mkdtemp() diff --git a/base/server/src/main/java/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java b/base/server/src/main/java/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java index 53bd6765516..881c5940f1f 100644 --- a/base/server/src/main/java/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java +++ b/base/server/src/main/java/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java @@ -124,25 +124,22 @@ protected void process(CMSRequest cmsReq) throws EBaseException { repo.checkRanges(); } - int radix = 10; + int radix = repo.getRadix(); String endNumConfig = null; String cloneNumConfig = null; String nextEndConfig = null; if (type.equals("request")) { - radix = 10; endNumConfig = "endRequestNumber"; cloneNumConfig = "requestCloneTransferNumber"; nextEndConfig = "nextEndRequestNumber"; } else if (type.equals("serialNo")) { - radix = 16; endNumConfig = "endSerialNumber"; cloneNumConfig = "serialCloneTransferNumber"; nextEndConfig = "nextEndSerialNumber"; } else if (type.equals("replicaId")) { - radix = 10; endNumConfig = "endReplicaNumber"; cloneNumConfig = "replicaCloneTransferNumber"; nextEndConfig = "nextEndReplicaNumber"; @@ -161,12 +158,19 @@ protected void process(CMSRequest cmsReq) throws EBaseException { * cases this is done by a scheduled task). */ - String endNumStr = dbConfig.getString(endNumConfig); - BigInteger endNum = new BigInteger(endNumStr, radix); + BigInteger endNum; + BigInteger transferSize; + if (repo.getIDGenerator() == Repository.IDGenerator.LEGACY_2) { + endNum = dbConfig.getBigInteger(endNumConfig); + transferSize = dbConfig.getBigInteger(cloneNumConfig); + } else { + String endNumStr = dbConfig.getString(endNumConfig); + endNum = new BigInteger(endNumStr, radix); + + String transferSizeStr = dbConfig.getString(cloneNumConfig, ""); + transferSize = new BigInteger(transferSizeStr, radix); + } logger.info("UpdateNumberRange: dbs." + endNumConfig + ": " + endNum); - - String transferSizeStr = dbConfig.getString(cloneNumConfig, ""); - BigInteger transferSize = new BigInteger(transferSizeStr, radix); logger.info("UpdateNumberRange: dbs." + cloneNumConfig + ": " + transferSize); // transferred range will start at beginNum @@ -224,7 +228,11 @@ protected void process(CMSRequest cmsReq) throws EBaseException { * this scenario is unlikely to arise. Furthermore, * recovery is automatic thanks to the scheduled tasks. */ - endNum = new BigInteger(dbConfig.getString(nextEndConfig, ""), radix); + if (repo.getIDGenerator() == Repository.IDGenerator.LEGACY_2) { + endNum = dbConfig.getBigInteger(nextEndConfig); + } else { + endNum = new BigInteger(dbConfig.getString(nextEndConfig, ""), radix); + } BigInteger newEndNum = endNum.subtract(transferSize); logger.info("UpdateNumberRange: Transferring from the end of next range"); @@ -232,7 +240,11 @@ protected void process(CMSRequest cmsReq) throws EBaseException { logger.info("UpdateNumberRange: Next range new end: " + newEndNum); repo.setNextMaxSerial(newEndNum); - dbConfig.putString(nextEndConfig, newEndNum.toString(radix)); + String strNewEndNum = newEndNum.toString(radix); + if (repo.getIDGenerator() == Repository.IDGenerator.LEGACY_2 && radix == Repository.HEX) { + strNewEndNum = "0x" + strNewEndNum; + } + dbConfig.putString(nextEndConfig, strNewEndNum); beginNum = newEndNum.add(BigInteger.ONE); } else { @@ -242,6 +254,9 @@ protected void process(CMSRequest cmsReq) throws EBaseException { BigInteger newEndNum = beginNum.subtract(BigInteger.ONE); repo.setMaxSerial(newEndNum); String newValStr = newEndNum.toString(radix); + if (repo.getIDGenerator() == Repository.IDGenerator.LEGACY_2 && radix == Repository.HEX) { + newValStr = "0x" + newValStr; + } dbConfig.putString(endNumConfig, newValStr); logger.info("UpdateNumberRange: New current range: " + nextSerial + ".." + newEndNum); @@ -273,8 +288,13 @@ protected void process(CMSRequest cmsReq) throws EBaseException { JSONObject jsonObj = new JSONObject(); ObjectNode responseNode = jsonObj.getMapper().createObjectNode(); responseNode.put("Status", SUCCESS); - responseNode.put("beginNumber", beginNum.toString(radix)); - responseNode.put("endNumber", endNum.toString(radix)); + if(repo.getIDGenerator() == Repository.IDGenerator.LEGACY_2 && radix == Repository.HEX) { + responseNode.put("beginNumber", "0x" + beginNum.toString(radix)); + responseNode.put("endNumber", "0x" + endNum.toString(radix)); + } else { + responseNode.put("beginNumber", beginNum.toString(radix)); + responseNode.put("endNumber", endNum.toString(radix)); + } jsonObj.getRootNode().set("Response", responseNode); outputResult(httpResp, "application/json", jsonObj.toByteArray()); cs.commit(false); diff --git a/base/server/src/main/java/com/netscape/cmscore/apps/DatabaseConfig.java b/base/server/src/main/java/com/netscape/cmscore/apps/DatabaseConfig.java index e895b3c11ba..186a4823ba0 100644 --- a/base/server/src/main/java/com/netscape/cmscore/apps/DatabaseConfig.java +++ b/base/server/src/main/java/com/netscape/cmscore/apps/DatabaseConfig.java @@ -37,6 +37,7 @@ public class DatabaseConfig extends ConfigStore { public static final String SERIAL_BASEDN = "serialDN"; public static final String SERIAL_RANGE_DN = "serialRangeDN"; + public static final String SERIAL_CLONE_TRANSFER_NUMBER = "serialCloneTransferNumber"; public static final String MIN_REQUEST_NUMBER = "beginRequestNumber"; public static final String MAX_REQUEST_NUMBER = "endRequestNumber"; @@ -49,6 +50,7 @@ public class DatabaseConfig extends ConfigStore { public static final String REQUEST_BASEDN = "requestDN"; public static final String REQUEST_RANGE_DN = "requestRangeDN"; + public static final String REQUEST_CLONE_TRANSFER_NUMBER = "requestCloneTransferNumber"; public static final String MIN_REPLICA_NUMBER = "beginReplicaNumber"; public static final String MAX_REPLICA_NUMBER = "endReplicaNumber"; @@ -124,6 +126,14 @@ public void setSerialRangeDN(String serialRangeDN) { putString(SERIAL_RANGE_DN, serialRangeDN); } + public String getSerialCloneTransferNumber() throws EBaseException { + return getString(SERIAL_CLONE_TRANSFER_NUMBER, ""); + } + + public void setSerialCloneTransferNumber(String serialCloneTransferNumber) { + putString(SERIAL_CLONE_TRANSFER_NUMBER, serialCloneTransferNumber); + } + public String getBeginSerialNumber() throws EBaseException { return getString(MIN_SERIAL_NUMBER, "0"); } @@ -188,6 +198,14 @@ public void setRequestRangeDN(String requestRangeDN) { putString(REQUEST_RANGE_DN, requestRangeDN); } + public String getRequestCloneTransferNumber() throws EBaseException { + return getString(REQUEST_CLONE_TRANSFER_NUMBER, ""); + } + + public void setRequestCloneTransferNumber(String requestCloneTransferNumber) { + putString(REQUEST_CLONE_TRANSFER_NUMBER, requestCloneTransferNumber); + } + public String getBeginRequestNumber() throws EBaseException { return getString(MIN_REQUEST_NUMBER, "0"); } diff --git a/base/server/src/main/java/com/netscape/cmscore/dbs/ReplicaIDRepository.java b/base/server/src/main/java/com/netscape/cmscore/dbs/ReplicaIDRepository.java index 089855003d4..c54123dd80b 100644 --- a/base/server/src/main/java/com/netscape/cmscore/dbs/ReplicaIDRepository.java +++ b/base/server/src/main/java/com/netscape/cmscore/dbs/ReplicaIDRepository.java @@ -38,7 +38,7 @@ public class ReplicaIDRepository extends Repository { * Constructs a certificate repository. */ public ReplicaIDRepository(DBSubsystem dbSubsystem) { - super(dbSubsystem, 10); + super(dbSubsystem, DEC); } @Override @@ -54,18 +54,10 @@ public void init() throws Exception { rangeDN = dbConfig.getReplicaRangeDN() + "," + dbSubsystem.getBaseDN(); logger.info("ReplicaIDRepository: - range DN: " + rangeDN); - minSerialName = DatabaseConfig.MIN_REPLICA_NUMBER; - String minSerial = dbConfig.getBeginReplicaNumber(); - if (minSerial != null) { - mMinSerialNo = new BigInteger(minSerial, mRadix); - } + mMinSerialNo = dbConfig.getBigInteger(DatabaseConfig.MIN_REPLICA_NUMBER, null); logger.info("ReplicaIDRepository: - min serial: " + mMinSerialNo); - maxSerialName = DatabaseConfig.MAX_REPLICA_NUMBER; - String maxSerial = dbConfig.getEndReplicaNumber(); - if (maxSerial != null) { - mMaxSerialNo = new BigInteger(maxSerial, mRadix); - } + mMaxSerialNo = dbConfig.getBigInteger(DatabaseConfig.MAX_REPLICA_NUMBER, null); logger.info("ReplicaIDRepository: - max serial: " + mMaxSerialNo); nextMinSerialName = DatabaseConfig.NEXT_MIN_REPLICA_NUMBER; @@ -73,7 +65,7 @@ public void init() throws Exception { if (nextMinSerial == null || nextMinSerial.equals("-1")) { mNextMinSerialNo = null; } else { - mNextMinSerialNo = new BigInteger(nextMinSerial, mRadix); + mNextMinSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MIN_REPLICA_NUMBER, null); } logger.info("ReplicaIDRepository: - next min serial: " + mNextMinSerialNo); @@ -82,19 +74,15 @@ public void init() throws Exception { if (nextMaxSerial == null || nextMaxSerial.equals("-1")) { mNextMaxSerialNo = null; } else { - mNextMaxSerialNo = new BigInteger(nextMaxSerial, mRadix); + mNextMaxSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MAX_REPLICA_NUMBER, null); } logger.info("ReplicaIDRepository: - next max serial: " + mNextMaxSerialNo); - String lowWaterMark = dbConfig.getReplicaLowWaterMark(); - if (lowWaterMark != null) { - mLowWaterMarkNo = new BigInteger(lowWaterMark, mRadix); - } + mLowWaterMarkNo = dbConfig.getBigInteger(DatabaseConfig.REPLICA_LOW_WATER_MARK, null); + logger.debug("ReplicaIDRepository: - low water mark serial: " + mNextMaxSerialNo); - String incrementNo = dbConfig.getReplicaIncrement(); - if (incrementNo != null) { - mIncrementNo = new BigInteger(incrementNo, mRadix); - } + mIncrementNo = dbConfig.getBigInteger(DatabaseConfig.REPLICA_INCREMENT, null); + logger.debug("ReplicaIDRepository: - increment serial: " + mIncrementNo); } /** 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 90b905b6dce..cf25fd1508c 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 @@ -50,7 +50,11 @@ public abstract class Repository { public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Repository.class); + public static final int HEX = 16; + public static final int DEC = 10; + public enum IDGenerator { + LEGACY_2("legacy2"), LEGACY("legacy"), RANDOM("random"); @@ -428,6 +432,9 @@ public void setMinSerialConfig() throws EBaseException { DatabaseConfig dbConfig = dbSubsystem.getDBConfigStore(); String serial = mMinSerialNo.toString(mRadix); + if (mRadix == HEX && idGenerator == IDGenerator.LEGACY_2) { + serial = "0x" + serial; + } logger.debug("Repository: Setting min serial number: " + serial); dbConfig.putString(minSerialName, serial); @@ -445,6 +452,9 @@ public void setMaxSerialConfig() throws EBaseException { DatabaseConfig dbConfig = dbSubsystem.getDBConfigStore(); String serial = mMaxSerialNo.toString(mRadix); + if (mRadix == HEX && idGenerator == IDGenerator.LEGACY_2) { + serial = "0x" + serial; + } logger.debug("Repository: Setting max serial number: " + serial); dbConfig.putString(maxSerialName, serial); @@ -466,6 +476,9 @@ public void setNextMinSerialConfig() throws EBaseException { dbConfig.remove(nextMinSerialName); } else { String serial = mNextMinSerialNo.toString(mRadix); + if (mRadix == HEX && idGenerator == IDGenerator.LEGACY_2) { + serial = "0x" + serial; + } logger.debug("Repository: Setting next min number: " + serial); dbConfig.putString(nextMinSerialName, serial); } @@ -488,6 +501,9 @@ public void setNextMaxSerialConfig() throws EBaseException { dbConfig.remove(nextMaxSerialName); } else { String serial = mNextMaxSerialNo.toString(mRadix); + if (mRadix == HEX && idGenerator == IDGenerator.LEGACY_2) { + serial = "0x" + serial; + } logger.debug("Repository: Setting next max number: " + serial); dbConfig.putString(nextMaxSerialName, serial); } @@ -622,9 +638,11 @@ public boolean hasRangeConflict() throws EBaseException { logger.info("Repository: Searching for conflicting entries"); + String minSerial = idGenerator == IDGenerator.LEGACY_2 ? + mMinSerialNo.toString() : mMinSerialNo.toString(mRadix); String filter = "(&(nsds5ReplConflict=*)(objectClass=pkiRange)(host= " + cs.getHostname() + ")(SecurePort=" + engine.getEESSLPort() + - ")(beginRange=" + mMinSerialNo.toString(mRadix) + "))"; + ")(beginRange=" + minSerial + "))"; LDAPSearchResults results = conn.search(rangeDN, LDAPv3.SCOPE_SUB, filter, null, false); @@ -697,8 +715,11 @@ public void checkRanges() throws EBaseException { logger.debug("Repository: Requesting next range"); String nextRange = getNextRange(); logger.debug("Repository: next range: " + nextRange); - - mNextMinSerialNo = new BigInteger(nextRange, mRadix); + if (idGenerator == IDGenerator.LEGACY_2) { + mNextMinSerialNo = new BigInteger(nextRange); + } else { + mNextMinSerialNo = new BigInteger(nextRange, mRadix); + } if (mNextMinSerialNo == null) { logger.debug("Repository: Next range not available"); } else { diff --git a/base/server/src/main/java/com/netscape/cmscore/request/RequestRepository.java b/base/server/src/main/java/com/netscape/cmscore/request/RequestRepository.java index 0773d60de31..31aad37bfba 100644 --- a/base/server/src/main/java/com/netscape/cmscore/request/RequestRepository.java +++ b/base/server/src/main/java/com/netscape/cmscore/request/RequestRepository.java @@ -58,6 +58,7 @@ public class RequestRepository extends Repository { public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RequestRepository.class); public static final String PROP_REQUEST_ID_GENERATOR = "request.id.generator"; + public static final String PROP_REQUEST_ID_RADIX = "request.id.radix"; public static final String DEFAULT_REQUEST_ID_GENERATOR = "legacy"; public static final String PROP_REQUEST_ID_LENGTH = "request.id.length"; @@ -77,8 +78,15 @@ public RequestRepository( DBSubsystem dbSubsystem, String filter) { - super(dbSubsystem, 10); - + super(dbSubsystem, DEC); + DatabaseConfig dbc = dbSubsystem.getDBConfigStore(); + try { + this.mRadix = dbc.getInteger(PROP_REQUEST_ID_RADIX, DEC); + logger.debug("CertificateRepository: number radix {}", this.mRadix); + + } catch (EBaseException ex) { + logger.debug("CertificateRepository: error reading number radix config, using default {} for ", HEX); + } this.secureRandom = secureRandom; this.filter = filter; } @@ -102,7 +110,8 @@ public void init() throws Exception { idLength = dbConfig.getInteger(PROP_REQUEST_ID_LENGTH, DEFAULT_REQUEST_ID_LENGTH); logger.debug("RequestRepository: - request ID length: " + idLength); - + } else if (idGenerator == IDGenerator.LEGACY_2) { + initLegacy2Generator(); } else { initLegacyGenerator(); } @@ -112,6 +121,45 @@ public void init() throws Exception { RequestRecord.register(dbSubsystem); } + protected void initLegacy2Generator() throws EBaseException { + DatabaseConfig dbConfig = dbSubsystem.getDBConfigStore(); + + rangeDN = dbConfig.getRequestRangeDN() + "," + dbSubsystem.getBaseDN(); + logger.debug("RequestRepository: - range DN: " + rangeDN); + + minSerialName = DatabaseConfig.MIN_REQUEST_NUMBER; + mMinSerialNo = dbConfig.getBigInteger(minSerialName, null); + logger.debug("RequestRepository: - min serial: " + mMinSerialNo); + + maxSerialName = DatabaseConfig.MAX_REQUEST_NUMBER; + mMaxSerialNo = dbConfig.getBigInteger(maxSerialName, null); + logger.debug("RequestRepository: - max serial: " + mMaxSerialNo); + + nextMinSerialName = DatabaseConfig.NEXT_MIN_REQUEST_NUMBER; + String nextMinSerial = dbConfig.getNextBeginSerialNumber(); + if (nextMinSerial == null || nextMinSerial.equals("-1")) { + mNextMinSerialNo = null; + } else { + mNextMinSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MIN_REQUEST_NUMBER, null); + } + logger.debug("RequestRepository: - next min serial: " + mNextMinSerialNo); + + nextMaxSerialName = DatabaseConfig.NEXT_MAX_REQUEST_NUMBER; + String nextMaxSerial = dbConfig.getNextEndSerialNumber(); + if (nextMaxSerial == null || nextMaxSerial.equals("-1")) { + mNextMaxSerialNo = null; + } else { + mNextMaxSerialNo = dbConfig.getBigInteger(DatabaseConfig.NEXT_MAX_REQUEST_NUMBER, null); + } + logger.debug("RequestRepository: - next max serial: " + mNextMaxSerialNo); + + mLowWaterMarkNo = dbConfig.getBigInteger(DatabaseConfig.REQUEST_LOW_WATER_MARK, null); + logger.debug("RequestRepository: - low water mark serial: " + mNextMaxSerialNo); + + mIncrementNo = dbConfig.getBigInteger(DatabaseConfig.REQUEST_INCREMENT, null); + logger.debug("RequestRepository: - increment serial: " + mIncrementNo); + } + public void initLegacyGenerator() throws Exception { DatabaseConfig dbConfig = dbSubsystem.getDBConfigStore(); diff --git a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemCLI.java b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemCLI.java index 2a11b4f0a71..93c9c17bcf9 100644 --- a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemCLI.java +++ b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemCLI.java @@ -16,6 +16,7 @@ import com.netscape.certsrv.base.EBaseException; import com.netscape.cmscore.apps.CMS; import com.netscape.cmscore.apps.EngineConfig; +import com.netscape.cmscore.apps.ServerConfig; import com.netscape.cmscore.base.ConfigStorage; import com.netscape.cmscore.base.FileConfigStorage; import com.netscape.cmscore.ldapconn.LDAPAuthenticationConfig; @@ -30,6 +31,7 @@ public abstract class SubsystemCLI extends CommandCLI { public static final Logger logger = LoggerFactory.getLogger(SubsystemCLI.class); + private static final String SERVER_XML = "server.xml"; protected SubsystemCLI(String name, String description, CLI parent) { super(name, description, parent); @@ -64,4 +66,18 @@ protected LdapAuthInfo getAuthInfo(PasswordStore passwordStore, LdapConnInfo con connInfo.getSecure()); return authInfo; } + + protected String getSecurePort(EngineConfig config) throws Exception { + + String path = CMS.getInstanceDir() + File.separator + "conf" + File.separator + SERVER_XML; + + ServerConfig serverConfig = ServerConfig.load(path); + String securePort = serverConfig.getSecurePort(); + + String port = config.getString("proxy.securePort", ""); + if (!port.equals("")) { + securePort = port; + } + return securePort; + } } diff --git a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemIdGeneratorUpdateCLI.java b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemIdGeneratorUpdateCLI.java new file mode 100644 index 00000000000..65a339ef753 --- /dev/null +++ b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemIdGeneratorUpdateCLI.java @@ -0,0 +1,289 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.cli; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.cmscore.apps.CMS; +import com.netscape.cmscore.apps.DatabaseConfig; +import com.netscape.cmscore.apps.EngineConfig; +import com.netscape.cmscore.dbs.DBSubsystem; +import com.netscape.cmscore.dbs.Repository; +import com.netscape.cmscore.dbs.Repository.IDGenerator; +import static com.netscape.cmscore.dbs.Repository.logger; +import com.netscape.cmscore.ldapconn.LDAPConfig; +import com.netscape.cmscore.ldapconn.LDAPConnectionConfig; +import com.netscape.cmscore.ldapconn.LdapAuthInfo; +import com.netscape.cmscore.ldapconn.LdapBoundConnection; +import com.netscape.cmscore.ldapconn.LdapConnInfo; +import com.netscape.cmscore.ldapconn.PKISocketConfig; +import com.netscape.cmscore.ldapconn.PKISocketFactory; +import com.netscape.cmscore.request.RequestRepository; +import com.netscape.cmsutil.password.PasswordStore; +import com.netscape.cmsutil.password.PasswordStoreConfig; +import java.math.BigInteger; +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPModification; +import netscape.ldap.LDAPSearchResults; +import netscape.ldap.LDAPv3; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.dogtagpki.cli.CLI; +import org.dogtagpki.util.logging.PKILogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Marco Fargetta {@literal } + */ +public abstract class SubsystemIdGeneratorUpdateCLI extends SubsystemCLI { + private static final Logger logger = LoggerFactory.getLogger(SubsystemIdGeneratorUpdateCLI.class); + protected IDGenerator idGenerator; + + public SubsystemIdGeneratorUpdateCLI(CLI parent) { + super("update", "Update " + parent.getParent().getParent().getName().toUpperCase() + " range generator", parent); + } + @Override + public void createOptions() { + options.addOption("t", "type", true, "Generator type to update."); + } + + @Override + public void execute(CommandLine cmd) throws Exception { + + if (!cmd.hasOption("type")) { + throw new Exception("Missing generator type."); + } + String generatorType = cmd.getOptionValue("type"); + + if (cmd.hasOption("debug")) { + PKILogger.setLevel(PKILogger.LogLevel.DEBUG); + + } else if (cmd.hasOption("verbose")) { + PKILogger.setLevel(PKILogger.LogLevel.INFO); + } + + String[] cmdArgs = cmd.getArgs(); + + if (cmdArgs.length != 1) { + throw new Exception("Missing generator"); + } + IDGenerator generator = IDGenerator.fromString(cmdArgs[0]); + + initializeTomcatJSS(); + String subsystem = parent.getParent().getParent().getName(); + EngineConfig cs = getEngineConfig(subsystem); + cs.load(); + + LDAPConfig ldapConfig = cs.getInternalDBConfig(); + String baseDN = ldapConfig.getBaseDN(); + + PasswordStoreConfig psc = cs.getPasswordStoreConfig(); + PasswordStore passwordStore = CMS.createPasswordStore(psc); + + LDAPConnectionConfig connConfig = ldapConfig.getConnectionConfig(); + + LdapConnInfo connInfo = new LdapConnInfo(connConfig); + LdapAuthInfo authInfo = getAuthInfo(passwordStore, connInfo, ldapConfig); + + PKISocketConfig socketConfig = cs.getSocketConfig(); + + PKISocketFactory socketFactory = new PKISocketFactory(); + socketFactory.setSecure(connInfo.getSecure()); + if (authInfo.getAuthType() == LdapAuthInfo.LDAP_AUTHTYPE_SSLCLIENTAUTH) { + socketFactory.setClientCertNickname(authInfo.getClientCertNickname()); + } + socketFactory.init(socketConfig); + + DatabaseConfig dbConfig = cs.getDatabaseConfig(); + + if (generatorType.equals("cert")){ + updateSerialNumberRangeGenerator( + socketFactory, + connInfo, + authInfo, + dbConfig, + baseDN, + generator, + cs.getHostname(), + getSecurePort(cs)); + cs.commit(false); + } else if (generatorType.equals("request")) { + updateRequestNumberRangeGenerator( + socketFactory, + connInfo, + authInfo, + dbConfig, + baseDN, + generator); + cs.commit(false); + } else { + throw new EBaseException("Generator type " + generatorType + " not supported."); + } + } + + protected void updateSerialNumberRangeGenerator(PKISocketFactory socketFactory, LdapConnInfo connInfo, + LdapAuthInfo authInfo, DatabaseConfig dbConfig, String baseDN, IDGenerator newGenerator, + String hostName, String securePort) throws Exception { + + if (newGenerator == IDGenerator.RANDOM && idGenerator != IDGenerator.RANDOM) { + logger.debug("Remove serial ranges from configuration"); + dbConfig.remove(DatabaseConfig.MIN_SERIAL_NUMBER); + dbConfig.remove(DatabaseConfig.MAX_SERIAL_NUMBER); + dbConfig.remove(DatabaseConfig.SERIAL_INCREMENT); + dbConfig.remove(DatabaseConfig.SERIAL_LOW_WATER_MARK); + dbConfig.remove(DatabaseConfig.SERIAL_CLONE_TRANSFER_NUMBER); + dbConfig.remove(DatabaseConfig.SERIAL_RANGE_DN); + return; + } + if (newGenerator == IDGenerator.LEGACY_2 && idGenerator == IDGenerator.LEGACY) { + logger.debug("Repository: Updating ranges entry to hex format"); + + LdapBoundConnection conn = new LdapBoundConnection(socketFactory, connInfo, authInfo); + try{ + String rangeDN = dbConfig.getSerialRangeDN() + "," + baseDN; + + String beginSerialNumber = dbConfig.getBeginSerialNumber(); + dbConfig.setBeginSerialNumber("0x" + beginSerialNumber); + + String endSerialNumber = dbConfig.getEndSerialNumber(); + LDAPEntry entrySerial = conn.read("cn=" + beginSerialNumber+"," + rangeDN); + LDAPAttribute attrEnd = entrySerial.getAttribute("endRange"); + if (attrEnd != null) { + endSerialNumber = attrEnd.getStringValues().nextElement(); + } + dbConfig.setEndSerialNumber("0x" + endSerialNumber); + + String serialIncrement = dbConfig.getSerialIncrement(); + dbConfig.setSerialIncrement("0x" + serialIncrement); + + String serialLowWaterMark = dbConfig.getSerialLowWaterMark(); + dbConfig.setSerialLowWaterMark("0x" + serialLowWaterMark); + + String serialCloneTransfer = dbConfig.getSerialCloneTransferNumber(); + dbConfig.setSerialCloneTransferNumber("0x" + serialCloneTransfer); + + String nextBeginSerial = dbConfig.getNextBeginSerialNumber(); + String nextEndSerial = dbConfig.getNextEndSerialNumber(); + if (nextBeginSerial != null && !nextBeginSerial.equals("-1")) { + dbConfig.setNextBeginSerialNumber("0x" + nextBeginSerial); + + LDAPEntry entryNextSerial = conn.read("cn=" + nextBeginSerial + "," + rangeDN); + LDAPAttribute attrNextEnd = entryNextSerial.getAttribute("endRange"); + if (attrNextEnd != null) { + nextEndSerial = attrNextEnd.getStringValues().nextElement(); + } + dbConfig.setNextEndSerialNumber("0x" + nextEndSerial); + endSerialNumber = nextEndSerial; + } + updateRanges(dbConfig, conn, baseDN, rangeDN, endSerialNumber, hostName, securePort); + } finally { + conn.disconnect(); + } + return; + } + throw new EBaseException("Update to " + newGenerator + " not supported"); + } + + protected void updateRequestNumberRangeGenerator(PKISocketFactory socketFactory, LdapConnInfo connInfo, + LdapAuthInfo authInfo, DatabaseConfig dbConfig, String baseDN, IDGenerator newGenerator) throws EBaseException { + + String value = dbConfig.getString( + RequestRepository.PROP_REQUEST_ID_GENERATOR, + RequestRepository.DEFAULT_REQUEST_ID_GENERATOR); + idGenerator = IDGenerator.fromString(value); + + if (newGenerator == IDGenerator.RANDOM && idGenerator != IDGenerator.RANDOM) { + logger.debug("Remove request ranges from configuration"); + dbConfig.remove(DatabaseConfig.MIN_REQUEST_NUMBER); + dbConfig.remove(DatabaseConfig.MAX_REQUEST_NUMBER); + dbConfig.remove(DatabaseConfig.REQUEST_INCREMENT); + dbConfig.remove(DatabaseConfig.REQUEST_LOW_WATER_MARK); + dbConfig.remove(DatabaseConfig.REQUEST_CLONE_TRANSFER_NUMBER); + dbConfig.remove(DatabaseConfig.REQUEST_RANGE_DN); + dbConfig.put(RequestRepository.PROP_REQUEST_ID_GENERATOR, newGenerator.toString()); + dbConfig.put(RequestRepository.PROP_REQUEST_ID_LENGTH, "128"); + return; + } + if (newGenerator == IDGenerator.LEGACY_2 && idGenerator == IDGenerator.LEGACY) { + dbConfig.put(RequestRepository.PROP_REQUEST_ID_GENERATOR, newGenerator.toString()); + dbConfig.put(RequestRepository.PROP_REQUEST_ID_RADIX, Integer.toString(Repository.DEC)); + return; + } + throw new EBaseException("Update to " + newGenerator + " not supported"); + } + + private void updateRanges(DatabaseConfig dbConfig, LdapBoundConnection conn, String baseDN, String rangeDN, String configEndSerialNumber, + String hostName, String securePort) throws Exception{ + + LDAPSearchResults ranges = conn.search(rangeDN, LDAPv3.SCOPE_SUB, "(objectClass=pkiRange)", null, false); + + BigInteger lastUsedSerial = BigInteger.ZERO; + boolean nextRangeToUpdate = true; + // Search for the last range entry. If it is associated to the CA to update or ranges are not defined + // then the nextRange is + while (ranges.hasMoreElements()) { + LDAPEntry entry = ranges.next(); + String endRange = entry.getAttribute("endRange").getStringValues().nextElement(); + String host = entry.getAttribute("host").getStringValues().nextElement(); + String port = entry.getAttribute("securePort").getStringValues().nextElement(); + BigInteger next = new BigInteger(endRange, 16); + if (lastUsedSerial.compareTo(next) < 0) { + lastUsedSerial = next; + nextRangeToUpdate = host.equals(hostName) && port.equals(securePort); + + } + } + + if (nextRangeToUpdate) { + // nextRange is updated using last range entry or, if no ranges, the configured endSerialNumber + if (lastUsedSerial == BigInteger.ZERO) { + lastUsedSerial = new BigInteger(configEndSerialNumber, 16); + } + BigInteger nextSerialNumber = lastUsedSerial.add(BigInteger.ONE); + String serialDN = dbConfig.getSerialDN() + "," + baseDN; + // store nextRange as decimal + LDAPAttribute attrSerialNextRange = new LDAPAttribute("nextRange", nextSerialNumber.toString()); + + LDAPModification serialmod = new LDAPModification(LDAPModification.REPLACE, attrSerialNextRange); + + conn.modify(serialDN, serialmod); + } + + LDAPSearchResults instanceRanges = conn.search(rangeDN, LDAPv3.SCOPE_SUB, "(&(objectClass=pkiRange)(host= " + + hostName + ")(SecurePort=" + securePort + "))", null, false); + + // update all ranges associated to the CA to update to decimal + while (instanceRanges.hasMoreElements()) { + LDAPEntry entry = instanceRanges.next(); + String beginRange = entry.getAttribute("beginRange").getStringValues().nextElement(); + BigInteger beginRangeNo = new BigInteger(beginRange, 16); + String endRange = entry.getAttribute("endRange").getStringValues().nextElement(); + BigInteger endRangeNo = new BigInteger(endRange, 16); + 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", beginRangeNo.toString())); + + // store endRange as decimal + attrs.add(new LDAPAttribute("endRange", endRangeNo.toString())); + + attrs.add(new LDAPAttribute("cn", beginRangeNo.toString())); + attrs.add(new LDAPAttribute("host", hostName)); + attrs.add(new LDAPAttribute("securePort", securePort)); + + String dn = "cn=" + beginRangeNo.toString() + "," + rangeDN; + LDAPEntry rangeEntry = new LDAPEntry(dn, attrs); + logger.info("SubsystemRangeGeneratorUpdateCLI.updateRanges: Remove entry " + entry.getDN()); + conn.delete(entry.getDN()); + logger.info("SubsystemRangeGeneratorUpdateCLI.updateRanges: Adding entry " + dn); + conn.add(rangeEntry); + } + } +} \ No newline at end of file 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 90ce9ca8ab9..3578dabeeed 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 @@ -38,6 +38,8 @@ public class SubsystemRangeUpdateCLI extends SubsystemCLI { public static final Logger logger = LoggerFactory.getLogger(SubsystemRangeUpdateCLI.class); + protected IDGenerator idGenerator; + public SubsystemRangeUpdateCLI(CLI parent) { super("update", "Update " + parent.getParent().getName().toUpperCase() + " ranges", parent); } @@ -109,17 +111,20 @@ 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()); - - // generate nextRange in decimal - String nextSerialNumber = endSerialNumber.add(BigInteger.ONE).toString(); + BigInteger endSerialNumber; + if (idGenerator == IDGenerator.LEGACY_2) { + endSerialNumber = dbConfig.getBigInteger(DatabaseConfig.MAX_SERIAL_NUMBER); + } else { + // parse the end of current cert range as decimal + // NOTE: this is a bug, cert range is stored as hex in CS.cfg + endSerialNumber = new BigInteger(dbConfig.getEndSerialNumber()); + } + BigInteger nextSerialNumber = endSerialNumber.add(BigInteger.ONE); String serialDN = dbConfig.getSerialDN() + "," + baseDN; // store nextRange as decimal - LDAPAttribute attrSerialNextRange = new LDAPAttribute("nextRange", nextSerialNumber); + LDAPAttribute attrSerialNextRange = new LDAPAttribute("nextRange", nextSerialNumber.toString()); LDAPModification serialmod = new LDAPModification(LDAPModification.REPLACE, attrSerialNextRange); @@ -140,9 +145,9 @@ public void updateRequestNumberRange( String value = dbConfig.getString( RequestRepository.PROP_REQUEST_ID_GENERATOR, RequestRepository.DEFAULT_REQUEST_ID_GENERATOR); - IDGenerator idGenerator = IDGenerator.fromString(value); + idGenerator = IDGenerator.fromString(value); - if (idGenerator != IDGenerator.LEGACY) { + if (idGenerator == IDGenerator.RANDOM) { logger.info("No need to update request ID range"); return; } @@ -152,16 +157,19 @@ public void updateRequestNumberRange( try { logger.info("Updating request ID range"); - // parse the end of current range as decimal - BigInteger endRequestNumber = new BigInteger(dbConfig.getEndRequestNumber()); - - // generate nextRange in decimal - String nextRequestNumber = endRequestNumber.add(BigInteger.ONE).toString(); + BigInteger endRequestNumber; + if (idGenerator == IDGenerator.LEGACY_2) { + endRequestNumber = dbConfig.getBigInteger(DatabaseConfig.MAX_REQUEST_NUMBER); + } else { + // parse the end of current range as decimal + endRequestNumber = new BigInteger(dbConfig.getEndRequestNumber()); + } + BigInteger nextRequestNumber = endRequestNumber.add(BigInteger.ONE); String requestDN = dbConfig.getRequestDN() + "," + baseDN; // store nextRange as decimal - LDAPAttribute attrRequestNextRange = new LDAPAttribute("nextRange", nextRequestNumber); + LDAPAttribute attrRequestNextRange = new LDAPAttribute("nextRange", nextRequestNumber.toString()); LDAPModification requestmod = new LDAPModification(LDAPModification.REPLACE, attrRequestNextRange); diff --git a/base/server/src/test/java/com/netscape/cmscore/test/CMSBaseTestHelper.java b/base/server/src/test/java/com/netscape/cmscore/test/CMSBaseTestHelper.java index cdfdb58dc18..5e7817e8ac7 100644 --- a/base/server/src/test/java/com/netscape/cmscore/test/CMSBaseTestHelper.java +++ b/base/server/src/test/java/com/netscape/cmscore/test/CMSBaseTestHelper.java @@ -4,6 +4,7 @@ import org.mozilla.jss.netscape.security.x509.X509CertImpl; +import com.netscape.cmscore.apps.DatabaseConfig; import com.netscape.cmscore.dbs.DBRegistry; import com.netscape.cmscore.dbs.DBSSession; import com.netscape.cmscore.dbs.DBSubsystem; @@ -28,11 +29,13 @@ public static void setDbSubsystem(DBSubsystemStub dbSubsystem) { private static DBSubsystemStub dbSubsystem; static DBRegistry registry; static DBSSession session; + static DatabaseConfig databaseConfig; public static final void setUp() { setDbSubsystem(new DBSubsystemStub()); registry = new DBRegistry(); session = new DBSSession(); + databaseConfig = new DatabaseConfig(null); } public static X509CertImpl getFakeCert() throws CertificateException { @@ -72,5 +75,10 @@ public DBSSession createSession() { public DBRegistry getRegistry() { return registry; } + + @Override + public DatabaseConfig getDBConfigStore() { + return databaseConfig; + } } }