diff --git a/.github/workflows/build-standalone.yml b/.github/workflows/build-standalone.yml index d01c711..59ea560 100644 --- a/.github/workflows/build-standalone.yml +++ b/.github/workflows/build-standalone.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: GO_VERSION: - - 1.25.2 + - 1.25.5 steps: - name: Checkout diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 979d9cf..1e0efb0 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: GO_VERSION: - - 1.25.2 + - 1.25.5 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2b7d52b..7fcb9bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: GO_VERSION: - - 1.25.2 + - 1.25.5 steps: - name: Checkout diff --git a/build/Dockerfile-boulder b/build/Dockerfile-boulder index feb604d..72374af 100644 --- a/build/Dockerfile-boulder +++ b/build/Dockerfile-boulder @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM letsencrypt/boulder-tools:go1.25.2_2025-10-07 AS boulder-tools +FROM letsencrypt/boulder-tools:go1.25.5_2025-12-03 AS boulder-tools FROM ubuntu:noble diff --git a/build/Dockerfile-control b/build/Dockerfile-control index 19ba89b..ad6ecd1 100644 --- a/build/Dockerfile-control +++ b/build/Dockerfile-control @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM letsencrypt/boulder-tools:go1.25.2_2025-10-07 AS boulder-tools +FROM letsencrypt/boulder-tools:go1.25.5_2025-12-03 AS boulder-tools FROM ubuntu:noble AS builder diff --git a/build/build.sh b/build/build.sh index 3623bd5..cd18d9f 100755 --- a/build/build.sh +++ b/build/build.sh @@ -8,7 +8,7 @@ TMP_DIR=$(pwd)/tmp rm -rf $TMP_DIR && mkdir -p $TMP_DIR/{admin,bin,logs,src} boulderDir=$TMP_DIR/src -boulderTag="v0.20251110.0" +boulderTag="v0.20251216.0" boulderUrl="https://github.com/letsencrypt/boulder/" cloneDir=$(pwd)/.. diff --git a/build/docker-compose.yml b/build/docker-compose.yml index a09f3b0..d908a62 100644 --- a/build/docker-compose.yml +++ b/build/docker-compose.yml @@ -9,7 +9,7 @@ services: context: test/boulder-tools/ # Should match one of the GO_CI_VERSIONS in test/boulder-tools/tag_and_upload.sh. args: - GO_VERSION: 1.25.2 + GO_VERSION: 1.25.5 environment: # To solve HTTP-01 and TLS-ALPN-01 challenges, change the IP in FAKE_DNS # to the IP address where your ACME client's solver is listening. This is @@ -148,7 +148,6 @@ services: nginx: image: nginx:latest - restart: always networks: - bouldernet ports: @@ -160,6 +159,7 @@ services: - nginx_html:/var/www/html depends_on: - control + restart: always control: image: ghcr.io/hakwerk/labca-control:${LABCA_IMAGE_VERSION:-latest} diff --git a/build/tmp.patch b/build/tmp.patch index dc1d826..92fd3a3 100644 --- a/build/tmp.patch +++ b/build/tmp.patch @@ -1,5 +1,5 @@ diff --git a/docker-compose.yml b/docker-compose.yml -index c0c7fc838..fd9a67f35 100644 +index b3d31f8fb..b720d5921 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: @@ -106,7 +106,7 @@ index c0c7fc838..fd9a67f35 100644 logging: driver: "json-file" options: -@@ -144,30 +155,28 @@ services: +@@ -143,31 +154,29 @@ services: - 80:80 - 443:443 volumes: @@ -118,6 +118,7 @@ index c0c7fc838..fd9a67f35 100644 + - nginx_html:/var/www/html depends_on: - control + restart: always control: - image: *boulder_tools_image diff --git a/gui/acme.go b/gui/acme.go index 0375fa4..2c5f682 100644 --- a/gui/acme.go +++ b/gui/acme.go @@ -1200,11 +1200,11 @@ func GetCertificates(w http.ResponseWriter, r *http.Request, forAccount string) } else { where := "" if r.URL.Query().Get("active") != "" { - where = " WHERE cs.revokedDate='0000-00-00 00:00:00' AND cs.notAfter >= NOW()" + where = " WHERE (cs.revokedDate='0000-00-00 00:00:00' OR cs.revokedDate='2000-01-01 00:00:00') AND cs.notAfter >= NOW()" } else if r.URL.Query().Get("expired") != "" { where = " WHERE cs.notAfter < NOW()" } else if r.URL.Query().Get("revoked") != "" { - where = " WHERE cs.revokedDate<>'0000-00-00 00:00:00'" + where = " WHERE cs.revokedDate<>'0000-00-00 00:00:00' AND cs.revokedDate<>'2000-01-01 00:00:00'" } if forAccount == "" { @@ -1269,7 +1269,7 @@ func getReasonText(RevokedReason int, Revoked string) string { reasonText := "" switch RevokedReason { case 0: - if Revoked != "0000-00-00 00:00:00" { + if Revoked != "0000-00-00 00:00:00" && Revoked != "2000-01-01 00:00:00" { reasonText = " - Unspecified" } case 1: @@ -1487,7 +1487,7 @@ func GetCertificate(w http.ResponseWriter, r *http.Request, id string, serial st Link := NameValue{"Account", template.HTML("" + strconv.Itoa(certificate.RegistrationID) + "")} CertificateDetails.Rows = append(CertificateDetails.Rows, Link) - if certificate.Revoked == "0000-00-00 00:00:00" { + if certificate.Revoked == "0000-00-00 00:00:00" || certificate.Revoked == "2000-01-01 00:00:00" { revokeHTML, err := tmpls.RenderSingle("views/revoke-partial.tmpl", struct{ Serial string }{Serial: certificate.Serial}) if err != nil { errorHandler(w, r, err, http.StatusInternalServerError) diff --git a/gui/apply-boulder b/gui/apply-boulder index 8ca8ea4..9925146 100755 --- a/gui/apply-boulder +++ b/gui/apply-boulder @@ -126,9 +126,9 @@ if [ "$PKI_DOMAIN_MODE" == "lockdown" ] || [ "$PKI_DOMAIN_MODE" == "whitelist" ] cat rate-limit-policies.yml | tr '\n' '\r' | sed -e "s/\(must-staple.le.wtf: 10000\).*\( registrationOverrides:\)/\1\n$REPLACEMENT\2/" | tr '\r' '\n' > rate-limit-policies.yml.bak && mv rate-limit-policies.yml.bak rate-limit-policies.yml cat rate-limit-policies.yml | tr '\n' '\r' | sed -e "s|\(certificatesPerFQDNSet:.*must-staple.le.wtf: 10000\).*\(certificatesPerFQDNSetFast:.*\)|\1\n${REPLACEMENT}rateLimitsURL: http://$PKI_FQDN/rate-limits\n\2|" | tr '\r' '\n' > rate-limit-policies.yml.bak && mv rate-limit-policies.yml.bak rate-limit-policies.yml - cat config/wfe2-ratelimit-overrides.yml | tr '\n' '\r' | sed -e "s/\(- CertificatesPerDomain:.*ratelimit.me.*\)\(- CertificatesPerDomain:\)/\2/" | tr '\r' '\n' > config/wfe2-ratelimit-overrides.yml.bak && mv config/wfe2-ratelimit-overrides.yml.bak config/wfe2-ratelimit-overrides.yml - cat config/wfe2-ratelimit-overrides.yml | tr '\n' '\r' | sed -e "s/\(- CertificatesPerDomain:.*ids:\)\(.*\)\(- CertificatesPerFQDNSet:\)/\1\r$REPLACEMENT2\3/" | tr '\r' '\n' > config/wfe2-ratelimit-overrides.yml.bak && mv config/wfe2-ratelimit-overrides.yml.bak config/wfe2-ratelimit-overrides.yml - cat config/wfe2-ratelimit-overrides.yml | tr '\n' '\r' | sed -e "s/\(- CertificatesPerFQDNSet:.*ids:\)\(.*\)/\1\r$REPLACEMENT2/" | tr '\r' '\n' > config/wfe2-ratelimit-overrides.yml.bak && mv config/wfe2-ratelimit-overrides.yml.bak config/wfe2-ratelimit-overrides.yml + cat config/ratelimit-overrides.yml | tr '\n' '\r' | sed -e "s/\(- CertificatesPerDomain:.*ratelimit.me.*\)\(- CertificatesPerDomain:\)/\2/" | tr '\r' '\n' > config/ratelimit-overrides.yml.bak && mv config/ratelimit-overrides.yml.bak config/ratelimit-overrides.yml + cat config/ratelimit-overrides.yml | tr '\n' '\r' | sed -e "s/\(- CertificatesPerDomain:.*ids:\)\(.*\)\(- CertificatesPerFQDNSet:\)/\1\r$REPLACEMENT2\3/" | tr '\r' '\n' > config/ratelimit-overrides.yml.bak && mv config/ratelimit-overrides.yml.bak config/ratelimit-overrides.yml + cat config/ratelimit-overrides.yml | tr '\n' '\r' | sed -e "s/\(- CertificatesPerFQDNSet:.*ids:\)\(.*\)/\1\r$REPLACEMENT2/" | tr '\r' '\n' > config/ratelimit-overrides.yml.bak && mv config/ratelimit-overrides.yml.bak config/ratelimit-overrides.yml perl -i -p0e "s/(\"labcaDomains\": \[\n).*?(\])/\1$LABCA_DOMAINS\n\t\t\2/igs" config/remoteva-a.json perl -i -p0e "s/(\"labcaDomains\": \[\n).*?(\])/\1$LABCA_DOMAINS\n\t\t\2/igs" config/remoteva-b.json diff --git a/gui/dashboard.go b/gui/dashboard.go index 4528b01..91b5586 100644 --- a/gui/dashboard.go +++ b/gui/dashboard.go @@ -682,7 +682,7 @@ func CollectDashboardData(w http.ResponseWriter, r *http.Request) (map[string]in dashboardData["NumCerts"] = numcerts dashboardData["NumExpired"] = numexpired } else { - rows, err = db.Query("SELECT count(*) FROM certificateStatus WHERE revokedDate='0000-00-00 00:00:00' AND notAfter >= NOW()") + rows, err = db.Query("SELECT count(*) FROM certificateStatus WHERE (revokedDate='0000-00-00 00:00:00' OR revokedDate='2000-01-01 00:00:00') AND notAfter >= NOW()") if err != nil { errorHandler(w, r, err, http.StatusInternalServerError) return nil, err @@ -718,7 +718,7 @@ func CollectDashboardData(w http.ResponseWriter, r *http.Request) (map[string]in if viper.GetString("backend") == "step-ca" { rows, err = db.Query("SELECT count(*) FROM revoked_x509_certs") } else { - rows, err = db.Query("SELECT count(*) FROM certificateStatus WHERE revokedDate<>'0000-00-00 00:00:00'") + rows, err = db.Query("SELECT count(*) FROM certificateStatus WHERE revokedDate<>'0000-00-00 00:00:00' AND revokedDate<>'2000-01-01 00:00:00'") } if err != nil { errorHandler(w, r, err, http.StatusInternalServerError) diff --git a/install b/install index b59dc7d..6107f28 100755 --- a/install +++ b/install @@ -30,7 +30,7 @@ dockerComposeVersion="v2.5.0" labcaUrl="https://github.com/hakwerk/labca/" boulderUrl="https://github.com/letsencrypt/boulder/" -boulderTag="v0.20251110.0" +boulderTag="v0.20251216.0" # # Color configuration @@ -716,6 +716,8 @@ cleanup() { rm -f $adminDir/templates/register.tmpl rm -f $adminDir/templates/setup.tmpl rm -f $adminDir/templates/wrapup.tmpl + rm -f $boulderLabCADir/akamai-test-srv/main.go + rm -f $boulderLabCADir/block-a-key/main.go # Remove host nginx if installed, as we are now using the docker container systemctl stop nginx &>>$installLog || true diff --git a/patch-cfg.sh b/patch-cfg.sh index f7c29a9..877ed50 100755 --- a/patch-cfg.sh +++ b/patch-cfg.sh @@ -34,7 +34,7 @@ perl -i -p0e "s/(\"accountURIPrefixes\": \[\n.*?\s+\])/\1,\n\t\t\"labcaDomains\" perl -i -p0e "s/(\"accountURIPrefixes\": \[\n.*?\s+\])/\1,\n\t\t\"labcaDomains\": [\n\t\t]/igs" $boulderLabCADir/config/remoteva-c.json perl -i -p0e "s/(\"accountURIPrefixes\": \[\n.*?\s+\])/\1,\n\t\t\"labcaDomains\": [\n\t\t]/igs" $boulderLabCADir/config/va.json -for f in $(grep -l boulder-proxysql $boulderLabCADir/secrets/*); do sed -i -e "s/proxysql:6033/mysql:3306/" $f; done +for f in $(grep -Rl boulder-proxysql $boulderLabCADir/secrets/); do sed -i -e "s/proxysql:6033/mysql:3306/" $f; done cd "$boulderLabCADir" sed -i -e "s|test/certs/webpki/int-rsa-a.cert.pem|labca/certs/webpki/issuer-01-cert.pem|" config/publisher.json @@ -50,6 +50,10 @@ sed -i -e "s|test/certs/webpki/root-rsa.cert.pem|labca/certs/webpki/root-01-cert sed -i -e "s|test/certs/webpki/root-rsa.cert.pem|labca/certs/webpki/root-01-cert.pem|" config/publisher.json sed -i -e "s|test/certs/webpki/root-rsa.cert.pem|labca/certs/webpki/root-01-cert.pem|" config/wfe2.json sed -i -e "s|test/certs/webpki/root-rsa.cert.pem|labca/certs/webpki/root-01-cert.pem|" helpers.py +sed -i -e "s|test/secrets/\(.*_dburl\)|labca/secrets/dburls/proxysql/\1|" config/bad-key-revoker.json +sed -i -e "s|test/secrets/\(.*_dburl\)|labca/secrets/dburls/proxysql/\1|" config/cert-checker.json +sed -i -e "s|test/secrets/\(.*_dburl\)|labca/secrets/dburls/proxysql/\1|" config/sa.json +sed -i -e "s|test/secrets/\(.*_dburl\)|labca/secrets/dburls/proxysql/\1|" config/admin.json sed -i -e "s|letsencrypt/boulder|hakwerk/labca|" config/wfe2.json sed -i -e "s|1.2.3.4|1.3.6.1.4.1.44947.1.1.1|g" config/ca.json sed -i -e "s/\"dnsTimeout\": \".*\"/\"dnsTimeout\": \"3s\"/" config/remoteva-a.json diff --git a/patch.sh b/patch.sh index ce2e1fe..e995a66 100755 --- a/patch.sh +++ b/patch.sh @@ -69,7 +69,7 @@ $SUDO patch -p1 < $cloneDir/patches/wfe2_wfe.patch sed -i -e "s|./test|./labca|" start.py -sed -i -e "s/proxysql:6033/mysql:3306/" sa/db/dbconfig.yml +sed -i -e "s/proxysql:6033/mysql:3306/" sa/db/dbconfig.mariadb.yml sed -i -e "s/\(.*overrides.*\)/-- \1/" sa/db-users/boulder_sa.sql diff --git a/patches/bad-key-revoker_main.patch b/patches/bad-key-revoker_main.patch index 2589ba8..b82af3b 100644 --- a/patches/bad-key-revoker_main.patch +++ b/patches/bad-key-revoker_main.patch @@ -1,8 +1,8 @@ diff --git a/cmd/bad-key-revoker/main.go b/cmd/bad-key-revoker/main.go -index 34c58eae5..dd40b9469 100644 +index a58e82801..d3255c3c5 100644 --- a/cmd/bad-key-revoker/main.go +++ b/cmd/bad-key-revoker/main.go -@@ -275,6 +275,11 @@ type Config struct { +@@ -266,6 +266,11 @@ type Config struct { TLS cmd.TLSConfig RAService *cmd.GRPCClientConfig @@ -14,7 +14,7 @@ index 34c58eae5..dd40b9469 100644 // MaximumRevocations specifies the maximum number of certificates associated with // a key hash that bad-key-revoker will attempt to revoke. If the number of certificates // is higher than MaximumRevocations bad-key-revoker will error out and refuse to -@@ -301,6 +306,8 @@ type Config struct { +@@ -292,6 +297,8 @@ type Config struct { // the database's maximum replication lag, and always well under 24 // hours. MaxExpectedReplicationLag config.Duration `validate:"-"` diff --git a/patches/bdns_dns.patch b/patches/bdns_dns.patch index 9d2744c..c259679 100644 --- a/patches/bdns_dns.patch +++ b/patches/bdns_dns.patch @@ -1,46 +1,46 @@ diff --git a/bdns/dns.go b/bdns/dns.go -index 5fee207b8..f147da8e9 100644 +index ea91a5c43..b6f5c1eba 100644 --- a/bdns/dns.go +++ b/bdns/dns.go -@@ -20,6 +20,7 @@ import ( +@@ -17,6 +17,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/letsencrypt/boulder/features" - "github.com/letsencrypt/boulder/iana" blog "github.com/letsencrypt/boulder/log" "github.com/letsencrypt/boulder/metrics" -@@ -75,22 +76,30 @@ func New( + ) +@@ -89,21 +90,31 @@ func New( + log blog.Logger, + tlsConfig *tls.Config, ) Client { - var client exchanger - -- // Clone the default transport because it comes with various settings -- // that we like, which are different from the zero value of an -- // `http.Transport`. +- // Clone the default transport because it comes with various settings that we +- // like, which are different from the zero value of an `http.Transport`. Then +- // set it to force HTTP/2, because Unbound will reject non-HTTP/2 DoH +- // requests. - transport := http.DefaultTransport.(*http.Transport).Clone() - transport.TLSClientConfig = tlsConfig -- // The default transport already sets this field, but it isn't -- // documented that it will always be set. Set it again to be sure, -- // because Unbound will reject non-HTTP/2 DoH requests. - transport.ForceAttemptHTTP2 = true -- client = &dohExchanger{ +- +- exchanger := &dohExchanger{ - clk: clk, - hc: http.Client{ - Timeout: readTimeout, - Transport: transport, - }, - userAgent: userAgent, ++ var exchanger exchanger ++ + if features.Get().DOH { -+ // Clone the default transport because it comes with various settings -+ // that we like, which are different from the zero value of an -+ // `http.Transport`. ++ // Clone the default transport because it comes with various settings that we ++ // like, which are different from the zero value of an `http.Transport`. Then ++ // set it to force HTTP/2, because Unbound will reject non-HTTP/2 DoH ++ // requests. + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.TLSClientConfig = tlsConfig -+ // The default transport already sets this field, but it isn't -+ // documented that it will always be set. Set it again to be sure, -+ // because Unbound will reject non-HTTP/2 DoH requests. + transport.ForceAttemptHTTP2 = true -+ client = &dohExchanger{ ++ ++ exchanger = &dohExchanger{ + clk: clk, + hc: http.Client{ + Timeout: readTimeout, @@ -49,7 +49,7 @@ index 5fee207b8..f147da8e9 100644 + userAgent: userAgent, + } + } else { -+ client = &dns.Client{ ++ exchanger = &dns.Client{ + // Set timeout for underlying net.Conn + ReadTimeout: readTimeout, + Net: "udp", @@ -57,25 +57,20 @@ index 5fee207b8..f147da8e9 100644 } queryTime := promauto.With(stats).NewHistogramVec( -@@ -260,10 +269,17 @@ func (dnsClient *impl) exchangeOne(ctx context.Context, hostname string, qtype u - case r := <-ch: - if r.err != nil { - var isRetryable bool -- // Check if the error is a timeout error. Network errors -- // that can timeout implement the net.Error interface. -- var netErr net.Error -- isRetryable = errors.As(r.err, &netErr) && netErr.Timeout() -+ if features.Get().DOH { -+ // Check if the error is a timeout error. Network errors -+ // that can timeout implement the net.Error interface. -+ var netErr net.Error -+ isRetryable = errors.As(r.err, &netErr) && netErr.Timeout() -+ } else { -+ // According to the net package documentation, retryable -+ // errors emitted by the net package are of type *net.OpError. -+ var opErr *net.OpError -+ isRetryable = errors.As(r.err, &opErr) && opErr.Temporary() -+ } - hasRetriesLeft := tries < dnsClient.maxTries - if isRetryable && hasRetriesLeft { - tries++ +@@ -230,8 +241,14 @@ func (c *impl) exchangeOne(ctx context.Context, hostname string, qtype uint16) ( + + // Check if the error is a network timeout, rather than a local context + // timeout. If it is, retry instead of giving up. +- var netErr net.Error +- isRetryable := ctx.Err() == nil && errors.As(err, &netErr) && netErr.Timeout() ++ var isRetryable bool ++ if features.Get().DOH { ++ var netErr net.Error ++ isRetryable = ctx.Err() == nil && errors.As(err, &netErr) && netErr.Timeout() ++ } else { ++ var opErr *net.OpError ++ isRetryable = ctx.Err() == nil && errors.As(err, &opErr) && opErr.Temporary() ++ } + hasRetriesLeft := tries < c.maxTries + if isRetryable && hasRetriesLeft { + continue diff --git a/patches/boulder-va_main.patch b/patches/boulder-va_main.patch index 81d8bb7..5e354c9 100644 --- a/patches/boulder-va_main.patch +++ b/patches/boulder-va_main.patch @@ -1,5 +1,5 @@ diff --git a/cmd/boulder-va/main.go b/cmd/boulder-va/main.go -index fecf2ed7f..aa4d3320a 100644 +index ab196c2ff..b364a744f 100644 --- a/cmd/boulder-va/main.go +++ b/cmd/boulder-va/main.go @@ -58,6 +58,7 @@ type Config struct { @@ -28,11 +28,11 @@ index fecf2ed7f..aa4d3320a 100644 cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver") } defer servers.Stop() -@@ -154,6 +159,7 @@ func main() { +@@ -142,6 +147,7 @@ func main() { va.PrimaryPerspective, "", iana.IsReservedAddr, + c.VA.LabCADomains, c.VA.SlowRemoteTimeout.Duration, + c.VA.DNSAllowLoopbackAddresses, ) - cmd.FailOnError(err, "Unable to create VA server") diff --git a/patches/ca_ca.patch b/patches/ca_ca.patch index 2036482..4495612 100644 --- a/patches/ca_ca.patch +++ b/patches/ca_ca.patch @@ -1,8 +1,8 @@ diff --git a/ca/ca.go b/ca/ca.go -index a5890452f..3a62648c3 100644 +index a3c03088d..713a38eb9 100644 --- a/ca/ca.go +++ b/ca/ca.go -@@ -192,7 +192,7 @@ func NewCertificateAuthorityImpl( +@@ -184,7 +184,7 @@ func NewCertificateAuthorityImpl( for _, keyAlg := range []x509.PublicKeyAlgorithm{x509.ECDSA, x509.RSA} { if !issuableKeys[keyAlg] { diff --git a/patches/ca_ca_keytype_hack.patch b/patches/ca_ca_keytype_hack.patch index 5af49c8..c69fe8a 100644 --- a/patches/ca_ca_keytype_hack.patch +++ b/patches/ca_ca_keytype_hack.patch @@ -1,8 +1,8 @@ diff --git a/ca/ca.go b/ca/ca.go -index 3a62648c3..2cb8337ca 100644 +index 713a38eb9..cc066ad49 100644 --- a/ca/ca.go +++ b/ca/ca.go -@@ -190,11 +190,12 @@ func NewCertificateAuthorityImpl( +@@ -182,11 +182,12 @@ func NewCertificateAuthorityImpl( } } @@ -20,7 +20,7 @@ index 3a62648c3..2cb8337ca 100644 return &certificateAuthorityImpl{ sa: sa, -@@ -474,9 +475,10 @@ func (ca *certificateAuthorityImpl) pickIssuer(profileName string, keyAlg x509.P +@@ -466,9 +467,10 @@ func (ca *certificateAuthorityImpl) pickIssuer(profileName string, keyAlg x509.P if !issuer.IsActive() { continue } diff --git a/patches/ceremony_ecdsa.patch b/patches/ceremony_ecdsa.patch index e2d28c3..dc27319 100644 --- a/patches/ceremony_ecdsa.patch +++ b/patches/ceremony_ecdsa.patch @@ -1,8 +1,8 @@ diff --git a/cmd/ceremony/ecdsa.go b/cmd/ceremony/ecdsa.go -index 3adec7313..dc00269fd 100644 +index e6d870094..3204e91ef 100644 --- a/cmd/ceremony/ecdsa.go +++ b/cmd/ceremony/ecdsa.go -@@ -30,7 +30,7 @@ var curveToOIDDER = map[string][]byte{ +@@ -28,7 +28,7 @@ var curveToOIDDER = map[string][]byte{ // ecArgs constructs the private and public key template attributes sent to the // device and specifies which mechanism should be used. curve determines which // type of key should be generated. @@ -11,7 +11,7 @@ index 3adec7313..dc00269fd 100644 encodedCurve := curveToOIDDER[curve.Params().Name] log.Printf("\tEncoded curve parameters for %s: %X\n", curve.Params().Name, encodedCurve) return generateArgs{ -@@ -51,7 +51,7 @@ func ecArgs(label string, curve elliptic.Curve, keyID []byte) generateArgs { +@@ -49,7 +49,7 @@ func ecArgs(label string, curve elliptic.Curve, keyID []byte) generateArgs { // Prevent attributes being retrieved pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true), // Prevent the key being extracted from the device @@ -20,7 +20,7 @@ index 3adec7313..dc00269fd 100644 // Allow the key to sign data pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), }, -@@ -82,7 +82,7 @@ func ecPub( +@@ -80,7 +80,7 @@ func ecPub( // specified by curveStr and with the provided label. It returns the public // part of the generated key pair as a ecdsa.PublicKey and the random key ID // that the HSM uses to identify the key pair. @@ -29,7 +29,7 @@ index 3adec7313..dc00269fd 100644 curve, present := stringToCurve[curveStr] if !present { return nil, nil, fmt.Errorf("curve %q not supported", curveStr) -@@ -93,7 +93,7 @@ func ecGenerate(session *pkcs11helpers.Session, label, curveStr string) (*ecdsa. +@@ -91,7 +91,7 @@ func ecGenerate(session *pkcs11helpers.Session, label, curveStr string) (*ecdsa. return nil, nil, err } log.Printf("Generating ECDSA key with curve %s and ID %x\n", curveStr, keyID) diff --git a/patches/ceremony_main.patch b/patches/ceremony_main.patch index 841ab04..75fa4c8 100644 --- a/patches/ceremony_main.patch +++ b/patches/ceremony_main.patch @@ -1,5 +1,5 @@ diff --git a/cmd/ceremony/main.go b/cmd/ceremony/main.go -index c075c6615..9f51130b0 100644 +index 97c94eb1d..629a24a24 100644 --- a/cmd/ceremony/main.go +++ b/cmd/ceremony/main.go @@ -98,6 +98,7 @@ type keyGenConfig struct { @@ -10,7 +10,7 @@ index c075c6615..9f51130b0 100644 } var allowedCurves = map[string]bool{ -@@ -174,6 +175,7 @@ type rootConfig struct { +@@ -173,6 +174,7 @@ type rootConfig struct { } `yaml:"outputs"` CertProfile certProfile `yaml:"certificate-profile"` SkipLints []string `yaml:"skip-lints"` @@ -18,7 +18,7 @@ index c075c6615..9f51130b0 100644 } func (rc rootConfig) validate() error { -@@ -189,9 +191,11 @@ func (rc rootConfig) validate() error { +@@ -188,9 +190,11 @@ func (rc rootConfig) validate() error { } // Output fields @@ -33,7 +33,7 @@ index c075c6615..9f51130b0 100644 } err = checkOutputFile(rc.Outputs.CertificatePath, "certificate-path") if err != nil { -@@ -577,23 +581,42 @@ func rootCeremony(configBytes []byte) error { +@@ -576,23 +580,42 @@ func rootCeremony(configBytes []byte) error { return fmt.Errorf("failed to setup session and PKCS#11 context for slot %d: %s", config.PKCS11.StoreSlot, err) } log.Printf("Opened PKCS#11 session for slot %d\n", config.PKCS11.StoreSlot) diff --git a/patches/cert-checker_main.patch b/patches/cert-checker_main.patch index 70af171..c590a5b 100644 --- a/patches/cert-checker_main.patch +++ b/patches/cert-checker_main.patch @@ -1,8 +1,8 @@ diff --git a/cmd/cert-checker/main.go b/cmd/cert-checker/main.go -index a323e70b8..df64d3e94 100644 +index 5e8790d20..c7aa8a713 100644 --- a/cmd/cert-checker/main.go +++ b/cmd/cert-checker/main.go -@@ -109,6 +109,7 @@ type certChecker struct { +@@ -110,6 +110,7 @@ type certChecker struct { acceptableValidityDurations map[time.Duration]bool lints lint.Registry logger blog.Logger @@ -10,7 +10,7 @@ index a323e70b8..df64d3e94 100644 } func newChecker(saDbMap certDB, -@@ -119,6 +120,7 @@ func newChecker(saDbMap certDB, +@@ -120,6 +121,7 @@ func newChecker(saDbMap certDB, avd map[time.Duration]bool, lints lint.Registry, logger blog.Logger, @@ -18,7 +18,7 @@ index a323e70b8..df64d3e94 100644 ) certChecker { precertGetter := func(ctx context.Context, serial string) ([]byte, error) { precertPb, err := sa.SelectPrecertificate(ctx, saDbMap, serial) -@@ -140,6 +142,7 @@ func newChecker(saDbMap certDB, +@@ -141,6 +143,7 @@ func newChecker(saDbMap certDB, acceptableValidityDurations: avd, lints: lints, logger: logger, @@ -26,7 +26,7 @@ index a323e70b8..df64d3e94 100644 } } -@@ -437,14 +440,16 @@ func (c *certChecker) checkCert(ctx context.Context, cert *corepb.Certificate) ( +@@ -438,14 +441,16 @@ func (c *certChecker) checkCert(ctx context.Context, cert *corepb.Certificate) ( problems = append(problems, fmt.Sprintf("Policy Authority isn't willing to issue for '%s': %s", name, err)) continue } @@ -51,7 +51,7 @@ index a323e70b8..df64d3e94 100644 } } for _, name := range parsedCert.IPAddresses { -@@ -533,9 +538,10 @@ type Config struct { +@@ -534,9 +539,10 @@ type Config struct { Workers int `validate:"required,min=1"` // Deprecated: this is ignored, and cert checker always checks both expired and unexpired. @@ -65,7 +65,7 @@ index a323e70b8..df64d3e94 100644 // AcceptableValidityDurations is a list of durations which are // acceptable for certificates we issue. -@@ -593,6 +599,8 @@ func main() { +@@ -599,6 +605,8 @@ func main() { acceptableValidityDurations[ninetyDays] = true } @@ -74,7 +74,7 @@ index a323e70b8..df64d3e94 100644 // Validate PA config and set defaults if needed. cmd.FailOnError(config.PA.CheckChallenges(), "Invalid PA configuration") cmd.FailOnError(config.PA.CheckIdentifiers(), "Invalid PA configuration") -@@ -637,6 +645,7 @@ func main() { +@@ -642,6 +650,7 @@ func main() { acceptableValidityDurations, lints, logger, diff --git a/patches/config_ra.patch b/patches/config_ra.patch index 9d25885..a31ef11 100644 --- a/patches/config_ra.patch +++ b/patches/config_ra.patch @@ -1,13 +1,13 @@ diff --git a/test/config/ra.json b/test/config/ra.json -index b2dcd15eb..3e8d5af59 100644 +index c74e12e77..8343e3ddc 100644 --- a/test/config/ra.json +++ b/test/config/ra.json @@ -3,7 +3,8 @@ "limiter": { "redis": { - "username": "boulder-wfe", -- "passwordFile": "test/secrets/wfe_ratelimits_redis_password", -+ "passwordFile": "labca/secrets/wfe_ratelimits_redis_password", + "username": "boulder", +- "passwordFile": "test/secrets/redis_password", ++ "passwordFile": "labca/secrets/redis_password", + "db": 1, "lookups": [ { @@ -24,10 +24,10 @@ index b2dcd15eb..3e8d5af59 100644 + "keyFile": "labca/certs/ipki/wfe.boulder/key.pem" } }, -- "Defaults": "test/config/wfe2-ratelimit-defaults.yml", -- "Overrides": "test/config/wfe2-ratelimit-overrides.yml" -+ "Defaults": "labca/config/wfe2-ratelimit-defaults.yml", -+ "Overrides": "labca/config/wfe2-ratelimit-overrides.yml" +- "Defaults": "test/config/ratelimit-defaults.yml", +- "Overrides": "test/config/ratelimit-overrides.yml" ++ "Defaults": "labca/config/ratelimit-defaults.yml", ++ "Overrides": "labca/config/ratelimit-overrides.yml" }, "maxContactsPerRegistration": 3, "debugAddr": ":8002", diff --git a/patches/config_wfe2.patch b/patches/config_wfe2.patch index d3fe07b..021b315 100644 --- a/patches/config_wfe2.patch +++ b/patches/config_wfe2.patch @@ -1,5 +1,5 @@ diff --git a/test/config/wfe2.json b/test/config/wfe2.json -index 51c7aa8ef..1ed5d37af 100644 +index aede35e09..fe35e5176 100644 --- a/test/config/wfe2.json +++ b/test/config/wfe2.json @@ -3,8 +3,8 @@ @@ -70,9 +70,9 @@ index 51c7aa8ef..1ed5d37af 100644 "staleTimeout": "5m", "limiter": { "redis": { - "username": "boulder-wfe", -- "passwordFile": "test/secrets/wfe_ratelimits_redis_password", -+ "passwordFile": "labca/secrets/wfe_ratelimits_redis_password", + "username": "boulder", +- "passwordFile": "test/secrets/redis_password", ++ "passwordFile": "labca/secrets/redis_password", + "db": 1, "lookups": [ { @@ -89,10 +89,10 @@ index 51c7aa8ef..1ed5d37af 100644 + "keyFile": "labca/certs/ipki/wfe.boulder/key.pem" } }, -- "Defaults": "test/config/wfe2-ratelimit-defaults.yml", -- "Overrides": "test/config/wfe2-ratelimit-overrides.yml" -+ "Defaults": "labca/config/wfe2-ratelimit-defaults.yml", -+ "Overrides": "labca/config/wfe2-ratelimit-overrides.yml" +- "Defaults": "test/config/ratelimit-defaults.yml", +- "Overrides": "test/config/ratelimit-overrides.yml" ++ "Defaults": "labca/config/ratelimit-defaults.yml", ++ "Overrides": "labca/config/ratelimit-overrides.yml" }, "features": { "ServeRenewalInfo": true, diff --git a/patches/db_migrations.patch b/patches/db_migrations.patch index 730fe53..b0cc007 100644 --- a/patches/db_migrations.patch +++ b/patches/db_migrations.patch @@ -1,5 +1,5 @@ diff --git a/sa/db/boulder_sa/20230419000000_CombinedSchema.sql b/sa/db/boulder_sa/20230419000000_CombinedSchema.sql -index 42c489be9..d2b1eb43b 100644 +index c2fa91c9e..6674fc3d9 100644 --- a/sa/db/boulder_sa/20230419000000_CombinedSchema.sql +++ b/sa/db/boulder_sa/20230419000000_CombinedSchema.sql @@ -1,7 +1,9 @@ @@ -13,21 +13,16 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `identifierType` tinyint(4) NOT NULL, `identifierValue` varchar(255) NOT NULL, -@@ -18,11 +20,9 @@ CREATE TABLE `authz2` ( - KEY `regID_expires_idx` (`registrationID`,`status`,`expires`), - KEY `regID_identifier_status_expires_idx` (`registrationID`,`identifierType`,`identifierValue`,`status`,`expires`), +@@ -20,7 +22,7 @@ CREATE TABLE `authz2` ( KEY `expires_idx` (`expires`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `blockedKeys` ( +CREATE TABLE IF NOT EXISTS `blockedKeys` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `keyHash` binary(32) NOT NULL, `added` datetime NOT NULL, -@@ -35,7 +35,7 @@ CREATE TABLE `blockedKeys` ( +@@ -33,7 +35,7 @@ CREATE TABLE `blockedKeys` ( KEY `extantCertificatesChecked_idx` (`extantCertificatesChecked`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -36,35 +31,25 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) NOT NULL AUTO_INCREMENT, `serial` varchar(255) NOT NULL, `subscriberApproved` tinyint(1) DEFAULT 0, -@@ -53,11 +53,9 @@ CREATE TABLE `certificateStatus` ( - KEY `serial` (`serial`), - KEY `isExpired_ocspLastUpdated_idx` (`isExpired`,`ocspLastUpdated`), +@@ -53,7 +55,7 @@ CREATE TABLE `certificateStatus` ( KEY `notAfter_idx` (`notAfter`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `certificates` ( +CREATE TABLE IF NOT EXISTS `certificates` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `registrationID` bigint(20) NOT NULL, `serial` varchar(255) NOT NULL, -@@ -69,11 +67,9 @@ CREATE TABLE `certificates` ( - KEY `serial` (`serial`), - KEY `regId_certificates_idx` (`registrationID`) COMMENT 'Common lookup', +@@ -67,7 +69,7 @@ CREATE TABLE `certificates` ( KEY `issued_idx` (`issued`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `certificatesPerName` ( +CREATE TABLE IF NOT EXISTS `certificatesPerName` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `eTLDPlusOne` varchar(255) NOT NULL, `time` datetime NOT NULL, -@@ -82,7 +78,22 @@ CREATE TABLE `certificatesPerName` ( +@@ -76,7 +78,22 @@ CREATE TABLE `certificatesPerName` ( UNIQUE KEY `eTLDPlusOne_time_idx` (`eTLDPlusOne`,`time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -88,44 +73,34 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `setHash` binary(32) NOT NULL, `serial` varchar(255) NOT NULL, -@@ -93,11 +104,9 @@ CREATE TABLE `fqdnSets` ( - PRIMARY KEY (`id`), - KEY `serial` (`serial`), +@@ -89,7 +106,7 @@ CREATE TABLE `fqdnSets` ( KEY `setHash_issued_idx` (`setHash`,`issued`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `incidents` ( +CREATE TABLE IF NOT EXISTS `incidents` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `serialTable` varchar(128) NOT NULL, `url` varchar(1024) NOT NULL, -@@ -106,7 +115,7 @@ CREATE TABLE `incidents` ( +@@ -98,7 +115,7 @@ CREATE TABLE `incidents` ( PRIMARY KEY (`id`) - ) CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `issuedNames` ( +CREATE TABLE IF NOT EXISTS `issuedNames` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `reversedName` varchar(640) CHARACTER SET ascii NOT NULL, `notBefore` datetime NOT NULL, -@@ -114,11 +123,9 @@ CREATE TABLE `issuedNames` ( - `renewal` tinyint(1) NOT NULL DEFAULT 0, - PRIMARY KEY (`id`), +@@ -108,7 +125,7 @@ CREATE TABLE `issuedNames` ( KEY `reversedName_notBefore_Idx` (`reversedName`,`notBefore`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `keyHashToSerial` ( +CREATE TABLE IF NOT EXISTS `keyHashToSerial` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `keyHash` binary(32) NOT NULL, `certNotAfter` datetime NOT NULL, -@@ -128,7 +135,7 @@ CREATE TABLE `keyHashToSerial` ( +@@ -118,7 +135,7 @@ CREATE TABLE `keyHashToSerial` ( KEY `keyHash_certNotAfter` (`keyHash`,`certNotAfter`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -134,7 +109,7 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) NOT NULL AUTO_INCREMENT, `regID` bigint(20) NOT NULL, `time` datetime NOT NULL, -@@ -137,7 +144,7 @@ CREATE TABLE `newOrdersRL` ( +@@ -127,7 +144,7 @@ CREATE TABLE `newOrdersRL` ( UNIQUE KEY `regID_time_idx` (`regID`,`time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -143,16 +118,9 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `setHash` binary(32) NOT NULL, `orderID` bigint(20) NOT NULL, -@@ -147,20 +154,18 @@ CREATE TABLE `orderFqdnSets` ( - KEY `setHash_expires_idx` (`setHash`,`expires`), - KEY `orderID_idx` (`orderID`), +@@ -139,14 +156,14 @@ CREATE TABLE `orderFqdnSets` ( KEY `orderFqdnSets_registrationID_registrations` (`registrationID`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -+ -+DROP TABLE IF EXISTS `orderToAuthz`; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `orderToAuthz2` ( +CREATE TABLE IF NOT EXISTS `orderToAuthz2` ( @@ -160,25 +128,14 @@ index 42c489be9..d2b1eb43b 100644 `authzID` bigint(20) NOT NULL, PRIMARY KEY (`orderID`,`authzID`), KEY `authzID` (`authzID`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE COLUMNS(orderID, authzID) --(PARTITION p_start VALUES LESS THAN (MAXVALUE, MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `orders` ( +CREATE TABLE IF NOT EXISTS `orders` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `registrationID` bigint(20) NOT NULL, `expires` datetime NOT NULL, -@@ -171,14 +176,12 @@ CREATE TABLE `orders` ( - PRIMARY KEY (`id`), - KEY `reg_status_expires` (`registrationID`,`expires`), - KEY `regID_created_idx` (`registrationID`,`created`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - +@@ -162,7 +179,7 @@ CREATE TABLE `orders` ( -- Note: This table's name is a historical artifact and it is now -- used to store linting certificates, not precertificates. -- See #6807. @@ -187,23 +144,16 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) NOT NULL AUTO_INCREMENT, `registrationID` bigint(20) NOT NULL, `serial` varchar(255) NOT NULL, -@@ -189,11 +192,11 @@ CREATE TABLE `precertificates` ( - KEY `serial` (`serial`), - KEY `regId_precertificates_idx` (`registrationID`), +@@ -175,7 +192,7 @@ CREATE TABLE `precertificates` ( KEY `issued_precertificates_idx` (`issued`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -+ -+DROP TABLE IF EXISTS `pendingAuthorizations`; + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE `registrations` ( +CREATE TABLE IF NOT EXISTS `registrations` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `jwk` mediumblob NOT NULL, `jwk_sha256` varchar(255) NOT NULL, -@@ -208,20 +211,32 @@ CREATE TABLE `registrations` ( +@@ -190,7 +207,7 @@ CREATE TABLE `registrations` ( KEY `initialIP_createdAt` (`initialIP`,`createdAt`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -212,14 +162,10 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) NOT NULL AUTO_INCREMENT, `orderID` bigint(20) NOT NULL, `reversedName` varchar(253) CHARACTER SET ascii NOT NULL, - PRIMARY KEY (`id`), - KEY `orderID_idx` (`orderID`), +@@ -199,9 +216,23 @@ CREATE TABLE `requestedNames` ( KEY `reversedName_idx` (`reversedName`) --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- PARTITION BY RANGE(id) --(PARTITION p_start VALUES LESS THAN (MAXVALUE)); -+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -+ + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `revokedCertificates` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `issuerID` bigint(20) NOT NULL, @@ -231,7 +177,7 @@ index 42c489be9..d2b1eb43b 100644 + PRIMARY KEY (`id`), + KEY `issuerID_shardIdx_notAfterHour_idx` (`issuerID`, `shardIdx`, `notAfterHour`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - ++ -- Tables below have foreign key constraints, so are created after all other tables. -CREATE TABLE `serials` ( @@ -241,11 +187,11 @@ index 42c489be9..d2b1eb43b 100644 `id` bigint(20) NOT NULL AUTO_INCREMENT, `registrationID` bigint(20) NOT NULL, `serial` varchar(255) NOT NULL, -@@ -239,6 +254,18 @@ CREATE TABLE `serials` ( +@@ -219,6 +250,18 @@ CREATE TABLE `serials` ( -- First set of tables have foreign key constraints, so are dropped first. DROP TABLE `serials`; -+CREATE TABLE `authz` ( ++CREATE TABLE IF NOT EXISTS `authz` ( + `id` varchar(255) NOT NULL, + `identifier` varchar(255) NOT NULL, + `registrationID` bigint(20) NOT NULL, @@ -260,12 +206,12 @@ index 42c489be9..d2b1eb43b 100644 DROP TABLE `authz2`; DROP TABLE `blockedKeys`; DROP TABLE `certificateStatus`; -@@ -249,8 +276,44 @@ DROP TABLE `issuedNames`; +@@ -230,8 +273,44 @@ DROP TABLE `issuedNames`; DROP TABLE `keyHashToSerial`; DROP TABLE `newOrdersRL`; DROP TABLE `orderFqdnSets`; + -+CREATE TABLE `orderToAuthz` ( ++CREATE TABLE IF NOT EXISTS `orderToAuthz` ( + `orderID` bigint(20) NOT NULL, + `authzID` varchar(255) NOT NULL, + PRIMARY KEY (`orderID`,`authzID`), @@ -275,7 +221,7 @@ index 42c489be9..d2b1eb43b 100644 DROP TABLE `orderToAuthz2`; DROP TABLE `orders`; + -+CREATE TABLE `pendingAuthorizations` ( ++CREATE TABLE IF NOT EXISTS `pendingAuthorizations` ( + `id` varchar(255) NOT NULL, + `identifier` varchar(255) NOT NULL, + `registrationID` bigint(20) NOT NULL, @@ -289,7 +235,7 @@ index 42c489be9..d2b1eb43b 100644 + CONSTRAINT `regId_pending_authz` FOREIGN KEY (`registrationID`) REFERENCES `registrations` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + -+CREATE TABLE `sctReceipts` ( ++CREATE TABLE IF NOT EXISTS `sctReceipts` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `sctVersion` tinyint(1) NOT NULL, + `logID` varchar(255) NOT NULL, diff --git a/patches/docker-compose.patch b/patches/docker-compose.patch index 6defebf..8881d5c 100644 --- a/patches/docker-compose.patch +++ b/patches/docker-compose.patch @@ -1,5 +1,5 @@ diff --git a/docker-compose.yml b/docker-compose.yml -index 39802cd8b..58bb84501 100644 +index d683f8568..c52fd4f2a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,4 @@ @@ -25,13 +25,16 @@ index 39802cd8b..58bb84501 100644 networks: bouldernet: ipv4_address: 10.77.77.77 -@@ -51,98 +54,136 @@ services: +@@ -50,117 +53,137 @@ services: + - 4001:4001 # ACMEv2 - 4003:4003 # SFE depends_on: - - bmysql +- - bmariadb - - bproxysql +- - bvitess - - bredis_1 - - bredis_2 ++ - bmysql + - bredis - bconsul - - bjaeger @@ -62,14 +65,16 @@ index 39802cd8b..58bb84501 100644 + max-file: "5" + restart: always - bmysql: +- bmariadb: ++ bmysql: image: mariadb:10.11.13 + volumes: + - dbdata:/var/lib/mysql networks: bouldernet: aliases: - - boulder-mysql +- - boulder-mariadb ++ - boulder-mysql environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" - # Send slow queries to a table so we can check for them in the @@ -81,12 +86,7 @@ index 39802cd8b..58bb84501 100644 + command: mysqld --bind-address=0.0.0.0 --log-output=TABLE logging: - driver: none -+ driver: "json-file" -+ options: -+ max-size: "500k" -+ max-file: "5" -+ restart: always - +- - bproxysql: - image: proxysql/proxysql:2.7.2 - # The --initial flag force resets the ProxySQL database on startup. By @@ -97,12 +97,17 @@ index 39802cd8b..58bb84501 100644 - volumes: - - ./test/:/test/:cached - depends_on: -- - bmysql +- - bmariadb - networks: - bouldernet: - aliases: - - boulder-proxysql -- ++ driver: "json-file" ++ options: ++ max-size: "500k" ++ max-file: "5" ++ restart: always + - bredis_1: + bredis: image: redis:7.0.15 @@ -165,12 +170,13 @@ index 39802cd8b..58bb84501 100644 + max-size: "500k" + max-file: "5" + restart: always -+ + +- bjaeger: +- image: jaegertracing/all-in-one:1.50 + nginx: + image: nginx:latest -+ restart: always -+ networks: -+ - bouldernet + networks: + - bouldernet + ports: + - 80:80 + - 443:443 @@ -180,13 +186,12 @@ index 39802cd8b..58bb84501 100644 + - /home/labca/nginx_data/static:/var/www/html + depends_on: + - control - -- bjaeger: -- image: jaegertracing/all-in-one:1.50 ++ restart: always ++ + control: + image: *boulder_tools_image - networks: - - bouldernet ++ networks: ++ - bouldernet + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /home/labca/admin/data:/opt/labca/data @@ -214,7 +219,23 @@ index 39802cd8b..58bb84501 100644 networks: - bouldernet + restart: always -+ + +- bvitess: +- # The `letsencrypt/boulder-vtcomboserver:latest` tag is automatically built +- # in local dev environments. In CI a specific BOULDER_VTCOMBOSERVER_TAG is +- # passed, and it is pulled with `docker compose pull`. +- image: letsencrypt/boulder-vtcomboserver:${BOULDER_VTCOMBOSERVER_TAG:-latest} +- build: +- context: test/vtcomboserver/ +- environment: +- # By specifying KEYSPACES vttestserver will create the corresponding +- # databases on startup. +- KEYSPACES: boulder_sa_test,boulder_sa_integration,incidents_sa_test,incidents_sa_integration +- NUM_SHARDS: 1,1,1,1 +- networks: +- bouldernet: +- aliases: +- - boulder-vitess +volumes: + dbdata: diff --git a/patches/entrypoint.patch b/patches/entrypoint.patch index e0fd62d..44b1632 100644 --- a/patches/entrypoint.patch +++ b/patches/entrypoint.patch @@ -1,23 +1,42 @@ diff --git a/test/entrypoint.sh b/test/entrypoint.sh -index 343979a0c..3733ba952 100755 +index 331c0c731..a6c45d067 100755 --- a/test/entrypoint.sh +++ b/test/entrypoint.sh -@@ -13,15 +13,15 @@ service rsyslog start - # make sure we can reach the mysqldb. - ./test/wait-for-it.sh boulder-mysql 3306 +@@ -10,32 +10,23 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + rm -f /var/run/rsyslogd.pid + rsyslogd --# make sure we can reach the proxysql. --./test/wait-for-it.sh bproxysql 6032 +-# make sure we can reach mariadb and proxysql +-./test/wait-for-it.sh boulder-mariadb 3306 +-./test/wait-for-it.sh boulder-proxysql 6033 - +-# make sure we can reach vitess +-./test/wait-for-it.sh boulder-vitess 33577 ++# make sure we can reach mysql ++./test/wait-for-it.sh boulder-mysql 3306 + # make sure we can reach pkilint ./test/wait-for-it.sh bpkimetal 8080 - # create the database - MYSQL_CONTAINER=1 $DIR/create_db.sh + # create the databases + MYSQL_CONTAINER=1 \ +-DB_HOST="boulder-mariadb" \ ++DB_HOST="boulder-mysql" \ + DB_PORT=3306 \ + DB_CONFIG_FILE="${DIR}/../sa/db/dbconfig.mariadb.yml" \ + SKIP_CREATE=0 \ + SKIP_USERS=0 \ + "$DIR/create_db.sh" +-MYSQL_CONTAINER=1 \ +-DB_HOST="boulder-vitess" \ +-DB_PORT=33577 \ +-DB_CONFIG_FILE="${DIR}/../sa/db/dbconfig.mysql8.yml" \ +-SKIP_CREATE=1 \ +-SKIP_USERS=1 \ +-"$DIR/create_db.sh" +# Generate the internal keys and certs +./test/certs/generate.sh -+ + if [[ $# -eq 0 ]]; then exec python3 ./start.py - fi diff --git a/patches/policy_pa.patch b/patches/policy_pa.patch index 9ceb77e..692e069 100644 --- a/patches/policy_pa.patch +++ b/patches/policy_pa.patch @@ -1,5 +1,5 @@ diff --git a/policy/pa.go b/policy/pa.go -index ab17bd89d..52866ef83 100644 +index ab17bd89d..0a71a962d 100644 --- a/policy/pa.go +++ b/policy/pa.go @@ -32,6 +32,9 @@ type AuthorityImpl struct { @@ -210,7 +210,7 @@ index ab17bd89d..52866ef83 100644 labels := strings.Split(ident.Value, ".") for i := range labels { joined := strings.Join(labels[i:], ".") -+ if pa.lockdown[joined] { ++ if pa.lockdown[joined] || pa.whitelist[joined] { + return nil + } if pa.domainBlocklist[joined] { diff --git a/patches/ra_ra.patch b/patches/ra_ra.patch index fc55c95..0ab2c01 100644 --- a/patches/ra_ra.patch +++ b/patches/ra_ra.patch @@ -1,8 +1,8 @@ diff --git a/ra/ra.go b/ra/ra.go -index cd8c599fb..32d94f68c 100644 +index 9fd1ee99d..aa9fdc98c 100644 --- a/ra/ra.go +++ b/ra/ra.go -@@ -41,7 +41,6 @@ import ( +@@ -42,7 +42,6 @@ import ( "github.com/letsencrypt/boulder/issuance" blog "github.com/letsencrypt/boulder/log" "github.com/letsencrypt/boulder/metrics" @@ -10,7 +10,7 @@ index cd8c599fb..32d94f68c 100644 "github.com/letsencrypt/boulder/probs" pubpb "github.com/letsencrypt/boulder/publisher/proto" rapb "github.com/letsencrypt/boulder/ra/proto" -@@ -566,7 +565,7 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error { +@@ -552,7 +551,7 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error { if !core.IsASCII(contact) { return berrors.InvalidEmailError("contact email contains non-ASCII characters") } @@ -19,7 +19,7 @@ index cd8c599fb..32d94f68c 100644 if err != nil { return err } -@@ -1847,6 +1846,9 @@ func crlShard(cert *x509.Certificate) (int64, error) { +@@ -1838,6 +1837,9 @@ func crlShard(cert *x509.Certificate) (int64, error) { return 0, fmt.Errorf("malformed CRLDistributionPoint %q", url) } shardStr := url[lastIndex+1:] diff --git a/patches/remoteva_main.patch b/patches/remoteva_main.patch index cb72cff..3b6653c 100644 --- a/patches/remoteva_main.patch +++ b/patches/remoteva_main.patch @@ -1,5 +1,5 @@ diff --git a/cmd/remoteva/main.go b/cmd/remoteva/main.go -index 43b68d621..1c950cff6 100644 +index e398f1b82..1e9f15fd7 100644 --- a/cmd/remoteva/main.go +++ b/cmd/remoteva/main.go @@ -59,7 +59,8 @@ type Config struct { @@ -30,11 +30,11 @@ index 43b68d621..1c950cff6 100644 cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver") } defer servers.Stop() -@@ -141,6 +146,7 @@ func main() { +@@ -128,6 +133,7 @@ func main() { c.RVA.Perspective, c.RVA.RIR, iana.IsReservedAddr, + c.RVA.LabCADomains, 0, + c.RVA.DNSAllowLoopbackAddresses, ) - cmd.FailOnError(err, "Unable to create Remote-VA server") diff --git a/patches/sfe_overrides.patch b/patches/sfe_overrides.patch index f5840a0..2af8224 100644 --- a/patches/sfe_overrides.patch +++ b/patches/sfe_overrides.patch @@ -1,5 +1,5 @@ diff --git a/sfe/overrides.go b/sfe/overrides.go -index e313f27b7..28b024373 100644 +index fd7589e60..abbbb8e1b 100644 --- a/sfe/overrides.go +++ b/sfe/overrides.go @@ -15,6 +15,7 @@ import ( @@ -10,7 +10,7 @@ index e313f27b7..28b024373 100644 "github.com/letsencrypt/boulder/policy" rl "github.com/letsencrypt/boulder/ratelimits" "github.com/letsencrypt/boulder/sfe/forms" -@@ -346,7 +347,11 @@ func validateOverrideRequestField(fieldName, fieldValue, rateLimit string) error +@@ -347,7 +348,11 @@ func validateOverrideRequestField(fieldName, fieldValue, rateLimit string) error return nil case emailAddressFieldName: @@ -23,7 +23,7 @@ index e313f27b7..28b024373 100644 if err == nil { return nil } -@@ -372,7 +377,11 @@ func validateOverrideRequestField(fieldName, fieldValue, rateLimit string) error +@@ -373,7 +378,11 @@ func validateOverrideRequestField(fieldName, fieldValue, rateLimit string) error return fmt.Errorf("IP address is invalid") case RegisteredDomainFieldName: diff --git a/patches/storer_storer.patch b/patches/storer_storer.patch index e2623eb..bb2d77d 100644 --- a/patches/storer_storer.patch +++ b/patches/storer_storer.patch @@ -1,5 +1,5 @@ diff --git a/crl/storer/storer.go b/crl/storer/storer.go -index 5896da2ac..8a939dc4d 100644 +index e0a49a19c..2b8090a5e 100644 --- a/crl/storer/storer.go +++ b/crl/storer/storer.go @@ -9,8 +9,12 @@ import ( @@ -15,7 +15,7 @@ index 5896da2ac..8a939dc4d 100644 "time" "github.com/aws/aws-sdk-go-v2/service/s3" -@@ -39,6 +43,7 @@ type crlStorer struct { +@@ -40,6 +44,7 @@ type crlStorer struct { cspb.UnsafeCRLStorerServer s3Client simpleS3 s3Bucket string @@ -23,7 +23,7 @@ index 5896da2ac..8a939dc4d 100644 issuers map[issuance.NameID]*issuance.Certificate uploadCount *prometheus.CounterVec sizeHistogram *prometheus.HistogramVec -@@ -53,6 +58,7 @@ func New( +@@ -54,6 +59,7 @@ func New( issuers []*issuance.Certificate, s3Client simpleS3, s3Bucket string, @@ -31,7 +31,7 @@ index 5896da2ac..8a939dc4d 100644 stats prometheus.Registerer, log blog.Logger, clk clock.Clock, -@@ -86,6 +92,7 @@ func New( +@@ -84,6 +90,7 @@ func New( issuers: issuersByNameID, s3Client: s3Client, s3Bucket: s3Bucket, @@ -39,7 +39,7 @@ index 5896da2ac..8a939dc4d 100644 uploadCount: uploadCount, sizeHistogram: sizeHistogram, latencyHistogram: latencyHistogram, -@@ -172,14 +179,21 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR +@@ -170,14 +177,21 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR // additional safety check against clock skew and potential races, if multiple // crl-updaters are working on the same shard at the same time. We only run // these checks if we found a CRL, so we don't block uploading brand new CRLs. @@ -67,7 +67,7 @@ index 5896da2ac..8a939dc4d 100644 return fmt.Errorf("getting previous CRL for %s: %w", crlId, err) } cs.log.Infof("No previous CRL found for %s, proceeding", crlId) -@@ -216,7 +230,7 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR +@@ -214,7 +228,7 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR } } if !uriMatch { @@ -76,7 +76,7 @@ index 5896da2ac..8a939dc4d 100644 } } -@@ -226,17 +240,21 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR +@@ -224,17 +238,21 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR checksum := sha256.Sum256(crlBytes) checksumb64 := base64.StdEncoding.EncodeToString(checksum[:]) crlContentType := "application/pkix-crl" @@ -109,7 +109,7 @@ index 5896da2ac..8a939dc4d 100644 latency := cs.clk.Now().Sub(start) cs.latencyHistogram.WithLabelValues(issuer.Subject.CommonName).Observe(latency.Seconds()) -@@ -255,3 +273,56 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR +@@ -253,3 +271,56 @@ func (cs *crlStorer) UploadCRL(stream grpc.ClientStreamingServer[cspb.UploadCRLR return stream.SendAndClose(&emptypb.Empty{}) } diff --git a/patches/updater_updater.patch b/patches/updater_updater.patch index 01f85a6..bdaa6aa 100644 --- a/patches/updater_updater.patch +++ b/patches/updater_updater.patch @@ -1,8 +1,8 @@ diff --git a/crl/updater/updater.go b/crl/updater/updater.go -index 9020c6c62..09b31f88a 100644 +index 2188cdc4e..760580c4e 100644 --- a/crl/updater/updater.go +++ b/crl/updater/updater.go -@@ -72,7 +72,7 @@ func NewUpdater( +@@ -73,7 +73,7 @@ func NewUpdater( return nil, fmt.Errorf("must have positive number of shards, got: %d", numShards) } @@ -11,7 +11,7 @@ index 9020c6c62..09b31f88a 100644 return nil, fmt.Errorf("must update CRLs at least every 24 hours, got: %s", updatePeriod) } -@@ -229,7 +229,7 @@ func (cu *crlUpdater) updateShard(ctx context.Context, atTime time.Time, issuerN +@@ -228,7 +228,7 @@ func (cu *crlUpdater) updateShard(ctx context.Context, atTime time.Time, issuerN crlEntries = append(crlEntries, entry) } diff --git a/patches/va_http.patch b/patches/va_http.patch index 2473192..bc1844c 100644 --- a/patches/va_http.patch +++ b/patches/va_http.patch @@ -1,8 +1,8 @@ diff --git a/va/http.go b/va/http.go -index e7b0ec304..2b2aa2210 100644 +index dd9f0a998..8af8d1fe8 100644 --- a/va/http.go +++ b/va/http.go -@@ -350,7 +350,16 @@ func (va *ValidationAuthorityImpl) extractRequestTarget(req *http.Request) (iden +@@ -349,7 +349,16 @@ func (va *ValidationAuthorityImpl) extractRequestTarget(req *http.Request) (iden } if _, err := iana.ExtractSuffix(reqHost); err != nil { @@ -20,7 +20,7 @@ index e7b0ec304..2b2aa2210 100644 } return identifier.NewDNS(reqHost), reqPort, nil -@@ -398,10 +407,10 @@ func (va *ValidationAuthorityImpl) setupHTTPValidation( +@@ -397,10 +406,10 @@ func (va *ValidationAuthorityImpl) setupHTTPValidation( // This is a backstop check to avoid connecting to reserved IP addresses. // They should have been caught and excluded by `bdns.LookupHost`. diff --git a/patches/va_va.patch b/patches/va_va.patch index 06d0028..f1e0d15 100644 --- a/patches/va_va.patch +++ b/patches/va_va.patch @@ -1,28 +1,28 @@ diff --git a/va/va.go b/va/va.go -index 55211e27b..20c5f0a94 100644 +index ccaa28558..433fc2c22 100644 --- a/va/va.go +++ b/va/va.go -@@ -220,6 +220,7 @@ type ValidationAuthorityImpl struct { - perspective string - rir string - isReservedIPFunc func(netip.Addr) error -+ labcaDomains []string +@@ -205,6 +205,7 @@ type ValidationAuthorityImpl struct { + rir string + isReservedIPFunc func(netip.Addr) error + allowRestrictedAddrs bool ++ labcaDomains []string metrics *vaMetrics } -@@ -240,6 +241,7 @@ func NewValidationAuthorityImpl( +@@ -225,6 +226,7 @@ func NewValidationAuthorityImpl( perspective string, rir string, reservedIPChecker func(netip.Addr) error, + labcaDomains []string, slowRemoteTimeout time.Duration, + allowRestrictedAddrs bool, ) (*ValidationAuthorityImpl, error) { - -@@ -278,6 +280,7 @@ func NewValidationAuthorityImpl( - perspective: perspective, - rir: rir, - isReservedIPFunc: reservedIPChecker, -+ labcaDomains: labcaDomains, +@@ -265,6 +267,7 @@ func NewValidationAuthorityImpl( + rir: rir, + isReservedIPFunc: reservedIPChecker, + allowRestrictedAddrs: allowRestrictedAddrs, ++ labcaDomains: labcaDomains, } return va, nil diff --git a/patches/wfe2_main.patch b/patches/wfe2_main.patch index cc0780b..e28940e 100644 --- a/patches/wfe2_main.patch +++ b/patches/wfe2_main.patch @@ -1,5 +1,5 @@ diff --git a/cmd/boulder-wfe2/main.go b/cmd/boulder-wfe2/main.go -index a7a10ca26..4241ad106 100644 +index 8e681840e..a8ecfff97 100644 --- a/cmd/boulder-wfe2/main.go +++ b/cmd/boulder-wfe2/main.go @@ -14,14 +14,17 @@ import ( @@ -65,7 +65,7 @@ index a7a10ca26..4241ad106 100644 source := ratelimits.NewRedisSource(limiterRedis.Ring, clk, stats) limiter, err = ratelimits.NewLimiter(clk, source, stats) cmd.FailOnError(err, "Failed to create rate limiter") -@@ -384,6 +403,7 @@ func main() { +@@ -387,6 +406,7 @@ func main() { unpauseSigner, c.WFE.Unpause.JWTLifetime.Duration, c.WFE.Unpause.URL, diff --git a/patches/wfe2_wfe.patch b/patches/wfe2_wfe.patch index 604286a..3b7366b 100644 --- a/patches/wfe2_wfe.patch +++ b/patches/wfe2_wfe.patch @@ -1,8 +1,8 @@ diff --git a/wfe2/wfe.go b/wfe2/wfe.go -index d82a529fc..3a0129c6c 100644 +index efe2c6d08..8c2b1e1b2 100644 --- a/wfe2/wfe.go +++ b/wfe2/wfe.go -@@ -166,6 +166,8 @@ type WebFrontEndImpl struct { +@@ -167,6 +167,8 @@ type WebFrontEndImpl struct { // descriptions (perhaps including URLs) of those profiles. NewOrder // Requests with a profile name not present in this map will be rejected. certProfiles map[string]string @@ -11,7 +11,7 @@ index d82a529fc..3a0129c6c 100644 } // NewWebFrontEndImpl constructs a web service for Boulder -@@ -192,6 +194,7 @@ func NewWebFrontEndImpl( +@@ -193,6 +195,7 @@ func NewWebFrontEndImpl( unpauseSigner unpause.JWTSigner, unpauseJWTLifetime time.Duration, unpauseURL string, @@ -19,7 +19,7 @@ index d82a529fc..3a0129c6c 100644 ) (WebFrontEndImpl, error) { if len(issuerCertificates) == 0 { return WebFrontEndImpl{}, errors.New("must provide at least one issuer certificate") -@@ -209,6 +212,10 @@ func NewWebFrontEndImpl( +@@ -210,6 +213,10 @@ func NewWebFrontEndImpl( return WebFrontEndImpl{}, errors.New("must provide a service for nonce redemption") } @@ -30,7 +30,7 @@ index d82a529fc..3a0129c6c 100644 wfe := WebFrontEndImpl{ log: logger, clk: clk, -@@ -232,6 +239,7 @@ func NewWebFrontEndImpl( +@@ -233,6 +240,7 @@ func NewWebFrontEndImpl( unpauseSigner: unpauseSigner, unpauseJWTLifetime: unpauseJWTLifetime, unpauseURL: unpauseURL, @@ -38,7 +38,7 @@ index d82a529fc..3a0129c6c 100644 } return wfe, nil -@@ -679,7 +687,7 @@ func (wfe *WebFrontEndImpl) contactsToEmails(contacts []string) ([]string, error +@@ -681,7 +689,7 @@ func (wfe *WebFrontEndImpl) contactsToEmails(contacts []string) ([]string, error return nil, berrors.InvalidEmailError("contact email contains non-ASCII characters") } @@ -47,7 +47,7 @@ index d82a529fc..3a0129c6c 100644 if err != nil { return nil, err } -@@ -2305,7 +2313,7 @@ func (wfe *WebFrontEndImpl) NewOrder( +@@ -2332,7 +2340,7 @@ func (wfe *WebFrontEndImpl) NewOrder( idents = identifier.Normalize(idents) logEvent.Identifiers = idents diff --git a/utils.sh b/utils.sh index 73f9c80..7e8c4be 100644 --- a/utils.sh +++ b/utils.sh @@ -4,7 +4,7 @@ set -e export PS_LABCA="bin/labca-gui" export PS_BOULDER="bin/boulder" -export PS_BOULDER_COUNT=26 +export PS_BOULDER_COUNT=25 export PS_MYSQL="mysqld" export PS_CONTROL="tcpserver" export PS_NGINX="nginx:"