From b85ce8702faf4d501e185b04063a5602f30b5377 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sat, 16 Mar 2024 22:09:17 -0500 Subject: [PATCH 01/37] Update CMAKE to be compatible with versions about 3.5 --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad057af0b6c..eb63cda66bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # Required cmake version -cmake_minimum_required(VERSION 3.0.0) +cmake_minimum_required(VERSION 3.5) project(pki) @@ -35,9 +35,9 @@ if (NOT DEFINED THEME) set(THEME "dogtag") endif(NOT DEFINED THEME) -string(REGEX REPLACE "^([0-9]+).*" "\\1" APPLICATION_VERSION_MAJOR ${VERSION}) -string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" APPLICATION_VERSION_MINOR ${VERSION}) -string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" APPLICATION_VERSION_PATCH ${VERSION}) +string(REGEX REPLACE "^([0-9]+).*" "\\1" "APPLICATION_VERSION_MAJOR" "${VERSION}") +string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" "APPLICATION_VERSION_MINOR" "${VERSION}") +string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" "APPLICATION_VERSION_PATCH" "${VERSION}") set(APP_SERVER "tomcat-9.0" CACHE STRING "Application server") From b51af27209349db5be4964c7a016f7afa185305e Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 00:21:51 -0500 Subject: [PATCH 02/37] Implement base ACME Algorithm class --- .../org/dogtagpki/acme/ACMEAlgorithm.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java new file mode 100644 index 00000000000..6174d26487b --- /dev/null +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -0,0 +1,42 @@ +package org.dogtagpki.acme; + +public class ACMEAlgorithm { + public enum Algorithm { + HS256("HS256","HmacSHA256"), + HS384("HS384", "HmacSHA384"), + HS512("HS512", "HmacSHA512"), + RS256("RS256", "SHA256withRSA"), + RS384("RS384", "SHA384withRSA"), + RS512("RS512", "SHA512withRSA"), + ES256("ES256", "SHA256withECDSA"), + ES384("ES384", "SHA384withECDSA"), + ES512("ES512", "SHA512withECDSA"), + PS256("PS256", "SHA256withRSAandMGF1"), + PS384("PS384", "SHA384withRSAandMGF1"), + PS512("PS512", "SHA512withRSAandMGF1"); + + private String alg; + private String jca; + + // RFC 7518 Appendix A.1 + // Digital Signature/MAC Algorithm Identifier Cross-Reference + public String getJCA() { + return jca; + } + + private Algorithm (String alg, String jca) { + this.alg = alg; + this.jca = jca; + } + } + + public boolean isSupported(String alg) { + for (Algorithm a : Algorithm.values()) { + if (a.alg == alg) { + return true; + } + } + + return false; + } +} \ No newline at end of file From 679063e9ea021b22580962a0eca18aefd158ed1c Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 00:40:08 -0500 Subject: [PATCH 03/37] Remove isSupported as it was not needed --- .../org/dogtagpki/acme/ACMEAlgorithm.java | 67 +++++++++++-------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 6174d26487b..6c64a246a47 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -1,42 +1,53 @@ package org.dogtagpki.acme; -public class ACMEAlgorithm { - public enum Algorithm { - HS256("HS256","HmacSHA256"), - HS384("HS384", "HmacSHA384"), - HS512("HS512", "HmacSHA512"), - RS256("RS256", "SHA256withRSA"), - RS384("RS384", "SHA384withRSA"), - RS512("RS512", "SHA512withRSA"), - ES256("ES256", "SHA256withECDSA"), - ES384("ES384", "SHA384withECDSA"), - ES512("ES512", "SHA512withECDSA"), - PS256("PS256", "SHA256withRSAandMGF1"), - PS384("PS384", "SHA384withRSAandMGF1"), - PS512("PS512", "SHA512withRSAandMGF1"); - - private String alg; - private String jca; - - // RFC 7518 Appendix A.1 - // Digital Signature/MAC Algorithm Identifier Cross-Reference - public String getJCA() { - return jca; - } +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + +public enum ACMEAlgorithm { + HS256("HS256", "HmacSHA256"), + HS384("HS384", "HmacSHA384"), + HS512("HS512", "HmacSHA512"), + RS256("RS256", "SHA256withRSA"), + RS384("RS384", "SHA384withRSA"), + RS512("RS512", "SHA512withRSA"), + ES256("ES256", "SHA256withECDSA"), + ES384("ES384", "SHA384withECDSA"), + ES512("ES512", "SHA512withECDSA"), + PS256("PS256", "SHA256withRSAandMGF1"), + PS384("PS384", "SHA384withRSAandMGF1"), + PS512("PS512", "SHA512withRSAandMGF1"); + + private String alg; + private String jca; - private Algorithm (String alg, String jca) { + private ACMEAlgorithm(String alg, String jca) { this.alg = alg; this.jca = jca; } + + // RFC 7518 Appendix A.1 + // Digital Signature/MAC Algorithm Identifier Cross-Reference + public String getJCA() { + return jca; } - public boolean isSupported(String alg) { - for (Algorithm a : Algorithm.values()) { + public static ACMEAlgorithm fromString(String alg) throws Exception { + for (ACMEAlgorithm a : ACMEAlgorithm.values()) { if (a.alg == alg) { - return true; + return a; } } - return false; + ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST); + builder.type("application/problem+json"); + + ACMEError error = new ACMEError(); + error.setType("urn:ietf:params:acme:error:badSignatureAlgorithm"); + error.setDetail("Signature of type " + alg + " not supported\n" + + "Try again with RS256."); + builder.entity(error); + + throw new WebApplicationException(builder.build()); } } \ No newline at end of file From 08510effe80966aac809f6d5e4088ecf1bb0ea12 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 00:40:30 -0500 Subject: [PATCH 04/37] Implement ACMEAlgorithm in ACMEEngine --- .../org/dogtagpki/acme/server/ACMEEngine.java | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java b/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java index 92a8baa99a5..3dc56ecd1cc 100644 --- a/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java +++ b/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java @@ -37,6 +37,7 @@ import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.dogtagpki.acme.ACMEAccount; +import org.dogtagpki.acme.ACMEAlgorithm; import org.dogtagpki.acme.ACMEAuthorization; import org.dogtagpki.acme.ACMEError; import org.dogtagpki.acme.ACMEIdentifier; @@ -604,39 +605,23 @@ public void removeExpiredRecords(Date currentTime) throws Exception { public void validateJWS(JWS jws, String alg, JWK jwk) throws Exception { - // TODO: support other algorithms - Signature signer; PublicKey publicKey; + ACMEAlgorithm acmeAlgo = ACMEAlgorithm.fromString(alg); - if ("RS256".equals(alg)) { - - signer = Signature.getInstance("SHA256withRSA", "Mozilla-JSS"); - - String kty = jwk.getKty(); - KeyFactory keyFactory = KeyFactory.getInstance(kty, "Mozilla-JSS"); + signer = Signature.getInstance(acmeAlgo.getJCA(), "Mozilla-JSS"); - String n = jwk.getN(); - BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n)); + String kty = jwk.getKty(); + KeyFactory keyFactory = KeyFactory.getInstance(kty, "Mozilla-JSS"); - String e = jwk.getE(); - BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e)); + String n = jwk.getN(); + BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n)); - RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent); - publicKey = keyFactory.generatePublic(keySpec); - - } else { - ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST); - builder.type("application/problem+json"); + String e = jwk.getE(); + BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e)); - ACMEError error = new ACMEError(); - error.setType("urn:ietf:params:acme:error:badSignatureAlgorithm"); - error.setDetail("Signature of type " + alg + " not supported\n" + - "Try again with RS256."); - builder.entity(error); - - throw new WebApplicationException(builder.build()); - } + RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent); + publicKey = keyFactory.generatePublic(keySpec); validateJWS(jws, signer, publicKey); } From cecb00eb85db42b00cc9d0af9c9b8ebecc847ef4 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 01:02:15 -0500 Subject: [PATCH 05/37] Add Author --- .../src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 6c64a246a47..7e5998b349b 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -4,6 +4,10 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; +/** + * @author Minsu Park + */ + public enum ACMEAlgorithm { HS256("HS256", "HmacSHA256"), HS384("HS384", "HmacSHA384"), From 9d8ea306daed5163f616bb8d46b222e3610b83c9 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 01:05:24 -0500 Subject: [PATCH 06/37] Move RFC comment --- .../main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 7e5998b349b..444bba66539 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -9,6 +9,8 @@ */ public enum ACMEAlgorithm { + // RFC 7518 Appendix A.1 + // Digital Signature/MAC Algorithm Identifier Cross-Reference HS256("HS256", "HmacSHA256"), HS384("HS384", "HmacSHA384"), HS512("HS512", "HmacSHA512"), @@ -26,12 +28,10 @@ public enum ACMEAlgorithm { private String jca; private ACMEAlgorithm(String alg, String jca) { - this.alg = alg; - this.jca = jca; - } + this.alg = alg; + this.jca = jca; + } - // RFC 7518 Appendix A.1 - // Digital Signature/MAC Algorithm Identifier Cross-Reference public String getJCA() { return jca; } From 5be877e5cbc969d63b477554787ffc45d1f992a2 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 15:23:06 -0500 Subject: [PATCH 07/37] Move web app error back to ACMEengine --- .../org/dogtagpki/acme/server/ACMEEngine.java | 87 ++++++++++++------- .../org/dogtagpki/acme/ACMEAlgorithm.java | 11 +-- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java b/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java index 3dc56ecd1cc..700de81a377 100644 --- a/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java +++ b/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEEngine.java @@ -376,39 +376,37 @@ public void initMonitors(String filename) throws Exception { } // the default class just sends the default config values - Class configSourceClass - = ACMEEngineConfigDefaultSource.class; + Class configSourceClass = ACMEEngineConfigDefaultSource.class; String className = monitorsConfig.getProperty("engine.class"); if (className != null && !className.isEmpty()) { - configSourceClass = - (Class) Class.forName(className); + configSourceClass = (Class) Class.forName(className); } engineConfigSource = configSourceClass.getDeclaredConstructor().newInstance(); // We pass to the ConfigSource only the callbacks needed to set - // the configuration (Consumer). This abstraction ensures the + // the configuration (Consumer). This abstraction ensures the // ConfigSource has no direct access to the ACMEEngine instance. engineConfigSource.setEnabledConsumer(new Consumer() { - @Override public void accept(Boolean b) { + @Override + public void accept(Boolean b) { config.setEnabled(b); logger.info( - "ACME service is " - + (b ? "enabled" : "DISABLED") - + " by configuration" - ); + "ACME service is " + + (b ? "enabled" : "DISABLED") + + " by configuration"); } }); engineConfigSource.setWildcardConsumer(new Consumer() { - @Override public void accept(Boolean b) { + @Override + public void accept(Boolean b) { config.getPolicyConfig().setEnableWildcards(b); logger.info( - "ACME wildcard issuance is " - + (b ? "enabled" : "DISABLED") - + " by configuration" - ); + "ACME wildcard issuance is " + + (b ? "enabled" : "DISABLED") + + " by configuration"); } }); @@ -456,7 +454,7 @@ public void start() throws Exception { loadConfig(acmeConfDir + File.separator + "engine.conf"); Boolean noncePersistent = config.getNoncesPersistent(); - this.noncesPersistent = noncePersistent != null ? noncePersistent : false; + this.noncesPersistent = noncePersistent != null ? noncePersistent : false; initRandomGenerator(); initMetadata(acmeConfDir + File.separator + "metadata.conf"); @@ -471,7 +469,8 @@ public void start() throws Exception { } public void shutdownDatabase() throws Exception { - if (database == null) return; + if (database == null) + return; database.close(); database = null; @@ -487,28 +486,32 @@ public void shutdownValidators() throws Exception { } public void shutdownIssuer() throws Exception { - if (issuer == null) return; + if (issuer == null) + return; issuer.close(); issuer = null; } public void shutdownScheduler() throws Exception { - if (scheduler == null) return; + if (scheduler == null) + return; scheduler.shutdown(); scheduler = null; } public void shutdownMonitors() throws Exception { - if (engineConfigSource == null) return; + if (engineConfigSource == null) + return; engineConfigSource.shutdown(); engineConfigSource = null; } public void shutdownRealm() throws Exception { - if (realm == null) return; + if (realm == null) + return; realm.stop(); realm = null; @@ -607,7 +610,21 @@ public void validateJWS(JWS jws, String alg, JWK jwk) throws Exception { Signature signer; PublicKey publicKey; - ACMEAlgorithm acmeAlgo = ACMEAlgorithm.fromString(alg); + ACMEAlgorithm acmeAlgo; + + try { + acmeAlgo = ACMEAlgorithm.fromString(alg); + } catch(Exception e) { + ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST); + builder.type("application/problem+json"); + + ACMEError error = new ACMEError(); + error.setType("urn:ietf:params:acme:error:badSignatureAlgorithm"); + error.setDetail("Signature of type " + alg + " not supported"); + builder.entity(error); + + throw new WebApplicationException(builder.build()); + } signer = Signature.getInstance(acmeAlgo.getJCA(), "Mozilla-JSS"); @@ -776,7 +793,9 @@ public void addOrder(ACMEAccount account, ACMEOrder order) throws Exception { database.addOrder(order); } - enum CheckOrderResult { ORDER_ACCOUNT_MISMATCH , ORDER_EXPIRED , ORDER_ACCESS_OK, ORDER_NULL} + enum CheckOrderResult { + ORDER_ACCOUNT_MISMATCH, ORDER_EXPIRED, ORDER_ACCESS_OK, ORDER_NULL + } public CheckOrderResult checkOrder(ACMEAccount account, ACMEOrder order) { @@ -885,8 +904,8 @@ public void validateCSR(ACMEAccount account, ACMEOrder order, PKCS10 pkcs10) thr if (!unauthorizedDNSNames.isEmpty()) { // TODO: generate proper exception throw new Exception( - "Unauthorized DNS names: " - + StringUtils.join(unauthorizedDNSNames, ", ")); + "Unauthorized DNS names: " + + StringUtils.join(unauthorizedDNSNames, ", ")); } // check for authorized names missing from CSR @@ -895,8 +914,8 @@ public void validateCSR(ACMEAccount account, ACMEOrder order, PKCS10 pkcs10) thr if (!extraAuthorizedDNSNames.isEmpty()) { // TODO: generate proper exception throw new Exception( - "Missing DNS names from order: " - + StringUtils.join(extraAuthorizedDNSNames, ", ")); + "Missing DNS names from order: " + + StringUtils.join(extraAuthorizedDNSNames, ", ")); } // TODO: validate other things in CSR @@ -910,9 +929,9 @@ public void validateRevocation(ACMEAccount account, ACMERevocation revocation) t // // The server MUST consider at least the following accounts authorized // for a given certificate: - // - the account that issued the certificate. - // - an account that holds authorizations for all of the identifiers in - // the certificate. + // - the account that issued the certificate. + // - an account that holds authorizations for all of the identifiers in + // the certificate. Date now = new Date(); String certBase64 = revocation.getCertificate(); @@ -946,11 +965,13 @@ public void validateRevocation(ACMEAccount account, ACMERevocation revocation) t Collection identifiers = getCertIdentifiers(cert); if (identifiers.isEmpty()) { - /* Protect against vacuous authorisation. If there are no + /* + * Protect against vacuous authorisation. If there are no * identifiers, it could be e.g. a user or CA certificate. * Without this check that there are at least /some/ identifiers * to authorise, every account would be vacuously authorised - * to revoke it. */ + * to revoke it. + */ throw new Exception("Certificate has no ACME identifiers."); } @@ -995,7 +1016,7 @@ public void validateRevocation(ACMEAccount account, ACMERevocation revocation) t logger.info("Account has no authorizations for:"); for (ACMEIdentifier identifier : identifiers) { logger.info("- " + identifier.getType() + ": " + identifier.getValue()); - } + } // TODO: generate proper exception throw new Exception("Account has no authorizations for " + identifiers); diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 444bba66539..5460eb7fb2f 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -43,15 +43,6 @@ public static ACMEAlgorithm fromString(String alg) throws Exception { } } - ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST); - builder.type("application/problem+json"); - - ACMEError error = new ACMEError(); - error.setType("urn:ietf:params:acme:error:badSignatureAlgorithm"); - error.setDetail("Signature of type " + alg + " not supported\n" + - "Try again with RS256."); - builder.entity(error); - - throw new WebApplicationException(builder.build()); + throw new Exception("unsupported algorithm " + alg); } } \ No newline at end of file From c5c23fb2fec13f51919aa4c1c2103a8d22f245d9 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sun, 17 Mar 2024 16:32:49 -0500 Subject: [PATCH 08/37] Remove unused imports --- .../src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 5460eb7fb2f..455af1bead8 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -1,9 +1,5 @@ package org.dogtagpki.acme; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.ResponseBuilder; - /** * @author Minsu Park */ From 339a7ea2f5fbbddd2d5104b77f2f9e9e881085d3 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 21 Mar 2024 20:23:29 -0500 Subject: [PATCH 09/37] Simplify ACME Algorithm string conversion --- .../src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 455af1bead8..436d46e741c 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -33,12 +33,6 @@ public String getJCA() { } public static ACMEAlgorithm fromString(String alg) throws Exception { - for (ACMEAlgorithm a : ACMEAlgorithm.values()) { - if (a.alg == alg) { - return a; - } - } - - throw new Exception("unsupported algorithm " + alg); + return ACMEAlgorithm.valueOf(alg.toUpperCase()); } } \ No newline at end of file From f90f2b1e63e46f50e74c448ab3e05739f2260614 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 21 Mar 2024 20:28:11 -0500 Subject: [PATCH 10/37] Add new line --- base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 436d46e741c..513090edbd2 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -35,4 +35,4 @@ public String getJCA() { public static ACMEAlgorithm fromString(String alg) throws Exception { return ACMEAlgorithm.valueOf(alg.toUpperCase()); } -} \ No newline at end of file +} From 8126c1660350a26619823ff45e9ca2ebd8408c3f Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 21 Mar 2024 20:49:21 -0500 Subject: [PATCH 11/37] Specify an exact argument fromString should throw --- base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 513090edbd2..f94b0103c39 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -32,7 +32,7 @@ public String getJCA() { return jca; } - public static ACMEAlgorithm fromString(String alg) throws Exception { + public static ACMEAlgorithm fromString(String alg) throws IllegalArgumentException { return ACMEAlgorithm.valueOf(alg.toUpperCase()); } } From 79ce58df29565ee560f987d3541c71f8388b59bf Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sat, 23 Mar 2024 23:06:01 -0500 Subject: [PATCH 12/37] Remove unsupported algorithms --- .../java/org/dogtagpki/acme/ACMEAlgorithm.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index f94b0103c39..e124992fe61 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -7,18 +7,18 @@ public enum ACMEAlgorithm { // RFC 7518 Appendix A.1 // Digital Signature/MAC Algorithm Identifier Cross-Reference - HS256("HS256", "HmacSHA256"), - HS384("HS384", "HmacSHA384"), - HS512("HS512", "HmacSHA512"), + + // Dogtag's JSS has slightly different algorithm names + // than what is in RFC 7518 RS256("RS256", "SHA256withRSA"), RS384("RS384", "SHA384withRSA"), RS512("RS512", "SHA512withRSA"), - ES256("ES256", "SHA256withECDSA"), - ES384("ES384", "SHA384withECDSA"), - ES512("ES512", "SHA512withECDSA"), - PS256("PS256", "SHA256withRSAandMGF1"), - PS384("PS384", "SHA384withRSAandMGF1"), - PS512("PS512", "SHA512withRSAandMGF1"); + ES256("ES256", "SHA256withEC"), + ES384("ES384", "SHA384withEC"), + ES512("ES512", "SHA512withEC"), + PS256("PS256", "SHA256withRSA/PSS"), + PS384("PS384", "SHA384withRSA/PSS"), + PS512("PS512", "SHA512withRSA/PSS"); private String alg; private String jca; From 79eb75ee07d991729a619854f51f4d40df32f7ed Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sat, 23 Mar 2024 23:33:44 -0500 Subject: [PATCH 13/37] Add test for ES256 --- .github/workflows/acme-certbot-test.yml | 67 +++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 20a7b1de188..74479f643e1 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -212,6 +212,15 @@ jobs: - name: Install certbot in client container run: docker exec client dnf install -y certbot + - name: Create CSR for ES256 Test + run: docker exec client openssl req \ + --outform PEM \ + --out ES256.csr \ + --newkey ec \ + --keyout ES256.key \ + --sha256 \ + --subj '/CN=es256.example.com' + - name: Register ACME account run: | docker exec client certbot register \ @@ -352,6 +361,64 @@ jobs: sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual + - name: Enroll using ES256 CSR + run: | + docker exec client certbot certonly \ + --server http://pki.example.com:8080/acme/directory \ + --key-path ES256.key \ + --csr ES256.csr \ + --standalone \ + --non-interactive + + - name: Check ES256 client locally + run: | + docker exec client pki client-cert-import \ + --cert /etc/letsencrypt/live/es256.example.com/fullchain.pem \ + es256 + + # store serial number + docker exec client pki nss-cert-show es256 | tee output + sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > es256.txt + + # subject should be CN=es256.example.com + echo "CN=es256.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + + - name: Check ES256 Registration + run: | + docker exec pki pki ca-cert-find | tee output + + # there should be 8 certs + echo "8" > expected + grep "Serial Number:" output | wc -l > actual + diff expected actual + + # check client cert + SERIAL=$(cat serial1.txt) + docker exec pki pki ca-cert-show $SERIAL | tee output + + # subject should be CN=client.example.com + echo "CN=client.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + + - name: Check ACME certs after enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificates,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no certs (they are stored in CA) + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + - name: Renew client cert run: | docker exec client certbot renew \ From 8f1fb62dc21703844d768bb342108ad68e1a0956 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Sat, 23 Mar 2024 23:42:16 -0500 Subject: [PATCH 14/37] Check against the correct serial number --- .github/workflows/acme-certbot-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 74479f643e1..aa76e5e9316 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -395,7 +395,7 @@ jobs: diff expected actual # check client cert - SERIAL=$(cat serial1.txt) + SERIAL=$(cat rs256.txt) docker exec pki pki ca-cert-show $SERIAL | tee output # subject should be CN=client.example.com From dc6ba9e8a3449d864cee4103f1b89894d005790c Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Mon, 25 Mar 2024 23:17:35 -0500 Subject: [PATCH 15/37] Correct parameters for openssl csr generation --- .github/workflows/acme-certbot-test.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index aa76e5e9316..4097d88995e 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -214,12 +214,14 @@ jobs: - name: Create CSR for ES256 Test run: docker exec client openssl req \ - --outform PEM \ - --out ES256.csr \ - --newkey ec \ - --keyout ES256.key \ - --sha256 \ - --subj '/CN=es256.example.com' + -outform PEM \ + -out ES256.csr \ + -newkey ec \ + -pkeyopt ec_paramgen_curve:P-256 \ + -keyout ES256.key \ + -sha256 \ + -subj '/CN=es256.example.com' + -nodes - name: Register ACME account run: | From f113955449877aee8d8033c3b3f5ad0297b06b16 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Mon, 25 Mar 2024 23:19:44 -0500 Subject: [PATCH 16/37] Add line separator --- .github/workflows/acme-certbot-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 4097d88995e..0655b5993a0 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -220,7 +220,7 @@ jobs: -pkeyopt ec_paramgen_curve:P-256 \ -keyout ES256.key \ -sha256 \ - -subj '/CN=es256.example.com' + -subj '/CN=es256.example.com' \ -nodes - name: Register ACME account From 87d5d0effcda76f091d4ba247abff861e076bbae Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Tue, 26 Mar 2024 20:38:46 -0500 Subject: [PATCH 17/37] Add install instructions for openssl --- .github/workflows/acme-certbot-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 0655b5993a0..7df35e5e993 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -212,6 +212,9 @@ jobs: - name: Install certbot in client container run: docker exec client dnf install -y certbot + - name: Install certbot in client container + run: docker exec client dnf install -y openssl + - name: Create CSR for ES256 Test run: docker exec client openssl req \ -outform PEM \ From ba81084434d7b1cf4c39a29660ba420d16201d81 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Tue, 26 Mar 2024 20:43:31 -0500 Subject: [PATCH 18/37] Move instructions to near where they're used --- .github/workflows/acme-certbot-test.yml | 29 +++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 7df35e5e993..0a25213edca 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -209,22 +209,8 @@ jobs: - name: Connect client container to network run: docker network connect example client --alias client.example.com - - name: Install certbot in client container - run: docker exec client dnf install -y certbot - - - name: Install certbot in client container - run: docker exec client dnf install -y openssl - - - name: Create CSR for ES256 Test - run: docker exec client openssl req \ - -outform PEM \ - -out ES256.csr \ - -newkey ec \ - -pkeyopt ec_paramgen_curve:P-256 \ - -keyout ES256.key \ - -sha256 \ - -subj '/CN=es256.example.com' \ - -nodes + - name: Install certbot and openssl in client container + run: docker exec client dnf install -y certbot openssl - name: Register ACME account run: | @@ -366,6 +352,17 @@ jobs: sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual + - name: Create CSR for ES256 Test + run: docker exec client openssl req \ + -outform PEM \ + -out ES256.csr \ + -newkey ec \ + -pkeyopt ec_paramgen_curve:P-256 \ + -keyout ES256.key \ + -sha256 \ + -subj '/CN=es256.example.com' \ + -nodes + - name: Enroll using ES256 CSR run: | docker exec client certbot certonly \ From 1108684ea2c346ba2500e5848ae3db7e747d88da Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Tue, 26 Mar 2024 20:57:59 -0500 Subject: [PATCH 19/37] Mirror tests for RS256 --- .github/workflows/acme-certbot-test.yml | 74 ++++++++++++++++++++----- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 0a25213edca..67308f8e763 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -387,25 +387,55 @@ jobs: sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual - - name: Check ES256 Registration + - name: Check ACME orders after ES256 enrollment run: | - docker exec pki pki ca-cert-find | tee output + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=orders,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output - # there should be 8 certs - echo "8" > expected - grep "Serial Number:" output | wc -l > actual + # there should be two orders + echo "2" > expected + grep "^dn:" output | wc -l > actual diff expected actual - # check client cert - SERIAL=$(cat rs256.txt) - docker exec pki pki ca-cert-show $SERIAL | tee output + - name: Check ACME authorizations after ES256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=authorizations,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output - # subject should be CN=client.example.com - echo "CN=client.example.com" > expected - sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual - diff expected actual + # there should be two authorizations + echo "2" > expected + grep "^dn:" output | wc -l > actual + diff expected actual - - name: Check ACME certs after enrollment + - name: Check ACME challenges after ES256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=challenges,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be two challenges + echo "2" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check ACME certs after ES256 enrollment run: | docker exec ds ldapsearch \ -H ldap://ds.example.com:3389 \ @@ -421,6 +451,24 @@ jobs: grep "^dn:" output | wc -l > actual diff expected actual + - name: Check CA certs after ES256 enrollment + run: | + docker exec pki pki ca-cert-find | tee output + + # there should be 8 certs + echo "8" > expected + grep "Serial Number:" output | wc -l > actual + diff expected actual + + # check client cert + SERIAL=$(cat es256.txt) + docker exec pki pki ca-cert-show $SERIAL | tee output + + # subject should be CN=es256.example.com + echo "CN=es256.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + - name: Renew client cert run: | docker exec client certbot renew \ From 6a31b85f69bfb4734de7f6bfd77aa0d167353525 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 21:18:44 -0500 Subject: [PATCH 20/37] Remove openssl install step, as it is already inside client's container --- .github/workflows/acme-certbot-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 67308f8e763..89af8425282 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -209,8 +209,8 @@ jobs: - name: Connect client container to network run: docker network connect example client --alias client.example.com - - name: Install certbot and openssl in client container - run: docker exec client dnf install -y certbot openssl + - name: Install certbot in client container + run: docker exec client dnf install -y certbot - name: Register ACME account run: | From a0f8e74d997162c0d4400447a5c60fcf4b19794f Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 21:21:16 -0500 Subject: [PATCH 21/37] Add verbosity to open ssl command --- .github/workflows/acme-certbot-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 89af8425282..2838e729b4e 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -361,7 +361,8 @@ jobs: -keyout ES256.key \ -sha256 \ -subj '/CN=es256.example.com' \ - -nodes + -nodes \ + -verbose - name: Enroll using ES256 CSR run: | From d74ce1d797485518f37cff93770cc8b78ac7910d Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 21:24:01 -0500 Subject: [PATCH 22/37] Replace -nodes for -noenc --- .github/workflows/acme-certbot-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 2838e729b4e..37a1c118e4f 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -361,7 +361,7 @@ jobs: -keyout ES256.key \ -sha256 \ -subj '/CN=es256.example.com' \ - -nodes \ + -noenc \ -verbose - name: Enroll using ES256 CSR From 6d745734906b8f6bcb0fc7f420e4fc61f48d58c2 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 21:35:24 -0500 Subject: [PATCH 23/37] Insert pipe character at the start of command --- .github/workflows/acme-certbot-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 37a1c118e4f..cb966870e66 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -353,7 +353,8 @@ jobs: diff expected actual - name: Create CSR for ES256 Test - run: docker exec client openssl req \ + run: | + docker exec client openssl req \ -outform PEM \ -out ES256.csr \ -newkey ec \ From 7170ccd7d8253e789b4f2405f87e36f5172c6cda Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 21:44:46 -0500 Subject: [PATCH 24/37] Update count checks --- .github/workflows/acme-certbot-test.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index cb966870e66..84b9174fad3 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -506,8 +506,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be two orders - echo "2" > expected + # there should be three orders + echo "3" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -522,8 +522,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be two authorizations - echo "2" > expected + # there should be three authorizations + echo "3" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -538,8 +538,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be two challenges - echo "2" > expected + # there should be three challenges + echo "3" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -563,8 +563,8 @@ jobs: run: | docker exec pki pki ca-cert-find | tee output - # there should be 8 certs - echo "8" > expected + # there should be 9 certs + echo "9" > expected grep "Serial Number:" output | wc -l > actual diff expected actual @@ -588,8 +588,8 @@ jobs: run: | docker exec pki pki ca-cert-find | tee output - # there should be 8 certs - echo "8" > expected + # there should be 9 certs + echo "9" > expected grep "Serial Number:" output | wc -l > actual diff expected actual From 69a3a4b13eda198d8e714d487b405ed002df7a67 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 21:57:11 -0500 Subject: [PATCH 25/37] Move algorithm tests to its own file --- .github/workflows/acme-algorithm-test.yml | 381 ++++++++++++++++++++++ .github/workflows/acme-certbot-test.yml | 119 ------- .github/workflows/acme-tests.yml | 5 + 3 files changed, 386 insertions(+), 119 deletions(-) create mode 100644 .github/workflows/acme-algorithm-test.yml diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml new file mode 100644 index 00000000000..76a94cdd5e7 --- /dev/null +++ b/.github/workflows/acme-algorithm-test.yml @@ -0,0 +1,381 @@ +name: ACME with certbot + +on: workflow_call + +env: + DB_IMAGE: ${{ vars.DB_IMAGE || 'quay.io/389ds/dirsrv' }} + +jobs: + # docs/installation/acme/Installing_PKI_ACME_Responder.md + # docs/user/acme/Using_PKI_ACME_Responder_with_Certbot.md + test: + name: Test + runs-on: ubuntu-latest + env: + SHARED: /tmp/workdir/pki + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - name: Retrieve ACME images + uses: actions/cache@v4 + with: + key: acme-images-${{ github.sha }} + path: acme-images.tar + + - name: Load ACME images + run: docker load --input acme-images.tar + + - name: Create network + run: docker network create example + + - name: Set up DS container + run: | + tests/bin/ds-container-create.sh ds + env: + IMAGE: ${{ env.DB_IMAGE }} + HOSTNAME: ds.example.com + PASSWORD: Secret.123 + + - 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 + + - name: Install CA in PKI container + 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 \ + -v + + - name: Install CA admin cert + run: | + docker exec pki pki-server cert-export ca_signing --cert-file ca_signing.crt + docker exec pki pki client-cert-import ca_signing --ca-cert ca_signing.crt + docker exec pki pki pkcs12-import \ + --pkcs12 /root/.dogtag/pki-tomcat/ca_admin_cert.p12 \ + --pkcs12-password Secret.123 + docker exec pki pki -n caadmin ca-user-show caadmin + + - name: Check initial CA certs + run: | + docker exec pki pki ca-cert-find | tee output + + # there should be 6 certs + echo "6" > expected + grep "Serial Number:" output | wc -l > actual + diff expected actual + + - name: Set up ACME database in DS container + run: | + docker exec ds ldapmodify \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -f $SHARED/base/acme/database/ds/schema.ldif + docker exec ds ldapadd \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -f $SHARED/base/acme/database/ds/create.ldif + docker exec ds ldapadd \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -f $SHARED/base/acme/realm/ds/create.ldif + + - name: Install ACME in PKI container + run: | + docker exec pki pki-server acme-create + docker exec pki pki-server acme-database-mod \ + --type ds \ + -D url=ldap://ds.example.com:3389 + docker exec pki pki-server acme-issuer-mod --type pki + docker exec pki pki-server acme-realm-mod \ + --type ds \ + -D url=ldap://ds.example.com:3389 + docker exec pki pki-server acme-deploy --wait + + - name: Check initial ACME accounts + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=accounts,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no accounts + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check initial ACME orders + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=orders,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no orders + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check initial ACME authorizations + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=authorizations,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no authorizations + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check initial ACME challenges + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=challenges,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no challenges + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check initial ACME certs + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificates,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no certs + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check CA certs after ACME installation + run: | + docker exec pki pki ca-cert-find | tee output + + # there should be 6 certs + echo "6" > expected + grep "Serial Number:" output | wc -l > actual + diff expected actual + + - name: Run PKI healthcheck in PKI container + run: docker exec pki pki-healthcheck --failures-only + + - name: Verify ACME in PKI container + run: docker exec pki pki acme-info + + - name: Set up client container + run: | + tests/bin/runner-init.sh client + env: + HOSTNAME: client.example.com + + - name: Connect client container to network + run: docker network connect example client --alias client.example.com + + - name: Install certbot in client container + run: docker exec client dnf install -y certbot + + - name: Register ACME account + run: | + docker exec client certbot register \ + --server http://pki.example.com:8080/acme/directory \ + --email testuser@example.com \ + --agree-tos \ + --non-interactive + + - name: Check ACME accounts after registration + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=accounts,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be one account + echo "1" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + # status should be valid + echo "valid" > expected + sed -n 's/^acmeStatus: *\(.*\)$/\1/p' output > actual + diff expected actual + + # email should be testuser@example.com + echo "mailto:testuser@example.com" > expected + sed -n 's/^acmeAccountContact: *\(.*\)$/\1/p' output > actual + diff expected actual + + - name: Create CSR for ES256 Test + run: | + docker exec client openssl req \ + -outform PEM \ + -out ES256.csr \ + -newkey ec \ + -pkeyopt ec_paramgen_curve:P-256 \ + -keyout ES256.key \ + -sha256 \ + -subj '/CN=es256.example.com' \ + -noenc \ + -verbose + + - name: Enroll using ES256 CSR + run: | + docker exec client certbot certonly \ + --server http://pki.example.com:8080/acme/directory \ + --key-path ES256.key \ + --csr ES256.csr \ + --standalone \ + --non-interactive + + - name: Check ES256 client locally + run: | + docker exec client pki client-cert-import \ + --cert /etc/letsencrypt/live/es256.example.com/fullchain.pem \ + es256 + + # store serial number + docker exec client pki nss-cert-show es256 | tee output + sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > es256.txt + + # subject should be CN=es256.example.com + echo "CN=es256.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + + - name: Check ACME orders after ES256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=orders,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be two orders + echo "2" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check ACME authorizations after ES256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=authorizations,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be two authorizations + echo "2" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check ACME challenges after ES256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=challenges,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be two challenges + echo "2" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check ACME certs after ES256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=certificates,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be no certs (they are stored in CA) + echo "0" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check CA certs after ES256 enrollment + run: | + docker exec pki pki ca-cert-find | tee output + + # there should be 8 certs + echo "8" > expected + grep "Serial Number:" output | wc -l > actual + diff expected actual + + # check client cert + SERIAL=$(cat es256.txt) + docker exec pki pki ca-cert-show $SERIAL | tee output + + # subject should be CN=es256.example.com + echo "CN=es256.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + + - name: Upload artifacts from server containers + if: always() + uses: actions/upload-artifact@v4 + with: + name: acme-certbot-server + path: | + /tmp/artifacts/pki + + - name: Upload artifacts from client container + if: always() + uses: actions/upload-artifact@v4 + with: + name: acme-certbot-client + path: /tmp/artifacts/client diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 84b9174fad3..68917d929e1 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -352,125 +352,6 @@ jobs: sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual - - name: Create CSR for ES256 Test - run: | - docker exec client openssl req \ - -outform PEM \ - -out ES256.csr \ - -newkey ec \ - -pkeyopt ec_paramgen_curve:P-256 \ - -keyout ES256.key \ - -sha256 \ - -subj '/CN=es256.example.com' \ - -noenc \ - -verbose - - - name: Enroll using ES256 CSR - run: | - docker exec client certbot certonly \ - --server http://pki.example.com:8080/acme/directory \ - --key-path ES256.key \ - --csr ES256.csr \ - --standalone \ - --non-interactive - - - name: Check ES256 client locally - run: | - docker exec client pki client-cert-import \ - --cert /etc/letsencrypt/live/es256.example.com/fullchain.pem \ - es256 - - # store serial number - docker exec client pki nss-cert-show es256 | tee output - sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > es256.txt - - # subject should be CN=es256.example.com - echo "CN=es256.example.com" > expected - sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual - diff expected actual - - - name: Check ACME orders after ES256 enrollment - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=orders,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be two orders - echo "2" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check ACME authorizations after ES256 enrollment - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=authorizations,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be two authorizations - echo "2" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check ACME challenges after ES256 enrollment - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=challenges,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be two challenges - echo "2" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check ACME certs after ES256 enrollment - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=certificates,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no certs (they are stored in CA) - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check CA certs after ES256 enrollment - run: | - docker exec pki pki ca-cert-find | tee output - - # there should be 8 certs - echo "8" > expected - grep "Serial Number:" output | wc -l > actual - diff expected actual - - # check client cert - SERIAL=$(cat es256.txt) - docker exec pki pki ca-cert-show $SERIAL | tee output - - # subject should be CN=es256.example.com - echo "CN=es256.example.com" > expected - sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual - diff expected actual - - name: Renew client cert run: | docker exec client certbot renew \ diff --git a/.github/workflows/acme-tests.yml b/.github/workflows/acme-tests.yml index 824576cee0c..632c946f86e 100644 --- a/.github/workflows/acme-tests.yml +++ b/.github/workflows/acme-tests.yml @@ -112,6 +112,11 @@ jobs: needs: build uses: ./.github/workflows/acme-postgresql-test.yml + acme-algorithm-test: + name: ACME CSRs with different signatures + needs: build + uses: ./.github/workflows/acme-algorithm-test.yml + publish: if: github.event_name == 'push' && github.ref_name == 'master' name: Publishing ACME images From 2b83e791f190418192c73c54132d369143f90ead Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 22:02:19 -0500 Subject: [PATCH 26/37] Return certbot test to its original form --- .github/workflows/acme-certbot-test.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/acme-certbot-test.yml b/.github/workflows/acme-certbot-test.yml index 68917d929e1..20a7b1de188 100644 --- a/.github/workflows/acme-certbot-test.yml +++ b/.github/workflows/acme-certbot-test.yml @@ -387,8 +387,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be three orders - echo "3" > expected + # there should be two orders + echo "2" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -403,8 +403,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be three authorizations - echo "3" > expected + # there should be two authorizations + echo "2" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -419,8 +419,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be three challenges - echo "3" > expected + # there should be two challenges + echo "2" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -444,8 +444,8 @@ jobs: run: | docker exec pki pki ca-cert-find | tee output - # there should be 9 certs - echo "9" > expected + # there should be 8 certs + echo "8" > expected grep "Serial Number:" output | wc -l > actual diff expected actual @@ -469,8 +469,8 @@ jobs: run: | docker exec pki pki ca-cert-find | tee output - # there should be 9 certs - echo "9" > expected + # there should be 8 certs + echo "8" > expected grep "Serial Number:" output | wc -l > actual diff expected actual From 6f70a80119393792c5b591aa8d0bf6e064c26a5f Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 22:09:20 -0500 Subject: [PATCH 27/37] Ensure post test counts are valid --- .github/workflows/acme-algorithm-test.yml | 36 +++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index 76a94cdd5e7..21aa050c1a9 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -246,18 +246,18 @@ jobs: sed -n 's/^acmeAccountContact: *\(.*\)$/\1/p' output > actual diff expected actual - - name: Create CSR for ES256 Test - run: | - docker exec client openssl req \ - -outform PEM \ - -out ES256.csr \ - -newkey ec \ - -pkeyopt ec_paramgen_curve:P-256 \ - -keyout ES256.key \ - -sha256 \ - -subj '/CN=es256.example.com' \ - -noenc \ - -verbose + - name: Create CSR for ES256 Test + run: | + docker exec client openssl req \ + -outform PEM \ + -out ES256.csr \ + -newkey ec \ + -pkeyopt ec_paramgen_curve:P-256 \ + -keyout ES256.key \ + -sha256 \ + -subj '/CN=es256.example.com' \ + -noenc \ + -verbose - name: Enroll using ES256 CSR run: | @@ -295,7 +295,7 @@ jobs: -LLL | tee output # there should be two orders - echo "2" > expected + echo "1" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -311,7 +311,7 @@ jobs: -LLL | tee output # there should be two authorizations - echo "2" > expected + echo "1" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -327,7 +327,7 @@ jobs: -LLL | tee output # there should be two challenges - echo "2" > expected + echo "1" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -347,12 +347,12 @@ jobs: grep "^dn:" output | wc -l > actual diff expected actual - - name: Check CA certs after ES256 enrollment + - name: Check CA certs after enrollments run: | docker exec pki pki ca-cert-find | tee output - # there should be 8 certs - echo "8" > expected + # there should be 7 certs + echo "7" > expected grep "Serial Number:" output | wc -l > actual diff expected actual From ad8910e25b01002bedcead9adb1696d6b1dad169 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Wed, 27 Mar 2024 22:15:01 -0500 Subject: [PATCH 28/37] Add TODO for HMAC algorithms --- .../common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index e124992fe61..6dc3dea86f6 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -10,6 +10,9 @@ public enum ACMEAlgorithm { // Dogtag's JSS has slightly different algorithm names // than what is in RFC 7518 + + // TODO: Implement HS256, HS384, HS512 once JSS provider + // implements those algorithms RS256("RS256", "SHA256withRSA"), RS384("RS384", "SHA384withRSA"), RS512("RS512", "SHA512withRSA"), From c36af7ddbf65a174133889c87422b87699a7e126 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 18:50:58 -0500 Subject: [PATCH 29/37] Remove duplicate tests --- .github/workflows/acme-algorithm-test.yml | 154 +--------------------- 1 file changed, 7 insertions(+), 147 deletions(-) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index 21aa050c1a9..b60513945b5 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -66,15 +66,6 @@ jobs: --pkcs12-password Secret.123 docker exec pki pki -n caadmin ca-user-show caadmin - - name: Check initial CA certs - run: | - docker exec pki pki ca-cert-find | tee output - - # there should be 6 certs - echo "6" > expected - grep "Serial Number:" output | wc -l > actual - diff expected actual - - name: Set up ACME database in DS container run: | docker exec ds ldapmodify \ @@ -105,95 +96,6 @@ jobs: -D url=ldap://ds.example.com:3389 docker exec pki pki-server acme-deploy --wait - - name: Check initial ACME accounts - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=accounts,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no accounts - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check initial ACME orders - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=orders,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no orders - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check initial ACME authorizations - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=authorizations,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no authorizations - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check initial ACME challenges - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=challenges,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no challenges - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check initial ACME certs - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=certificates,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no certs - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - - name: Check CA certs after ACME installation - run: | - docker exec pki pki ca-cert-find | tee output - - # there should be 6 certs - echo "6" > expected - grep "Serial Number:" output | wc -l > actual - diff expected actual - - name: Run PKI healthcheck in PKI container run: docker exec pki pki-healthcheck --failures-only @@ -220,32 +122,6 @@ jobs: --agree-tos \ --non-interactive - - name: Check ACME accounts after registration - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=accounts,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be one account - echo "1" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - # status should be valid - echo "valid" > expected - sed -n 's/^acmeStatus: *\(.*\)$/\1/p' output > actual - diff expected actual - - # email should be testuser@example.com - echo "mailto:testuser@example.com" > expected - sed -n 's/^acmeAccountContact: *\(.*\)$/\1/p' output > actual - diff expected actual - - name: Create CSR for ES256 Test run: | docker exec client openssl req \ @@ -255,7 +131,7 @@ jobs: -pkeyopt ec_paramgen_curve:P-256 \ -keyout ES256.key \ -sha256 \ - -subj '/CN=es256.example.com' \ + -subj '/CN=client.example.com' \ -noenc \ -verbose @@ -271,15 +147,15 @@ jobs: - name: Check ES256 client locally run: | docker exec client pki client-cert-import \ - --cert /etc/letsencrypt/live/es256.example.com/fullchain.pem \ + --cert /etc/letsencrypt/live/client.example.com/fullchain.pem \ es256 # store serial number docker exec client pki nss-cert-show es256 | tee output sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > es256.txt - # subject should be CN=es256.example.com - echo "CN=es256.example.com" > expected + # subject should be CN=client.example.com + echo "CN=client.example.com" > expected sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual @@ -326,27 +202,11 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be two challenges + # there should be one challenge echo "1" > expected grep "^dn:" output | wc -l > actual diff expected actual - - name: Check ACME certs after ES256 enrollment - run: | - docker exec ds ldapsearch \ - -H ldap://ds.example.com:3389 \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - -b ou=certificates,dc=acme,dc=pki,dc=example,dc=com \ - -s one \ - -o ldif_wrap=no \ - -LLL | tee output - - # there should be no certs (they are stored in CA) - echo "0" > expected - grep "^dn:" output | wc -l > actual - diff expected actual - - name: Check CA certs after enrollments run: | docker exec pki pki ca-cert-find | tee output @@ -360,8 +220,8 @@ jobs: SERIAL=$(cat es256.txt) docker exec pki pki ca-cert-show $SERIAL | tee output - # subject should be CN=es256.example.com - echo "CN=es256.example.com" > expected + # subject should be CN=client.example.com + echo "CN=client.example.com" > expected sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual From 2c3f163d584fc7e28d17f4316288c953bc41168a Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 19:07:48 -0500 Subject: [PATCH 30/37] Add verbose flag --- .github/workflows/acme-algorithm-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index b60513945b5..e258d77f175 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -143,6 +143,7 @@ jobs: --csr ES256.csr \ --standalone \ --non-interactive + --verbose - name: Check ES256 client locally run: | From 8a39298619cf820d1444464c891b9d2027746ac2 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 19:31:39 -0500 Subject: [PATCH 31/37] Configure cerbot to use correct signature algorithm --- .github/workflows/acme-algorithm-test.yml | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index e258d77f175..a3f1a7a0214 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -121,26 +121,13 @@ jobs: --email testuser@example.com \ --agree-tos \ --non-interactive - - - name: Create CSR for ES256 Test - run: | - docker exec client openssl req \ - -outform PEM \ - -out ES256.csr \ - -newkey ec \ - -pkeyopt ec_paramgen_curve:P-256 \ - -keyout ES256.key \ - -sha256 \ - -subj '/CN=client.example.com' \ - -noenc \ - -verbose - name: Enroll using ES256 CSR run: | docker exec client certbot certonly \ --server http://pki.example.com:8080/acme/directory \ - --key-path ES256.key \ - --csr ES256.csr \ + --key-type ecdsa \ + --elliptic-curve secp256r1 \ --standalone \ --non-interactive --verbose From c686329a6b3f51883ac88a31d91ce39ee22f6863 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 19:51:13 -0500 Subject: [PATCH 32/37] Set domain for certbot --- .github/workflows/acme-algorithm-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index a3f1a7a0214..8d2e967ea2a 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -128,6 +128,7 @@ jobs: --server http://pki.example.com:8080/acme/directory \ --key-type ecdsa \ --elliptic-curve secp256r1 \ + --domain client.example.com \ --standalone \ --non-interactive --verbose From a5d7ce9a74bc0889d0354975fcc12c2df4fc08dd Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 20:04:49 -0500 Subject: [PATCH 33/37] Add line separator --- .github/workflows/acme-algorithm-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index 8d2e967ea2a..32251be3817 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -130,7 +130,7 @@ jobs: --elliptic-curve secp256r1 \ --domain client.example.com \ --standalone \ - --non-interactive + --non-interactive \ --verbose - name: Check ES256 client locally From 248266e518a1407955c1fd547e03fa97ae9a9e22 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 22:34:26 -0500 Subject: [PATCH 34/37] Add RS256 --- .github/workflows/acme-algorithm-test.yml | 121 ++++++++++++++++++---- 1 file changed, 99 insertions(+), 22 deletions(-) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index 32251be3817..ae9654d08b9 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -121,7 +121,99 @@ jobs: --email testuser@example.com \ --agree-tos \ --non-interactive - + + - name: Enroll using RS256 CSR + run: | + docker exec client certbot certonly \ + --server http://pki.example.com:8080/acme/directory \ + --key-type rsa \ + --rsa-key-size 2048 \ + --domain client.example.com \ + --standalone \ + --non-interactive \ + --verbose + + - name: Check RS256 client locally + run: | + docker exec client pki client-cert-import \ + --cert /etc/letsencrypt/live/client.example.com/fullchain.pem \ + rs256 + + # store serial number + docker exec client pki nss-cert-show rs256 | tee output + sed -n 's/^ *Serial Number: *\(.*\)/\1/p' output > rs256.txt + + # subject should be CN=client.example.com + echo "CN=client.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + + - name: Check ACME orders after RS256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=orders,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be one order + echo "1" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check ACME authorizations after RS256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=authorizations,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be one authorization + echo "1" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check ACME challenges after RS256 enrollment + run: | + docker exec ds ldapsearch \ + -H ldap://ds.example.com:3389 \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b ou=challenges,dc=acme,dc=pki,dc=example,dc=com \ + -s one \ + -o ldif_wrap=no \ + -LLL | tee output + + # there should be one challenge + echo "1" > expected + grep "^dn:" output | wc -l > actual + diff expected actual + + - name: Check CA certs after RS256 enrollments + run: | + docker exec pki pki ca-cert-find | tee output + + # there should be 7 certs + echo "7" > expected + grep "Serial Number:" output | wc -l > actual + diff expected actual + + # check client cert + SERIAL=$(cat rs256.txt) + docker exec pki pki ca-cert-show $SERIAL | tee output + + # subject should be CN=client.example.com + echo "CN=client.example.com" > expected + sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual + diff expected actual + - name: Enroll using ES256 CSR run: | docker exec client certbot certonly \ @@ -160,7 +252,7 @@ jobs: -LLL | tee output # there should be two orders - echo "1" > expected + echo "2" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -176,7 +268,7 @@ jobs: -LLL | tee output # there should be two authorizations - echo "1" > expected + echo "2" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -191,8 +283,8 @@ jobs: -o ldif_wrap=no \ -LLL | tee output - # there should be one challenge - echo "1" > expected + # there should be two challenges + echo "2" > expected grep "^dn:" output | wc -l > actual diff expected actual @@ -200,8 +292,8 @@ jobs: run: | docker exec pki pki ca-cert-find | tee output - # there should be 7 certs - echo "7" > expected + # there should be 8 certs + echo "8" > expected grep "Serial Number:" output | wc -l > actual diff expected actual @@ -213,18 +305,3 @@ jobs: echo "CN=client.example.com" > expected sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual - - - name: Upload artifacts from server containers - if: always() - uses: actions/upload-artifact@v4 - with: - name: acme-certbot-server - path: | - /tmp/artifacts/pki - - - name: Upload artifacts from client container - if: always() - uses: actions/upload-artifact@v4 - with: - name: acme-certbot-client - path: /tmp/artifacts/client From 01931d7dcc6872a71267dc54b461cc5003931b84 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Thu, 28 Mar 2024 22:50:35 -0500 Subject: [PATCH 35/37] Add a revocation step --- .github/workflows/acme-algorithm-test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index ae9654d08b9..1fa94a41b44 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -214,6 +214,13 @@ jobs: sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual + - name: Revoke RS256 client cert + run: | + docker exec client certbot revoke \ + --server http://pki.example.com:8080/acme/directory \ + --cert-name client.example.com \ + --non-interactive + - name: Enroll using ES256 CSR run: | docker exec client certbot certonly \ From 63e3184b5d5db37d4ddc2e7b74e874bd898777e9 Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Fri, 29 Mar 2024 00:53:06 -0500 Subject: [PATCH 36/37] Create duplicate cert --- .github/workflows/acme-algorithm-test.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/acme-algorithm-test.yml b/.github/workflows/acme-algorithm-test.yml index 1fa94a41b44..b4f7413b2df 100644 --- a/.github/workflows/acme-algorithm-test.yml +++ b/.github/workflows/acme-algorithm-test.yml @@ -214,22 +214,16 @@ jobs: sed -n 's/^ *Subject DN: *\(.*\)/\1/p' output > actual diff expected actual - - name: Revoke RS256 client cert - run: | - docker exec client certbot revoke \ - --server http://pki.example.com:8080/acme/directory \ - --cert-name client.example.com \ - --non-interactive - - name: Enroll using ES256 CSR run: | docker exec client certbot certonly \ --server http://pki.example.com:8080/acme/directory \ + --domain client.example.com \ --key-type ecdsa \ --elliptic-curve secp256r1 \ - --domain client.example.com \ --standalone \ --non-interactive \ + --duplicate \ --verbose - name: Check ES256 client locally From 57552c439c675727733faba3107eb943073cd79d Mon Sep 17 00:00:00 2001 From: Minsu Park Date: Fri, 29 Mar 2024 19:38:10 -0500 Subject: [PATCH 37/37] Use standard RFC naming --- .../src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java index 6dc3dea86f6..b0304701f0e 100644 --- a/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java +++ b/base/common/src/main/java/org/dogtagpki/acme/ACMEAlgorithm.java @@ -8,17 +8,14 @@ public enum ACMEAlgorithm { // RFC 7518 Appendix A.1 // Digital Signature/MAC Algorithm Identifier Cross-Reference - // Dogtag's JSS has slightly different algorithm names - // than what is in RFC 7518 - // TODO: Implement HS256, HS384, HS512 once JSS provider // implements those algorithms RS256("RS256", "SHA256withRSA"), RS384("RS384", "SHA384withRSA"), RS512("RS512", "SHA512withRSA"), - ES256("ES256", "SHA256withEC"), - ES384("ES384", "SHA384withEC"), - ES512("ES512", "SHA512withEC"), + ES256("ES256", "SHA256withECDSA"), + ES384("ES384", "SHA384withECDSA"), + ES512("ES512", "SHA512withECDSA"), PS256("PS256", "SHA256withRSA/PSS"), PS384("PS384", "SHA384withRSA/PSS"), PS512("PS512", "SHA512withRSA/PSS");