From 96f124060393f30bf9da67de0e492c599fa38445 Mon Sep 17 00:00:00 2001 From: Matthew McPherrin Date: Wed, 21 Feb 2024 17:51:26 -0500 Subject: [PATCH 01/17] Update publicsuffix-go (#7334) --- go.mod | 2 +- go.sum | 8 +- .../publicsuffix-go/publicsuffix/rules.go | 580 ++++++++++++++++-- vendor/modules.txt | 2 +- 4 files changed, 551 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index bc73fdad299..6e97ea2ece4 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/prometheus/client_model v0.4.0 github.com/redis/go-redis/v9 v9.3.0 github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 - github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 + github.com/weppos/publicsuffix-go v0.30.2-0.20240219083929-48f3a5ae027a github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c github.com/zmap/zlint/v3 v3.6.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 diff --git a/go.sum b/go.sum index 7e55e53eb15..1361046c418 100644 --- a/go.sum +++ b/go.sum @@ -249,8 +249,9 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHT github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 h1:h2JizvZl9aIj6za9S5AyrkU+OzIS4CetQthH/ejO+lg= github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ= +github.com/weppos/publicsuffix-go v0.30.2-0.20240219083929-48f3a5ae027a h1:s0Yp4S5jdEQFTJE1blGE5o+n7T0uI386YHXzocLKLR4= +github.com/weppos/publicsuffix-go v0.30.2-0.20240219083929-48f3a5ae027a/go.mod h1:v7j8MuFp1CIYgAd2n7xEUctTbsreRd1vPmOwyzmGFiE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -299,6 +300,7 @@ golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= @@ -328,6 +330,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -366,6 +369,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -376,6 +380,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= @@ -388,6 +393,7 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/vendor/github.com/weppos/publicsuffix-go/publicsuffix/rules.go b/vendor/github.com/weppos/publicsuffix-go/publicsuffix/rules.go index 60a43de7826..39bb25e54b7 100644 --- a/vendor/github.com/weppos/publicsuffix-go/publicsuffix/rules.go +++ b/vendor/github.com/weppos/publicsuffix-go/publicsuffix/rules.go @@ -3,13 +3,13 @@ package publicsuffix -const ListVersion = "PSL version 4e6c53 (Fri Jul 28 21:50:43 2023)" +const ListVersion = "PSL version b7a060 (Mon Feb 12 23:55:23 2024)" -func DefaultRules() [9106]Rule { +func DefaultRules() [9610]Rule { return r } -var r = [9106]Rule{ +var r = [9610]Rule{ {1, "ac", 1, false}, {1, "com.ac", 2, false}, {1, "edu.ac", 2, false}, @@ -841,21 +841,10 @@ var r = [9106]Rule{ {1, "nom.fr", 2, false}, {1, "prd.fr", 2, false}, {1, "tm.fr", 2, false}, - {1, "aeroport.fr", 2, false}, - {1, "avocat.fr", 2, false}, {1, "avoues.fr", 2, false}, {1, "cci.fr", 2, false}, - {1, "chambagri.fr", 2, false}, - {1, "chirurgiens-dentistes.fr", 2, false}, - {1, "experts-comptables.fr", 2, false}, - {1, "geometre-expert.fr", 2, false}, {1, "greta.fr", 2, false}, {1, "huissier-justice.fr", 2, false}, - {1, "medecin.fr", 2, false}, - {1, "notaires.fr", 2, false}, - {1, "pharmacien.fr", 2, false}, - {1, "port.fr", 2, false}, - {1, "veterinaire.fr", 2, false}, {1, "ga", 1, false}, {1, "gb", 1, false}, {1, "edu.gd", 2, false}, @@ -5214,6 +5203,7 @@ var r = [9106]Rule{ {1, "lg.ua", 2, false}, {1, "lt.ua", 2, false}, {1, "lugansk.ua", 2, false}, + {1, "luhansk.ua", 2, false}, {1, "lutsk.ua", 2, false}, {1, "lv.ua", 2, false}, {1, "lviv.ua", 2, false}, @@ -5237,11 +5227,13 @@ var r = [9106]Rule{ {1, "ternopil.ua", 2, false}, {1, "uz.ua", 2, false}, {1, "uzhgorod.ua", 2, false}, + {1, "uzhhorod.ua", 2, false}, {1, "vinnica.ua", 2, false}, {1, "vinnytsia.ua", 2, false}, {1, "vn.ua", 2, false}, {1, "volyn.ua", 2, false}, {1, "yalta.ua", 2, false}, + {1, "zakarpattia.ua", 2, false}, {1, "zaporizhzhe.ua", 2, false}, {1, "zaporizhzhia.ua", 2, false}, {1, "zhitomir.ua", 2, false}, @@ -5339,7 +5331,6 @@ var r = [9106]Rule{ {1, "k12.co.us", 3, false}, {1, "k12.ct.us", 3, false}, {1, "k12.dc.us", 3, false}, - {1, "k12.de.us", 3, false}, {1, "k12.fl.us", 3, false}, {1, "k12.ga.us", 3, false}, {1, "k12.gu.us", 3, false}, @@ -5846,7 +5837,6 @@ var r = [9106]Rule{ {1, "baby", 1, false}, {1, "baidu", 1, false}, {1, "banamex", 1, false}, - {1, "bananarepublic", 1, false}, {1, "band", 1, false}, {1, "bank", 1, false}, {1, "bar", 1, false}, @@ -5942,7 +5932,6 @@ var r = [9106]Rule{ {1, "cba", 1, false}, {1, "cbn", 1, false}, {1, "cbre", 1, false}, - {1, "cbs", 1, false}, {1, "center", 1, false}, {1, "ceo", 1, false}, {1, "cern", 1, false}, @@ -5965,7 +5954,6 @@ var r = [9106]Rule{ {1, "citi", 1, false}, {1, "citic", 1, false}, {1, "city", 1, false}, - {1, "cityeats", 1, false}, {1, "claims", 1, false}, {1, "cleaning", 1, false}, {1, "click", 1, false}, @@ -5980,7 +5968,6 @@ var r = [9106]Rule{ {1, "coffee", 1, false}, {1, "college", 1, false}, {1, "cologne", 1, false}, - {1, "comcast", 1, false}, {1, "commbank", 1, false}, {1, "community", 1, false}, {1, "company", 1, false}, @@ -6077,7 +6064,6 @@ var r = [9106]Rule{ {1, "erni", 1, false}, {1, "esq", 1, false}, {1, "estate", 1, false}, - {1, "etisalat", 1, false}, {1, "eurovision", 1, false}, {1, "eus", 1, false}, {1, "events", 1, false}, @@ -6133,7 +6119,6 @@ var r = [9106]Rule{ {1, "fresenius", 1, false}, {1, "frl", 1, false}, {1, "frogans", 1, false}, - {1, "frontdoor", 1, false}, {1, "frontier", 1, false}, {1, "ftr", 1, false}, {1, "fujitsu", 1, false}, @@ -6287,7 +6272,6 @@ var r = [9106]Rule{ {1, "kia", 1, false}, {1, "kids", 1, false}, {1, "kim", 1, false}, - {1, "kinder", 1, false}, {1, "kindle", 1, false}, {1, "kitchen", 1, false}, {1, "kiwi", 1, false}, @@ -6406,7 +6390,6 @@ var r = [9106]Rule{ {1, "mtn", 1, false}, {1, "mtr", 1, false}, {1, "music", 1, false}, - {1, "mutual", 1, false}, {1, "nab", 1, false}, {1, "nagoya", 1, false}, {1, "natura", 1, false}, @@ -6432,7 +6415,6 @@ var r = [9106]Rule{ {1, "nissan", 1, false}, {1, "nissay", 1, false}, {1, "nokia", 1, false}, - {1, "northwesternmutual", 1, false}, {1, "norton", 1, false}, {1, "now", 1, false}, {1, "nowruz", 1, false}, @@ -6447,7 +6429,6 @@ var r = [9106]Rule{ {1, "okinawa", 1, false}, {1, "olayan", 1, false}, {1, "olayangroup", 1, false}, - {1, "oldnavy", 1, false}, {1, "ollo", 1, false}, {1, "omega", 1, false}, {1, "one", 1, false}, @@ -6553,7 +6534,6 @@ var r = [9106]Rule{ {1, "ril", 1, false}, {1, "rio", 1, false}, {1, "rip", 1, false}, - {1, "rocher", 1, false}, {1, "rocks", 1, false}, {1, "rodeo", 1, false}, {1, "rogers", 1, false}, @@ -6582,7 +6562,6 @@ var r = [9106]Rule{ {1, "saxo", 1, false}, {1, "sbi", 1, false}, {1, "sbs", 1, false}, - {1, "sca", 1, false}, {1, "scb", 1, false}, {1, "schaeffler", 1, false}, {1, "schmidt", 1, false}, @@ -6616,7 +6595,6 @@ var r = [9106]Rule{ {1, "shopping", 1, false}, {1, "shouji", 1, false}, {1, "show", 1, false}, - {1, "showtime", 1, false}, {1, "silk", 1, false}, {1, "sina", 1, false}, {1, "singles", 1, false}, @@ -6753,7 +6731,6 @@ var r = [9106]Rule{ {1, "vivo", 1, false}, {1, "vlaanderen", 1, false}, {1, "vodka", 1, false}, - {1, "volkswagen", 1, false}, {1, "volvo", 1, false}, {1, "vote", 1, false}, {1, "voting", 1, false}, @@ -6771,6 +6748,7 @@ var r = [9106]Rule{ {1, "webcam", 1, false}, {1, "weber", 1, false}, {1, "website", 1, false}, + {1, "wed", 1, false}, {1, "wedding", 1, false}, {1, "weibo", 1, false}, {1, "weir", 1, false}, @@ -6793,7 +6771,6 @@ var r = [9106]Rule{ {1, "wtf", 1, false}, {1, "xbox", 1, false}, {1, "xerox", 1, false}, - {1, "xfinity", 1, false}, {1, "xihuan", 1, false}, {1, "xin", 1, false}, {1, "xn--11b4c3d", 1, false}, @@ -6854,7 +6831,6 @@ var r = [9106]Rule{ {1, "xn--kput3i", 1, false}, {1, "xn--mgba3a3ejt", 1, false}, {1, "xn--mgba7c0bbn0a", 1, false}, - {1, "xn--mgbaakc7dvf", 1, false}, {1, "xn--mgbab2bd", 1, false}, {1, "xn--mgbca7dzdo", 1, false}, {1, "xn--mgbi4ecexp", 1, false}, @@ -6904,18 +6880,25 @@ var r = [9106]Rule{ {1, "zip", 1, false}, {1, "zone", 1, false}, {1, "zuerich", 1, false}, + {1, "12chars.dev", 2, true}, + {1, "12chars.it", 2, true}, + {1, "12chars.pro", 2, true}, {1, "cc.ua", 2, true}, {1, "inf.ua", 2, true}, {1, "ltd.ua", 2, true}, {1, "611.to", 2, true}, + {1, "a2hosted.com", 2, true}, + {1, "cpserver.com", 2, true}, {1, "graphox.us", 2, true}, {2, "devcdnaccesso.com", 3, true}, {2, "on-acorn.io", 3, true}, {1, "activetrail.biz", 2, true}, {1, "adobeaemcloud.com", 2, true}, {2, "dev.adobeaemcloud.com", 4, true}, + {1, "aem.live", 2, true}, {1, "hlx.live", 2, true}, {1, "adobeaemcloud.net", 2, true}, + {1, "aem.page", 2, true}, {1, "hlx.page", 2, true}, {1, "hlx3.page", 2, true}, {1, "adobeio-static.net", 2, true}, @@ -6947,49 +6930,371 @@ var r = [9106]Rule{ {1, "altervista.org", 2, true}, {1, "alwaysdata.net", 2, true}, {1, "myamaze.net", 2, true}, + {1, "execute-api.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "execute-api.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "execute-api.af-south-1.amazonaws.com", 4, true}, + {1, "execute-api.ap-east-1.amazonaws.com", 4, true}, + {1, "execute-api.ap-northeast-1.amazonaws.com", 4, true}, + {1, "execute-api.ap-northeast-2.amazonaws.com", 4, true}, + {1, "execute-api.ap-northeast-3.amazonaws.com", 4, true}, + {1, "execute-api.ap-south-1.amazonaws.com", 4, true}, + {1, "execute-api.ap-south-2.amazonaws.com", 4, true}, + {1, "execute-api.ap-southeast-1.amazonaws.com", 4, true}, + {1, "execute-api.ap-southeast-2.amazonaws.com", 4, true}, + {1, "execute-api.ap-southeast-3.amazonaws.com", 4, true}, + {1, "execute-api.ap-southeast-4.amazonaws.com", 4, true}, + {1, "execute-api.ca-central-1.amazonaws.com", 4, true}, + {1, "execute-api.ca-west-1.amazonaws.com", 4, true}, + {1, "execute-api.eu-central-1.amazonaws.com", 4, true}, + {1, "execute-api.eu-central-2.amazonaws.com", 4, true}, + {1, "execute-api.eu-north-1.amazonaws.com", 4, true}, + {1, "execute-api.eu-south-1.amazonaws.com", 4, true}, + {1, "execute-api.eu-south-2.amazonaws.com", 4, true}, + {1, "execute-api.eu-west-1.amazonaws.com", 4, true}, + {1, "execute-api.eu-west-2.amazonaws.com", 4, true}, + {1, "execute-api.eu-west-3.amazonaws.com", 4, true}, + {1, "execute-api.il-central-1.amazonaws.com", 4, true}, + {1, "execute-api.me-central-1.amazonaws.com", 4, true}, + {1, "execute-api.me-south-1.amazonaws.com", 4, true}, + {1, "execute-api.sa-east-1.amazonaws.com", 4, true}, + {1, "execute-api.us-east-1.amazonaws.com", 4, true}, + {1, "execute-api.us-east-2.amazonaws.com", 4, true}, + {1, "execute-api.us-gov-east-1.amazonaws.com", 4, true}, + {1, "execute-api.us-gov-west-1.amazonaws.com", 4, true}, + {1, "execute-api.us-west-1.amazonaws.com", 4, true}, + {1, "execute-api.us-west-2.amazonaws.com", 4, true}, {1, "cloudfront.net", 2, true}, + {1, "auth.af-south-1.amazoncognito.com", 4, true}, + {1, "auth.ap-northeast-1.amazoncognito.com", 4, true}, + {1, "auth.ap-northeast-2.amazoncognito.com", 4, true}, + {1, "auth.ap-northeast-3.amazoncognito.com", 4, true}, + {1, "auth.ap-south-1.amazoncognito.com", 4, true}, + {1, "auth.ap-southeast-1.amazoncognito.com", 4, true}, + {1, "auth.ap-southeast-2.amazoncognito.com", 4, true}, + {1, "auth.ap-southeast-3.amazoncognito.com", 4, true}, + {1, "auth.ca-central-1.amazoncognito.com", 4, true}, + {1, "auth.eu-central-1.amazoncognito.com", 4, true}, + {1, "auth.eu-north-1.amazoncognito.com", 4, true}, + {1, "auth.eu-south-1.amazoncognito.com", 4, true}, + {1, "auth.eu-west-1.amazoncognito.com", 4, true}, + {1, "auth.eu-west-2.amazoncognito.com", 4, true}, + {1, "auth.eu-west-3.amazoncognito.com", 4, true}, + {1, "auth.il-central-1.amazoncognito.com", 4, true}, + {1, "auth.me-south-1.amazoncognito.com", 4, true}, + {1, "auth.sa-east-1.amazoncognito.com", 4, true}, + {1, "auth.us-east-1.amazoncognito.com", 4, true}, + {1, "auth-fips.us-east-1.amazoncognito.com", 4, true}, + {1, "auth.us-east-2.amazoncognito.com", 4, true}, + {1, "auth-fips.us-east-2.amazoncognito.com", 4, true}, + {1, "auth-fips.us-gov-west-1.amazoncognito.com", 4, true}, + {1, "auth.us-west-1.amazoncognito.com", 4, true}, + {1, "auth-fips.us-west-1.amazoncognito.com", 4, true}, + {1, "auth.us-west-2.amazoncognito.com", 4, true}, + {1, "auth-fips.us-west-2.amazoncognito.com", 4, true}, {2, "compute.amazonaws.com", 4, true}, {2, "compute-1.amazonaws.com", 4, true}, {2, "compute.amazonaws.com.cn", 5, true}, {1, "us-east-1.amazonaws.com", 3, true}, + {1, "emrappui-prod.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "emrnotebooks-prod.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "emrstudio-prod.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "emrappui-prod.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "emrstudio-prod.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "emrappui-prod.af-south-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.af-south-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.af-south-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-east-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-east-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-east-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-northeast-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-northeast-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-northeast-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-northeast-2.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-northeast-2.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-northeast-2.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-northeast-3.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-northeast-3.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-northeast-3.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-south-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-south-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-south-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-southeast-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-southeast-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-southeast-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-southeast-2.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-southeast-2.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-southeast-2.amazonaws.com", 4, true}, + {1, "emrappui-prod.ap-southeast-3.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ap-southeast-3.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ap-southeast-3.amazonaws.com", 4, true}, + {1, "emrappui-prod.ca-central-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.ca-central-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.ca-central-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.eu-central-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.eu-central-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.eu-central-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.eu-north-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.eu-north-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.eu-north-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.eu-south-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.eu-south-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.eu-south-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.eu-west-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.eu-west-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.eu-west-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.eu-west-2.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.eu-west-2.amazonaws.com", 4, true}, + {1, "emrstudio-prod.eu-west-2.amazonaws.com", 4, true}, + {1, "emrappui-prod.eu-west-3.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.eu-west-3.amazonaws.com", 4, true}, + {1, "emrstudio-prod.eu-west-3.amazonaws.com", 4, true}, + {1, "emrappui-prod.me-central-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.me-central-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.me-central-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.me-south-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.me-south-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.me-south-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.sa-east-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.sa-east-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.sa-east-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.us-east-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.us-east-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.us-east-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.us-east-2.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.us-east-2.amazonaws.com", 4, true}, + {1, "emrstudio-prod.us-east-2.amazonaws.com", 4, true}, + {1, "emrappui-prod.us-gov-east-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.us-gov-east-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.us-gov-east-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.us-gov-west-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.us-gov-west-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.us-gov-west-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.us-west-1.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.us-west-1.amazonaws.com", 4, true}, + {1, "emrstudio-prod.us-west-1.amazonaws.com", 4, true}, + {1, "emrappui-prod.us-west-2.amazonaws.com", 4, true}, + {1, "emrnotebooks-prod.us-west-2.amazonaws.com", 4, true}, + {1, "emrstudio-prod.us-west-2.amazonaws.com", 4, true}, + {2, "cn-north-1.airflow.amazonaws.com.cn", 6, true}, + {2, "cn-northwest-1.airflow.amazonaws.com.cn", 6, true}, + {2, "ap-northeast-1.airflow.amazonaws.com", 5, true}, + {2, "ap-northeast-2.airflow.amazonaws.com", 5, true}, + {2, "ap-south-1.airflow.amazonaws.com", 5, true}, + {2, "ap-southeast-1.airflow.amazonaws.com", 5, true}, + {2, "ap-southeast-2.airflow.amazonaws.com", 5, true}, + {2, "ca-central-1.airflow.amazonaws.com", 5, true}, + {2, "eu-central-1.airflow.amazonaws.com", 5, true}, + {2, "eu-north-1.airflow.amazonaws.com", 5, true}, + {2, "eu-west-1.airflow.amazonaws.com", 5, true}, + {2, "eu-west-2.airflow.amazonaws.com", 5, true}, + {2, "eu-west-3.airflow.amazonaws.com", 5, true}, + {2, "sa-east-1.airflow.amazonaws.com", 5, true}, + {2, "us-east-1.airflow.amazonaws.com", 5, true}, + {2, "us-east-2.airflow.amazonaws.com", 5, true}, + {2, "us-west-2.airflow.amazonaws.com", 5, true}, + {1, "s3.dualstack.cn-north-1.amazonaws.com.cn", 6, true}, + {1, "s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn", 6, true}, + {1, "s3-website.dualstack.cn-north-1.amazonaws.com.cn", 6, true}, {1, "s3.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "s3-accesspoint.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "s3-deprecated.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "s3-object-lambda.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "s3-website.cn-north-1.amazonaws.com.cn", 5, true}, + {1, "s3.dualstack.cn-northwest-1.amazonaws.com.cn", 6, true}, + {1, "s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn", 6, true}, + {1, "s3.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "s3-accesspoint.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "s3-object-lambda.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "s3-website.cn-northwest-1.amazonaws.com.cn", 5, true}, + {1, "s3.dualstack.af-south-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.af-south-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.af-south-1.amazonaws.com", 5, true}, + {1, "s3.af-south-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.af-south-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.af-south-1.amazonaws.com", 4, true}, + {1, "s3-website.af-south-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.ap-east-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-east-1.amazonaws.com", 5, true}, + {1, "s3.ap-east-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-east-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-east-1.amazonaws.com", 4, true}, + {1, "s3-website.ap-east-1.amazonaws.com", 4, true}, {1, "s3.dualstack.ap-northeast-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ap-northeast-1.amazonaws.com", 5, true}, + {1, "s3.ap-northeast-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-northeast-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-northeast-1.amazonaws.com", 4, true}, + {1, "s3-website.ap-northeast-1.amazonaws.com", 4, true}, {1, "s3.dualstack.ap-northeast-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ap-northeast-2.amazonaws.com", 5, true}, {1, "s3.ap-northeast-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-northeast-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-northeast-2.amazonaws.com", 4, true}, {1, "s3-website.ap-northeast-2.amazonaws.com", 4, true}, + {1, "s3.dualstack.ap-northeast-3.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ap-northeast-3.amazonaws.com", 5, true}, + {1, "s3.ap-northeast-3.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-northeast-3.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-northeast-3.amazonaws.com", 4, true}, + {1, "s3-website.ap-northeast-3.amazonaws.com", 4, true}, {1, "s3.dualstack.ap-south-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-south-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ap-south-1.amazonaws.com", 5, true}, {1, "s3.ap-south-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-south-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-south-1.amazonaws.com", 4, true}, {1, "s3-website.ap-south-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.ap-south-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-south-2.amazonaws.com", 5, true}, + {1, "s3.ap-south-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-south-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-south-2.amazonaws.com", 4, true}, + {1, "s3-website.ap-south-2.amazonaws.com", 4, true}, {1, "s3.dualstack.ap-southeast-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ap-southeast-1.amazonaws.com", 5, true}, + {1, "s3.ap-southeast-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-southeast-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-southeast-1.amazonaws.com", 4, true}, + {1, "s3-website.ap-southeast-1.amazonaws.com", 4, true}, {1, "s3.dualstack.ap-southeast-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ap-southeast-2.amazonaws.com", 5, true}, + {1, "s3.ap-southeast-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-southeast-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-southeast-2.amazonaws.com", 4, true}, + {1, "s3-website.ap-southeast-2.amazonaws.com", 4, true}, + {1, "s3.dualstack.ap-southeast-3.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com", 5, true}, + {1, "s3.ap-southeast-3.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-southeast-3.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-southeast-3.amazonaws.com", 4, true}, + {1, "s3-website.ap-southeast-3.amazonaws.com", 4, true}, + {1, "s3.dualstack.ap-southeast-4.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com", 5, true}, + {1, "s3.ap-southeast-4.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ap-southeast-4.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ap-southeast-4.amazonaws.com", 4, true}, + {1, "s3-website.ap-southeast-4.amazonaws.com", 4, true}, {1, "s3.dualstack.ca-central-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ca-central-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.ca-central-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ca-central-1.amazonaws.com", 5, true}, {1, "s3.ca-central-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ca-central-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.ca-central-1.amazonaws.com", 4, true}, + {1, "s3-fips.ca-central-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.ca-central-1.amazonaws.com", 4, true}, {1, "s3-website.ca-central-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.ca-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.ca-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.ca-west-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.ca-west-1.amazonaws.com", 5, true}, + {1, "s3.ca-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.ca-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.ca-west-1.amazonaws.com", 4, true}, + {1, "s3-fips.ca-west-1.amazonaws.com", 4, true}, + {1, "s3-website.ca-west-1.amazonaws.com", 4, true}, {1, "s3.dualstack.eu-central-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-central-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.eu-central-1.amazonaws.com", 5, true}, {1, "s3.eu-central-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-central-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-central-1.amazonaws.com", 4, true}, {1, "s3-website.eu-central-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.eu-central-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-central-2.amazonaws.com", 5, true}, + {1, "s3.eu-central-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-central-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-central-2.amazonaws.com", 4, true}, + {1, "s3-website.eu-central-2.amazonaws.com", 4, true}, + {1, "s3.dualstack.eu-north-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-north-1.amazonaws.com", 5, true}, + {1, "s3.eu-north-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-north-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-north-1.amazonaws.com", 4, true}, + {1, "s3-website.eu-north-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.eu-south-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-south-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.eu-south-1.amazonaws.com", 5, true}, + {1, "s3.eu-south-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-south-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-south-1.amazonaws.com", 4, true}, + {1, "s3-website.eu-south-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.eu-south-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-south-2.amazonaws.com", 5, true}, + {1, "s3.eu-south-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-south-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-south-2.amazonaws.com", 4, true}, + {1, "s3-website.eu-south-2.amazonaws.com", 4, true}, {1, "s3.dualstack.eu-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-west-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.eu-west-1.amazonaws.com", 5, true}, + {1, "s3.eu-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-west-1.amazonaws.com", 4, true}, + {1, "s3-deprecated.eu-west-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-west-1.amazonaws.com", 4, true}, + {1, "s3-website.eu-west-1.amazonaws.com", 4, true}, {1, "s3.dualstack.eu-west-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-west-2.amazonaws.com", 5, true}, {1, "s3.eu-west-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-west-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-west-2.amazonaws.com", 4, true}, {1, "s3-website.eu-west-2.amazonaws.com", 4, true}, {1, "s3.dualstack.eu-west-3.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.eu-west-3.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.eu-west-3.amazonaws.com", 5, true}, {1, "s3.eu-west-3.amazonaws.com", 4, true}, + {1, "s3-accesspoint.eu-west-3.amazonaws.com", 4, true}, + {1, "s3-object-lambda.eu-west-3.amazonaws.com", 4, true}, {1, "s3-website.eu-west-3.amazonaws.com", 4, true}, + {1, "s3.dualstack.il-central-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.il-central-1.amazonaws.com", 5, true}, + {1, "s3.il-central-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.il-central-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.il-central-1.amazonaws.com", 4, true}, + {1, "s3-website.il-central-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.me-central-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.me-central-1.amazonaws.com", 5, true}, + {1, "s3.me-central-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.me-central-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.me-central-1.amazonaws.com", 4, true}, + {1, "s3-website.me-central-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.me-south-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.me-south-1.amazonaws.com", 5, true}, + {1, "s3.me-south-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.me-south-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.me-south-1.amazonaws.com", 4, true}, + {1, "s3-website.me-south-1.amazonaws.com", 4, true}, {1, "s3.amazonaws.com", 3, true}, + {1, "s3-1.amazonaws.com", 3, true}, + {1, "s3-ap-east-1.amazonaws.com", 3, true}, {1, "s3-ap-northeast-1.amazonaws.com", 3, true}, {1, "s3-ap-northeast-2.amazonaws.com", 3, true}, + {1, "s3-ap-northeast-3.amazonaws.com", 3, true}, {1, "s3-ap-south-1.amazonaws.com", 3, true}, {1, "s3-ap-southeast-1.amazonaws.com", 3, true}, {1, "s3-ap-southeast-2.amazonaws.com", 3, true}, {1, "s3-ca-central-1.amazonaws.com", 3, true}, {1, "s3-eu-central-1.amazonaws.com", 3, true}, + {1, "s3-eu-north-1.amazonaws.com", 3, true}, {1, "s3-eu-west-1.amazonaws.com", 3, true}, {1, "s3-eu-west-2.amazonaws.com", 3, true}, {1, "s3-eu-west-3.amazonaws.com", 3, true}, {1, "s3-external-1.amazonaws.com", 3, true}, + {1, "s3-fips-us-gov-east-1.amazonaws.com", 3, true}, {1, "s3-fips-us-gov-west-1.amazonaws.com", 3, true}, + {1, "mrap.accesspoint.s3-global.amazonaws.com", 5, true}, + {1, "s3-me-south-1.amazonaws.com", 3, true}, {1, "s3-sa-east-1.amazonaws.com", 3, true}, {1, "s3-us-east-2.amazonaws.com", 3, true}, + {1, "s3-us-gov-east-1.amazonaws.com", 3, true}, {1, "s3-us-gov-west-1.amazonaws.com", 3, true}, {1, "s3-us-west-1.amazonaws.com", 3, true}, {1, "s3-us-west-2.amazonaws.com", 3, true}, @@ -6999,18 +7304,164 @@ var r = [9106]Rule{ {1, "s3-website-eu-west-1.amazonaws.com", 3, true}, {1, "s3-website-sa-east-1.amazonaws.com", 3, true}, {1, "s3-website-us-east-1.amazonaws.com", 3, true}, + {1, "s3-website-us-gov-west-1.amazonaws.com", 3, true}, {1, "s3-website-us-west-1.amazonaws.com", 3, true}, {1, "s3-website-us-west-2.amazonaws.com", 3, true}, {1, "s3.dualstack.sa-east-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.sa-east-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.sa-east-1.amazonaws.com", 5, true}, + {1, "s3.sa-east-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.sa-east-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.sa-east-1.amazonaws.com", 4, true}, + {1, "s3-website.sa-east-1.amazonaws.com", 4, true}, {1, "s3.dualstack.us-east-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.us-east-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.us-east-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.us-east-1.amazonaws.com", 5, true}, + {1, "s3.us-east-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.us-east-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.us-east-1.amazonaws.com", 4, true}, + {1, "s3-deprecated.us-east-1.amazonaws.com", 4, true}, + {1, "s3-fips.us-east-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.us-east-1.amazonaws.com", 4, true}, + {1, "s3-website.us-east-1.amazonaws.com", 4, true}, {1, "s3.dualstack.us-east-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.us-east-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.us-east-2.amazonaws.com", 5, true}, {1, "s3.us-east-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.us-east-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.us-east-2.amazonaws.com", 4, true}, + {1, "s3-deprecated.us-east-2.amazonaws.com", 4, true}, + {1, "s3-fips.us-east-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.us-east-2.amazonaws.com", 4, true}, {1, "s3-website.us-east-2.amazonaws.com", 4, true}, + {1, "s3.dualstack.us-gov-east-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.us-gov-east-1.amazonaws.com", 5, true}, + {1, "s3.us-gov-east-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.us-gov-east-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.us-gov-east-1.amazonaws.com", 4, true}, + {1, "s3-fips.us-gov-east-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.us-gov-east-1.amazonaws.com", 4, true}, + {1, "s3-website.us-gov-east-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.us-gov-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.us-gov-west-1.amazonaws.com", 5, true}, + {1, "s3.us-gov-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.us-gov-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.us-gov-west-1.amazonaws.com", 4, true}, + {1, "s3-fips.us-gov-west-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.us-gov-west-1.amazonaws.com", 4, true}, + {1, "s3-website.us-gov-west-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.us-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.us-west-1.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.us-west-1.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.us-west-1.amazonaws.com", 5, true}, + {1, "s3.us-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint.us-west-1.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.us-west-1.amazonaws.com", 4, true}, + {1, "s3-fips.us-west-1.amazonaws.com", 4, true}, + {1, "s3-object-lambda.us-west-1.amazonaws.com", 4, true}, + {1, "s3-website.us-west-1.amazonaws.com", 4, true}, + {1, "s3.dualstack.us-west-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint.dualstack.us-west-2.amazonaws.com", 5, true}, + {1, "s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com", 5, true}, + {1, "s3-fips.dualstack.us-west-2.amazonaws.com", 5, true}, + {1, "s3-website.dualstack.us-west-2.amazonaws.com", 5, true}, + {1, "s3.us-west-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint.us-west-2.amazonaws.com", 4, true}, + {1, "s3-accesspoint-fips.us-west-2.amazonaws.com", 4, true}, + {1, "s3-deprecated.us-west-2.amazonaws.com", 4, true}, + {1, "s3-fips.us-west-2.amazonaws.com", 4, true}, + {1, "s3-object-lambda.us-west-2.amazonaws.com", 4, true}, + {1, "s3-website.us-west-2.amazonaws.com", 4, true}, + {1, "notebook.af-south-1.sagemaker.aws", 4, true}, + {1, "notebook.ap-east-1.sagemaker.aws", 4, true}, + {1, "notebook.ap-northeast-1.sagemaker.aws", 4, true}, + {1, "notebook.ap-northeast-2.sagemaker.aws", 4, true}, + {1, "notebook.ap-northeast-3.sagemaker.aws", 4, true}, + {1, "notebook.ap-south-1.sagemaker.aws", 4, true}, + {1, "notebook.ap-south-2.sagemaker.aws", 4, true}, + {1, "notebook.ap-southeast-1.sagemaker.aws", 4, true}, + {1, "notebook.ap-southeast-2.sagemaker.aws", 4, true}, + {1, "notebook.ap-southeast-3.sagemaker.aws", 4, true}, + {1, "notebook.ap-southeast-4.sagemaker.aws", 4, true}, + {1, "notebook.ca-central-1.sagemaker.aws", 4, true}, + {1, "notebook-fips.ca-central-1.sagemaker.aws", 4, true}, + {1, "notebook.ca-west-1.sagemaker.aws", 4, true}, + {1, "notebook-fips.ca-west-1.sagemaker.aws", 4, true}, + {1, "notebook.eu-central-1.sagemaker.aws", 4, true}, + {1, "notebook.eu-central-2.sagemaker.aws", 4, true}, + {1, "notebook.eu-north-1.sagemaker.aws", 4, true}, + {1, "notebook.eu-south-1.sagemaker.aws", 4, true}, + {1, "notebook.eu-south-2.sagemaker.aws", 4, true}, + {1, "notebook.eu-west-1.sagemaker.aws", 4, true}, + {1, "notebook.eu-west-2.sagemaker.aws", 4, true}, + {1, "notebook.eu-west-3.sagemaker.aws", 4, true}, + {1, "notebook.il-central-1.sagemaker.aws", 4, true}, + {1, "notebook.me-central-1.sagemaker.aws", 4, true}, + {1, "notebook.me-south-1.sagemaker.aws", 4, true}, + {1, "notebook.sa-east-1.sagemaker.aws", 4, true}, + {1, "notebook.us-east-1.sagemaker.aws", 4, true}, + {1, "notebook-fips.us-east-1.sagemaker.aws", 4, true}, + {1, "notebook.us-east-2.sagemaker.aws", 4, true}, + {1, "notebook-fips.us-east-2.sagemaker.aws", 4, true}, + {1, "notebook.us-gov-east-1.sagemaker.aws", 4, true}, + {1, "notebook-fips.us-gov-east-1.sagemaker.aws", 4, true}, + {1, "notebook.us-gov-west-1.sagemaker.aws", 4, true}, + {1, "notebook-fips.us-gov-west-1.sagemaker.aws", 4, true}, + {1, "notebook.us-west-1.sagemaker.aws", 4, true}, + {1, "notebook.us-west-2.sagemaker.aws", 4, true}, + {1, "notebook-fips.us-west-2.sagemaker.aws", 4, true}, + {1, "notebook.cn-north-1.sagemaker.com.cn", 5, true}, + {1, "notebook.cn-northwest-1.sagemaker.com.cn", 5, true}, + {1, "studio.af-south-1.sagemaker.aws", 4, true}, + {1, "studio.ap-east-1.sagemaker.aws", 4, true}, + {1, "studio.ap-northeast-1.sagemaker.aws", 4, true}, + {1, "studio.ap-northeast-2.sagemaker.aws", 4, true}, + {1, "studio.ap-northeast-3.sagemaker.aws", 4, true}, + {1, "studio.ap-south-1.sagemaker.aws", 4, true}, + {1, "studio.ap-southeast-1.sagemaker.aws", 4, true}, + {1, "studio.ap-southeast-2.sagemaker.aws", 4, true}, + {1, "studio.ap-southeast-3.sagemaker.aws", 4, true}, + {1, "studio.ca-central-1.sagemaker.aws", 4, true}, + {1, "studio.eu-central-1.sagemaker.aws", 4, true}, + {1, "studio.eu-north-1.sagemaker.aws", 4, true}, + {1, "studio.eu-south-1.sagemaker.aws", 4, true}, + {1, "studio.eu-west-1.sagemaker.aws", 4, true}, + {1, "studio.eu-west-2.sagemaker.aws", 4, true}, + {1, "studio.eu-west-3.sagemaker.aws", 4, true}, + {1, "studio.il-central-1.sagemaker.aws", 4, true}, + {1, "studio.me-central-1.sagemaker.aws", 4, true}, + {1, "studio.me-south-1.sagemaker.aws", 4, true}, + {1, "studio.sa-east-1.sagemaker.aws", 4, true}, + {1, "studio.us-east-1.sagemaker.aws", 4, true}, + {1, "studio.us-east-2.sagemaker.aws", 4, true}, + {1, "studio.us-gov-east-1.sagemaker.aws", 4, true}, + {1, "studio-fips.us-gov-east-1.sagemaker.aws", 4, true}, + {1, "studio.us-gov-west-1.sagemaker.aws", 4, true}, + {1, "studio-fips.us-gov-west-1.sagemaker.aws", 4, true}, + {1, "studio.us-west-1.sagemaker.aws", 4, true}, + {1, "studio.us-west-2.sagemaker.aws", 4, true}, + {1, "studio.cn-north-1.sagemaker.com.cn", 5, true}, + {1, "studio.cn-northwest-1.sagemaker.com.cn", 5, true}, {1, "analytics-gateway.ap-northeast-1.amazonaws.com", 4, true}, + {1, "analytics-gateway.ap-northeast-2.amazonaws.com", 4, true}, + {1, "analytics-gateway.ap-south-1.amazonaws.com", 4, true}, + {1, "analytics-gateway.ap-southeast-1.amazonaws.com", 4, true}, + {1, "analytics-gateway.ap-southeast-2.amazonaws.com", 4, true}, + {1, "analytics-gateway.eu-central-1.amazonaws.com", 4, true}, {1, "analytics-gateway.eu-west-1.amazonaws.com", 4, true}, {1, "analytics-gateway.us-east-1.amazonaws.com", 4, true}, {1, "analytics-gateway.us-east-2.amazonaws.com", 4, true}, {1, "analytics-gateway.us-west-2.amazonaws.com", 4, true}, + {2, "amplifyapp.com", 3, true}, + {2, "awsapprunner.com", 3, true}, {1, "webview-assets.aws-cloud9.af-south-1.amazonaws.com", 5, true}, {1, "vfs.cloud9.af-south-1.amazonaws.com", 5, true}, {1, "webview-assets.cloud9.af-south-1.amazonaws.com", 5, true}, @@ -7056,6 +7507,8 @@ var r = [9106]Rule{ {1, "webview-assets.aws-cloud9.eu-west-3.amazonaws.com", 5, true}, {1, "vfs.cloud9.eu-west-3.amazonaws.com", 5, true}, {1, "webview-assets.cloud9.eu-west-3.amazonaws.com", 5, true}, + {1, "webview-assets.aws-cloud9.il-central-1.amazonaws.com", 5, true}, + {1, "vfs.cloud9.il-central-1.amazonaws.com", 5, true}, {1, "webview-assets.aws-cloud9.me-south-1.amazonaws.com", 5, true}, {1, "vfs.cloud9.me-south-1.amazonaws.com", 5, true}, {1, "webview-assets.cloud9.me-south-1.amazonaws.com", 5, true}, @@ -7077,31 +7530,41 @@ var r = [9106]Rule{ {1, "cn-north-1.eb.amazonaws.com.cn", 5, true}, {1, "cn-northwest-1.eb.amazonaws.com.cn", 5, true}, {1, "elasticbeanstalk.com", 2, true}, + {1, "af-south-1.elasticbeanstalk.com", 3, true}, + {1, "ap-east-1.elasticbeanstalk.com", 3, true}, {1, "ap-northeast-1.elasticbeanstalk.com", 3, true}, {1, "ap-northeast-2.elasticbeanstalk.com", 3, true}, {1, "ap-northeast-3.elasticbeanstalk.com", 3, true}, {1, "ap-south-1.elasticbeanstalk.com", 3, true}, {1, "ap-southeast-1.elasticbeanstalk.com", 3, true}, {1, "ap-southeast-2.elasticbeanstalk.com", 3, true}, + {1, "ap-southeast-3.elasticbeanstalk.com", 3, true}, {1, "ca-central-1.elasticbeanstalk.com", 3, true}, {1, "eu-central-1.elasticbeanstalk.com", 3, true}, + {1, "eu-north-1.elasticbeanstalk.com", 3, true}, + {1, "eu-south-1.elasticbeanstalk.com", 3, true}, {1, "eu-west-1.elasticbeanstalk.com", 3, true}, {1, "eu-west-2.elasticbeanstalk.com", 3, true}, {1, "eu-west-3.elasticbeanstalk.com", 3, true}, + {1, "il-central-1.elasticbeanstalk.com", 3, true}, + {1, "me-south-1.elasticbeanstalk.com", 3, true}, {1, "sa-east-1.elasticbeanstalk.com", 3, true}, {1, "us-east-1.elasticbeanstalk.com", 3, true}, {1, "us-east-2.elasticbeanstalk.com", 3, true}, + {1, "us-gov-east-1.elasticbeanstalk.com", 3, true}, {1, "us-gov-west-1.elasticbeanstalk.com", 3, true}, {1, "us-west-1.elasticbeanstalk.com", 3, true}, {1, "us-west-2.elasticbeanstalk.com", 3, true}, {2, "elb.amazonaws.com.cn", 5, true}, {2, "elb.amazonaws.com", 4, true}, {1, "awsglobalaccelerator.com", 2, true}, + {2, "private.repost.aws", 4, true}, {1, "eero.online", 2, true}, {1, "eero-stage.online", 2, true}, {1, "t3l3p0rt.net", 2, true}, {1, "tele.amune.org", 3, true}, {1, "apigee.io", 2, true}, + {1, "panel.dev", 2, true}, {1, "siiites.com", 2, true}, {1, "appspacehosted.com", 2, true}, {1, "appspaceusercontent.com", 2, true}, @@ -7143,6 +7606,7 @@ var r = [9106]Rule{ {1, "base.shop", 2, true}, {1, "beagleboard.io", 2, true}, {2, "beget.app", 3, true}, + {1, "pages.gay", 2, true}, {1, "betainabox.com", 2, true}, {1, "bnr.la", 2, true}, {1, "bitbucket.io", 2, true}, @@ -7158,6 +7622,7 @@ var r = [9106]Rule{ {1, "square7.de", 2, true}, {1, "bplaced.net", 2, true}, {1, "square7.net", 2, true}, + {2, "s.brave.io", 4, true}, {1, "shop.brendly.rs", 3, true}, {1, "browsersafetymark.io", 2, true}, {1, "uk0.bigv.io", 3, true}, @@ -7279,6 +7744,7 @@ var r = [9106]Rule{ {1, "feste-ip.net", 2, true}, {1, "knx-server.net", 2, true}, {1, "static-access.net", 2, true}, + {2, "cprapid.com", 3, true}, {1, "realm.cz", 2, true}, {2, "cryptonomic.net", 3, true}, {1, "cupcake.is", 2, true}, @@ -7287,6 +7753,10 @@ var r = [9106]Rule{ {2, "oci.customer-oci.com", 4, true}, {2, "ocp.customer-oci.com", 4, true}, {2, "ocs.customer-oci.com", 4, true}, + {1, "cyclic.app", 2, true}, + {1, "cyclic.cloud", 2, true}, + {1, "cyclic-app.com", 2, true}, + {1, "cyclic.co.in", 3, true}, {1, "cyon.link", 2, true}, {1, "cyon.site", 2, true}, {1, "fnwk.site", 2, true}, @@ -7733,7 +8203,6 @@ var r = [9106]Rule{ {1, "mymailer.com.tw", 3, true}, {1, "url.tw", 2, true}, {1, "onfabrica.com", 2, true}, - {1, "apps.fbsbx.com", 3, true}, {1, "ru.net", 2, true}, {1, "adygeya.ru", 2, true}, {1, "bashkiria.ru", 2, true}, @@ -7848,6 +8317,7 @@ var r = [9106]Rule{ {1, "flap.id", 2, true}, {1, "onflashdrive.app", 2, true}, {1, "fldrv.com", 2, true}, + {1, "flutterflow.app", 2, true}, {1, "fly.dev", 2, true}, {1, "edgeapp.net", 2, true}, {1, "shw.io", 2, true}, @@ -7880,6 +8350,7 @@ var r = [9106]Rule{ {2, "ex.ortsinfo.at", 4, true}, {2, "kunden.ortsinfo.at", 4, true}, {2, "statics.cloud", 3, true}, + {1, "aliases121.com", 2, true}, {1, "independent-commission.uk", 2, true}, {1, "independent-inquest.uk", 2, true}, {1, "independent-inquiry.uk", 2, true}, @@ -8018,11 +8489,9 @@ var r = [9106]Rule{ {1, "cloudapps.digital", 2, true}, {1, "london.cloudapps.digital", 3, true}, {1, "pymnt.uk", 2, true}, - {1, "homeoffice.gov.uk", 3, true}, {1, "ro.im", 2, true}, {1, "goip.de", 2, true}, - {1, "run.app", 2, true}, - {1, "a.run.app", 3, true}, + {2, "run.app", 3, true}, {1, "web.app", 2, true}, {2, "0emm.com", 3, true}, {1, "appspot.com", 2, true}, @@ -8138,6 +8607,9 @@ var r = [9106]Rule{ {1, "development.run", 2, true}, {1, "ravendb.run", 2, true}, {1, "homesklep.pl", 2, true}, + {2, "kin.one", 3, true}, + {2, "id.pub", 3, true}, + {2, "kin.pub", 3, true}, {1, "secaas.hk", 2, true}, {1, "hoplix.shop", 2, true}, {1, "orx.biz", 2, true}, @@ -8401,6 +8873,8 @@ var r = [9106]Rule{ {1, "miniserver.com", 2, true}, {1, "memset.net", 2, true}, {1, "messerli.app", 2, true}, + {1, "atmeta.com", 2, true}, + {1, "apps.fbsbx.com", 3, true}, {2, "cloud.metacentrum.cz", 4, true}, {1, "custom.metacentrum.cz", 3, true}, {1, "flt.cloud.muni.cz", 4, true}, @@ -8409,18 +8883,29 @@ var r = [9106]Rule{ {1, "eu.meteorapp.com", 3, true}, {1, "co.pl", 2, true}, {2, "azurecontainer.io", 3, true}, + {2, "cloudapp.azure.com", 4, true}, + {1, "azure-api.net", 2, true}, + {1, "azureedge.net", 2, true}, + {1, "azurefd.net", 2, true}, {1, "azurewebsites.net", 2, true}, {1, "azure-mobile.net", 2, true}, - {1, "cloudapp.net", 2, true}, {1, "azurestaticapps.net", 2, true}, {1, "1.azurestaticapps.net", 3, true}, {1, "2.azurestaticapps.net", 3, true}, {1, "3.azurestaticapps.net", 3, true}, + {1, "4.azurestaticapps.net", 3, true}, + {1, "5.azurestaticapps.net", 3, true}, + {1, "6.azurestaticapps.net", 3, true}, + {1, "7.azurestaticapps.net", 3, true}, {1, "centralus.azurestaticapps.net", 3, true}, {1, "eastasia.azurestaticapps.net", 3, true}, {1, "eastus2.azurestaticapps.net", 3, true}, {1, "westeurope.azurestaticapps.net", 3, true}, {1, "westus2.azurestaticapps.net", 3, true}, + {1, "cloudapp.net", 2, true}, + {1, "trafficmanager.net", 2, true}, + {1, "blob.core.windows.net", 4, true}, + {1, "servicebus.windows.net", 3, true}, {1, "csx.cc", 2, true}, {1, "mintere.site", 2, true}, {1, "forte.id", 2, true}, @@ -8459,6 +8944,7 @@ var r = [9106]Rule{ {1, "sa.ngrok.io", 3, true}, {1, "us.ngrok.io", 3, true}, {1, "ngrok.pizza", 2, true}, + {1, "torun.pl", 2, true}, {1, "nh-serv.co.uk", 3, true}, {1, "nfshost.com", 2, true}, {2, "developer.app", 3, true}, @@ -8646,7 +9132,8 @@ var r = [9106]Rule{ {1, "perspecta.cloud", 2, true}, {1, "lk3.ru", 2, true}, {1, "on-web.fr", 2, true}, - {1, "bc.platform.sh", 3, true}, + {2, "upsun.app", 3, true}, + {1, "upsunapp.com", 2, true}, {1, "ent.platform.sh", 3, true}, {1, "eu.platform.sh", 3, true}, {1, "us.platform.sh", 3, true}, @@ -8658,6 +9145,7 @@ var r = [9106]Rule{ {1, "pdns.page", 2, true}, {1, "plesk.page", 2, true}, {1, "pleskns.com", 2, true}, + {1, "pley.games", 2, true}, {1, "dyn53.io", 2, true}, {1, "onporter.run", 2, true}, {1, "co.bn", 2, true}, @@ -8777,12 +9265,14 @@ var r = [9106]Rule{ {2, "builder.code.com", 4, true}, {2, "dev-builder.code.com", 4, true}, {2, "stg-builder.code.com", 4, true}, + {2, "001.test.code-builder-stg.platform.salesforce.com", 7, true}, {1, "sandcats.io", 2, true}, {1, "logoip.de", 2, true}, {1, "logoip.com", 2, true}, {1, "fr-par-1.baremetal.scw.cloud", 4, true}, {1, "fr-par-2.baremetal.scw.cloud", 4, true}, {1, "nl-ams-1.baremetal.scw.cloud", 4, true}, + {1, "cockpit.fr-par.scw.cloud", 4, true}, {1, "fnc.fr-par.scw.cloud", 4, true}, {1, "functions.fnc.fr-par.scw.cloud", 5, true}, {1, "k8s.fr-par.scw.cloud", 4, true}, @@ -8793,11 +9283,13 @@ var r = [9106]Rule{ {1, "priv.instances.scw.cloud", 4, true}, {1, "pub.instances.scw.cloud", 4, true}, {1, "k8s.scw.cloud", 3, true}, + {1, "cockpit.nl-ams.scw.cloud", 4, true}, {1, "k8s.nl-ams.scw.cloud", 4, true}, {1, "nodes.k8s.nl-ams.scw.cloud", 5, true}, {1, "s3.nl-ams.scw.cloud", 4, true}, {1, "s3-website.nl-ams.scw.cloud", 4, true}, {1, "whm.nl-ams.scw.cloud", 4, true}, + {1, "cockpit.pl-waw.scw.cloud", 4, true}, {1, "k8s.pl-waw.scw.cloud", 4, true}, {1, "nodes.k8s.pl-waw.scw.cloud", 5, true}, {1, "s3.pl-waw.scw.cloud", 4, true}, @@ -8844,6 +9336,16 @@ var r = [9106]Rule{ {1, "bounty-full.com", 2, true}, {1, "alpha.bounty-full.com", 3, true}, {1, "beta.bounty-full.com", 3, true}, + {1, "aeroport.fr", 2, true}, + {1, "avocat.fr", 2, true}, + {1, "chambagri.fr", 2, true}, + {1, "chirurgiens-dentistes.fr", 2, true}, + {1, "experts-comptables.fr", 2, true}, + {1, "medecin.fr", 2, true}, + {1, "notaires.fr", 2, true}, + {1, "pharmacien.fr", 2, true}, + {1, "port.fr", 2, true}, + {1, "veterinaire.fr", 2, true}, {1, "small-web.org", 2, true}, {1, "vp4.me", 2, true}, {1, "snowflake.app", 2, true}, @@ -9035,7 +9537,6 @@ var r = [9106]Rule{ {1, "to.gt", 2, true}, {1, "be.gy", 2, true}, {1, "cc.hn", 2, true}, - {1, "blog.kg", 2, true}, {1, "io.kg", 2, true}, {1, "jp.kg", 2, true}, {1, "tv.kg", 2, true}, @@ -9088,6 +9589,8 @@ var r = [9106]Rule{ {1, "js.wpenginepowered.com", 3, true}, {1, "wixsite.com", 2, true}, {1, "editorx.io", 2, true}, + {1, "wixstudio.io", 2, true}, + {1, "wix.run", 2, true}, {1, "half.host", 2, true}, {1, "xnbay.com", 2, true}, {1, "u2.xnbay.com", 3, true}, @@ -9112,6 +9615,7 @@ var r = [9106]Rule{ {1, "noho.st", 2, true}, {1, "za.net", 2, true}, {1, "za.org", 2, true}, + {1, "zap.cloud", 2, true}, {1, "bss.design", 2, true}, {1, "basicserver.io", 2, true}, {1, "virtualserver.io", 2, true}, diff --git a/vendor/modules.txt b/vendor/modules.txt index 6608bfe6058..fd87b594c73 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -259,7 +259,7 @@ github.com/redis/go-redis/v9/internal/util # github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 ## explicit github.com/titanous/rocacheck -# github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 +# github.com/weppos/publicsuffix-go v0.30.2-0.20240219083929-48f3a5ae027a ## explicit; go 1.16 github.com/weppos/publicsuffix-go/publicsuffix # github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c From 313e3b93ba67ce9ade7b65290e54b3f1ed0d7d77 Mon Sep 17 00:00:00 2001 From: Matthew McPherrin Date: Fri, 23 Feb 2024 17:45:01 -0500 Subject: [PATCH 02/17] Add DNSStaticResolver option (#7336) We run the RVAs in AWS, where we don't have all the same service discovery infrastructure we do for the primary VAs and the rest of Boulder. The solution for populating SRV records we have today hasn't been reliable, so we'd like to experiment with bringing up RVAs paired 1:1 with a local DNS resolver. This brings back some of the previous static DNS resolver configuration, though it's not a clean revert because other configuration has changed in the meantime --- cmd/boulder-va/main.go | 24 +++++++++++++++--------- test/config-next/va-remote-a.json | 11 ++++------- test/config-next/va-remote-b.json | 11 ++++------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cmd/boulder-va/main.go b/cmd/boulder-va/main.go index 495acf82364..0bef1d4f1d1 100644 --- a/cmd/boulder-va/main.go +++ b/cmd/boulder-va/main.go @@ -26,9 +26,13 @@ type Config struct { // DNSTries is the number of times to try a DNS query (that has a temporary error) // before giving up. May be short-circuited by deadlines. A zero value // will be turned into 1. - DNSTries int - DNSProvider *cmd.DNSProvider `validate:"required"` - DNSTimeout config.Duration `validate:"required"` + DNSTries int + DNSProvider *cmd.DNSProvider `validate:"required_without=DNSStaticResolvers"` + // DNSStaticResolvers is a list of DNS resolvers. Each entry must + // be a host or IP and port separated by a colon. IPv6 addresses + // must be enclosed in square brackets. + DNSStaticResolvers []string `validate:"required_without=DNSProvider,dive,hostname_port"` + DNSTimeout config.Duration `validate:"required"` DNSAllowLoopbackAddresses bool RemoteVAs []cmd.GRPCClientConfig `validate:"omitempty,dive"` @@ -79,17 +83,19 @@ func main() { } clk := cmd.Clock() - if c.VA.DNSProvider == nil { - cmd.Fail("Must specify dnsProvider") - } - var servers bdns.ServerProvider proto := "udp" if features.Get().DOH { proto = "tcp" } - servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, proto) - cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver") + + if len(c.VA.DNSStaticResolvers) != 0 { + servers, err = bdns.NewStaticProvider(c.VA.DNSStaticResolvers) + cmd.FailOnError(err, "Couldn't start static DNS server resolver") + } else { + servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, proto) + cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver") + } defer servers.Stop() tlsConfig, err := c.VA.TLS.Load(scope) diff --git a/test/config-next/va-remote-a.json b/test/config-next/va-remote-a.json index 32a535346e1..6b2c2c23bff 100644 --- a/test/config-next/va-remote-a.json +++ b/test/config-next/va-remote-a.json @@ -2,13 +2,10 @@ "va": { "userAgent": "boulder-remote-a", "dnsTries": 3, - "dnsProvider": { - "dnsAuthority": "consul.service.consul", - "srvLookup": { - "service": "doh", - "domain": "service.consul" - } - }, + "dnsStaticResolvers": [ + "10.77.77.77:8343", + "10.77.77.77:8443" + ], "dnsTimeout": "1s", "dnsAllowLoopbackAddresses": true, "issuerDomain": "happy-hacker-ca.invalid", diff --git a/test/config-next/va-remote-b.json b/test/config-next/va-remote-b.json index a694c343e56..de0831dc5e4 100644 --- a/test/config-next/va-remote-b.json +++ b/test/config-next/va-remote-b.json @@ -2,13 +2,10 @@ "va": { "userAgent": "boulder-remote-b", "dnsTries": 3, - "dnsProvider": { - "dnsAuthority": "consul.service.consul", - "srvLookup": { - "service": "doh", - "domain": "service.consul" - } - }, + "dnsStaticResolvers": [ + "10.77.77.77:8343", + "10.77.77.77:8443" + ], "dnsTimeout": "1s", "dnsAllowLoopbackAddresses": true, "issuerDomain": "happy-hacker-ca.invalid", From 34b705f29348930ab6f6ac3c8b70f3dcdd061e24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 10:31:30 -0500 Subject: [PATCH 03/17] build(deps): bump github.com/aws/aws-sdk-go-v2/service/s3 from 1.48.0 to 1.50.2 (#7333) Bumps [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) from 1.48.0 to 1.50.2. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 22 +++++----- go.sum | 44 +++++++++---------- .../aws-sdk-go-v2/aws/go_module_metadata.go | 2 +- .../aws/protocol/eventstream/CHANGELOG.md | 4 ++ .../eventstream/go_module_metadata.go | 2 +- .../internal/configsources/CHANGELOG.md | 5 +++ .../configsources/go_module_metadata.go | 2 +- .../internal/endpoints/v2/CHANGELOG.md | 5 +++ .../endpoints/v2/go_module_metadata.go | 2 +- .../aws-sdk-go-v2/internal/v4a/CHANGELOG.md | 5 +++ .../internal/v4a/go_module_metadata.go | 2 +- .../internal/accept-encoding/CHANGELOG.md | 4 ++ .../accept-encoding/go_module_metadata.go | 2 +- .../service/internal/checksum/CHANGELOG.md | 5 +++ .../internal/checksum/go_module_metadata.go | 2 +- .../internal/presigned-url/CHANGELOG.md | 5 +++ .../presigned-url/go_module_metadata.go | 2 +- .../service/internal/s3shared/CHANGELOG.md | 5 +++ .../internal/s3shared/go_module_metadata.go | 2 +- .../aws/aws-sdk-go-v2/service/s3/CHANGELOG.md | 21 +++++++++ .../aws-sdk-go-v2/service/s3/api_client.go | 36 +-------------- .../service/s3/api_op_HeadBucket.go | 24 ++++++++++ .../service/s3/api_op_HeadObject.go | 24 ++++++++++ .../service/s3/endpoint_auth_resolver.go | 11 +++++ .../aws/aws-sdk-go-v2/service/s3/endpoints.go | 9 +++- .../service/s3/express_resolve.go | 9 +--- .../service/s3/go_module_metadata.go | 2 +- .../internal/customizations/signer_wrapper.go | 13 +++--- vendor/github.com/aws/smithy-go/.gitignore | 3 ++ vendor/github.com/aws/smithy-go/CHANGELOG.md | 7 +++ vendor/github.com/aws/smithy-go/Makefile | 7 ++- .../aws/smithy-go/go_module_metadata.go | 2 +- vendor/modules.txt | 44 +++++++++---------- 33 files changed, 217 insertions(+), 117 deletions(-) diff --git a/go.mod b/go.mod index 6e97ea2ece4..1ea1774ca25 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/letsencrypt/boulder go 1.21 require ( - github.com/aws/aws-sdk-go-v2 v1.24.1 + github.com/aws/aws-sdk-go-v2 v1.25.0 github.com/aws/aws-sdk-go-v2/config v1.26.3 - github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0 - github.com/aws/smithy-go v1.19.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.50.2 + github.com/aws/smithy-go v1.20.0 github.com/eggsampler/acme/v3 v3.4.0 github.com/go-logr/stdr v1.2.2 github.com/go-sql-driver/mysql v1.5.0 @@ -48,17 +48,17 @@ require ( require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.0 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.16.14 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.18.6 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect diff --git a/go.sum b/go.sum index 1361046c418..d360869e9e7 100644 --- a/go.sum +++ b/go.sum @@ -12,42 +12,42 @@ github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= -github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo= +github.com/aws/aws-sdk-go-v2 v1.25.0 h1:sv7+1JVJxOu/dD/sz/csHX7jFqmP001TIY7aytBWDSQ= +github.com/aws/aws-sdk-go-v2 v1.25.0/go.mod h1:G104G1Aho5WqF+SR3mDIobTABQzpYV0WxMsKxlMggOA= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.0 h1:2UO6/nT1lCZq1LqM67Oa4tdgP1CvL1sLSxvuD+VrOeE= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.0/go.mod h1:5zGj2eA85ClyedTDK+Whsu+w9yimnVIZvhvBKrDquM8= github.com/aws/aws-sdk-go-v2/config v1.26.3 h1:dKuc2jdp10y13dEEvPqWxqLoc0vF3Z9FC45MvuQSxOA= github.com/aws/aws-sdk-go-v2/config v1.26.3/go.mod h1:Bxgi+DeeswYofcYO0XyGClwlrq3DZEXli0kLf4hkGA0= github.com/aws/aws-sdk-go-v2/credentials v1.16.14 h1:mMDTwwYO9A0/JbOCOG7EOZHtYM+o7OfGWfu0toa23VE= github.com/aws/aws-sdk-go-v2/credentials v1.16.14/go.mod h1:cniAUh3ErQPHtCQGPT5ouvSAQ0od8caTO9OOuufZOAE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 h1:NPs/EqVO+ajwOoq56EfcGKa3L3ruWuazkIw1BqxwOPw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0/go.mod h1:D+duLy2ylgatV+yTlQ8JTuLfDD0BnFvnQRc+o6tbZ4M= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 h1:ks7KGMVUMoDzcxNWUlEdI+/lokMFD136EL6DWmUOV80= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0/go.mod h1:hL6BWM/d/qz113fVitZjbXR0E+RCTU1+x+1Idyn5NgE= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 h1:5oE2WzJE56/mVveuDZPJESKlg/00AaS2pY2QZcnxg4M= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10/go.mod h1:FHbKWQtRBYUz4vO5WBWjzMD2by126ny5y/1EoaWoLfI= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 h1:L0ai8WICYHozIKK+OtPzVJBugL7culcuM4E4JOpIEm8= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10/go.mod h1:byqfyxJBshFk0fF9YmK0M0ugIO8OWjzH2T3bPG4eGuA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 h1:KOxnQeWy5sXyS37fdKEvAsGHOr9fa/qvwxfJurR/BzE= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10/go.mod h1:jMx5INQFYFYB3lQD9W0D8Ohgq6Wnl7NYOJ2TQndbulI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0 h1:PJTdBMsyvra6FtED7JZtDpQrIAflYDHFoZAu/sKYkwU= -github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0/go.mod h1:4qXHrG1Ne3VGIMZPCB8OjH/pLFO94sKABIusjh0KWPU= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.0 h1:TkbRExyKSVHELwG9gz2+gql37jjec2R5vus9faTomwE= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.0/go.mod h1:T3/9xMKudHhnj8it5EqIrhvv11tVZqWYkKcot+BFStc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.0 h1:a33HuFlO0KsveiP90IUJh8Xr/cx9US2PqkSroaLc+o8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.0/go.mod h1:SxIkWpByiGbhbHYTo9CMTUnx2G4p4ZQMrDPcRRy//1c= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.0 h1:UiSyK6ent6OKpkMJN3+k5HZ4sk4UfchEaaW5wv7SblQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.0/go.mod h1:l7kzl8n8DXoRyFz5cIMG70HnPauWa649TUhgw8Rq6lo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.0 h1:SHN/umDLTmFTmYfI+gkanz6da3vK8Kvj/5wkqnTHbuA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.0/go.mod h1:l8gPU5RYGOFHJqWEpPMoRTP0VoaWQSkJdKo+hwWnnDA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.0 h1:l5puwOHr7IxECuPMIuZG7UKOzAnF24v6t4l+Z5Moay4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.0/go.mod h1:Oov79flWa/n7Ni+lQC3z+VM7PoRM47omRqbJU9B5Y7E= +github.com/aws/aws-sdk-go-v2/service/s3 v1.50.2 h1:UxJGNZ+/VhocG50aui1p7Ub2NjDzijCpg8Y3NuznijM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.50.2/go.mod h1:1o/W6JFUuREj2ExoQ21vHJgO7wakvjhol91M9eknFgs= github.com/aws/aws-sdk-go-v2/service/sso v1.18.6 h1:dGrs+Q/WzhsiUKh82SfTVN66QzyulXuMDTV/G8ZxOac= github.com/aws/aws-sdk-go-v2/service/sso v1.18.6/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 h1:Yf2MIo9x+0tyv76GljxzqA3WtC5mw7NmazD2chwjxE4= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/aws/smithy-go v1.20.0 h1:6+kZsCXZwKxZS9RfISnPc4EXlHoyAkm2hPuM8X2BrrQ= +github.com/aws/smithy-go v1.20.0/go.mod h1:uo5RKksAl4PzhqaAbjd4rLgFoq5koTsQKYuGe7dklGc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go index 66d09630308..2501a2be89f 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go @@ -3,4 +3,4 @@ package aws // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.24.1" +const goModuleVersion = "1.25.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md index 1e1da56b3b9..4b1064a4733 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.6.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. + # v1.5.4 (2023-12-07) * No change notes available for this release. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go index 6759e90e99f..78f3caf8581 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go @@ -3,4 +3,4 @@ package eventstream // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.5.4" +const goModuleVersion = "1.6.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md index dc87ec41027..4c73ce3cafa 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.3.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.2.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go index 41ee0bfbe3e..eb43c377b87 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go @@ -3,4 +3,4 @@ package configsources // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.2.10" +const goModuleVersion = "1.3.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md index e0265474c4f..2e95faf7f5b 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md @@ -1,3 +1,8 @@ +# v2.6.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v2.5.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go index bec2c6a1e9c..19636a7fe97 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go @@ -3,4 +3,4 @@ package endpoints // goModuleVersion is the tagged release for this module -const goModuleVersion = "2.5.10" +const goModuleVersion = "2.6.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md index 8aa94972d34..f6e0446baa1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.3.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.2.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go index 2a5888c1b95..54bf72b8586 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go @@ -3,4 +3,4 @@ package v4a // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.2.10" +const goModuleVersion = "1.3.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md index c3525fd2298..4ebb9d935da 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.11.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. + # v1.10.4 (2023-12-07) * No change notes available for this release. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go index cc6384005aa..534fb48fc4c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go @@ -3,4 +3,4 @@ package acceptencoding // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.10.4" +const goModuleVersion = "1.11.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/CHANGELOG.md index 8f974036174..57aff37618f 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.3.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.2.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/go_module_metadata.go index a88534d2a73..50b862821c6 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/checksum/go_module_metadata.go @@ -3,4 +3,4 @@ package checksum // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.2.10" +const goModuleVersion = "1.3.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md index a65890b58f3..b39fb01a18d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.11.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.10.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go index 073e8866b75..547d0d62443 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go @@ -3,4 +3,4 @@ package presignedurl // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.10.10" +const goModuleVersion = "1.11.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/CHANGELOG.md index c4df2176519..d9872a950bf 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.17.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.16.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/go_module_metadata.go index 986affe186a..fe8dd039e32 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/s3shared/go_module_metadata.go @@ -3,4 +3,4 @@ package s3shared // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.16.10" +const goModuleVersion = "1.17.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/CHANGELOG.md index f83de2a5efe..0ba81ee86ab 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/CHANGELOG.md @@ -1,3 +1,24 @@ +# v1.50.2 (2024-02-20) + +* **Bug Fix**: When sourcing values for a service's `EndpointParameters`, the lack of a configured region (i.e. `options.Region == ""`) will now translate to a `nil` value for `EndpointParameters.Region` instead of a pointer to the empty string `""`. This will result in a much more explicit error when calling an operation instead of an obscure hostname lookup failure. + +# v1.50.1 (2024-02-19) + +* **Bug Fix**: Prevent potential panic caused by invalid comparison of credentials. + +# v1.50.0 (2024-02-16) + +* **Feature**: Add new ClientOptions field to waiter config which allows you to extend the config for operation calls made by waiters. + +# v1.49.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.48.1 (2024-01-24) + +* No change notes available for this release. + # v1.48.0 (2024-01-05) * **Feature**: Support smithy sigv4a trait for codegen. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_client.go index 5e5f27b2d72..db35814d356 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_client.go @@ -56,10 +56,10 @@ func New(options Options, optFns ...func(*Options)) *Client { resolveHTTPSignerV4(&options) - resolveHTTPSignerV4a(&options) - resolveEndpointResolverV2(&options) + resolveHTTPSignerV4a(&options) + resolveAuthSchemeResolver(&options) for _, fn := range optFns { @@ -68,8 +68,6 @@ func New(options Options, optFns ...func(*Options)) *Client { finalizeRetryMaxAttempts(&options) - resolveCredentialProvider(&options) - ignoreAnonymousAuth(&options) resolveExpressCredentials(&options) @@ -111,8 +109,6 @@ func (c *Client) invokeOperation(ctx context.Context, opID string, params interf finalizeClientEndpointResolverOptions(&options) - resolveCredentialProvider(&options) - finalizeOperationExpressCredentials(&options, *c) finalizeOperationEndpointAuthResolver(&options) @@ -496,33 +492,6 @@ func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error { return nil } -func resolveCredentialProvider(o *Options) { - if o.Credentials == nil { - return - } - - if _, ok := o.Credentials.(v4a.CredentialsProvider); ok { - return - } - - if aws.IsCredentialsProvider(o.Credentials, (*aws.AnonymousCredentials)(nil)) { - return - } - - o.Credentials = &v4a.SymmetricCredentialAdaptor{SymmetricProvider: o.Credentials} -} - -func swapWithCustomHTTPSignerMiddleware(stack *middleware.Stack, o Options) error { - mw := s3cust.NewSignHTTPRequestMiddleware(s3cust.SignHTTPRequestMiddlewareOptions{ - CredentialsProvider: o.Credentials, - V4Signer: o.HTTPSignerV4, - V4aSigner: o.httpSignerV4a, - LogSigning: o.ClientLogMode.IsSigning(), - }) - - return s3cust.RegisterSigningMiddleware(stack, mw) -} - type httpSignerV4a interface { SignHTTP(ctx context.Context, credentials v4a.Credentials, r *http.Request, payloadHash, service string, regionSet []string, signingTime time.Time, @@ -540,7 +509,6 @@ func newDefaultV4aSigner(o Options) *v4a.Signer { return v4a.NewSigner(func(so *v4a.SignerOptions) { so.Logger = o.Logger so.LogSigning = o.ClientLogMode.IsSigning() - so.DisableURIPathEscaping = true }) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadBucket.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadBucket.go index 8a18ff851e7..c6d10276d2d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadBucket.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadBucket.go @@ -259,8 +259,17 @@ type BucketExistsWaiterOptions struct { // Set of options to modify how an operation is invoked. These apply to all // operations invoked for this client. Use functional options on operation call to // modify this list for per operation behavior. + // + // Passing options here is functionally equivalent to passing values to this + // config's ClientOptions field that extend the inner client's APIOptions directly. APIOptions []func(*middleware.Stack) error + // Functional options to be passed to all operations invoked by this client. + // + // Function values that modify the inner APIOptions are applied after the waiter + // config's own APIOptions modifiers. + ClientOptions []func(*Options) + // MinDelay is the minimum amount of time to delay between retries. If unset, // BucketExistsWaiter will use default minimum delay of 5 seconds. Note that // MinDelay must resolve to a value lesser than or equal to the MaxDelay. @@ -358,6 +367,9 @@ func (w *BucketExistsWaiter) WaitForOutput(ctx context.Context, params *HeadBuck out, err := w.client.HeadBucket(ctx, params, func(o *Options) { o.APIOptions = append(o.APIOptions, apiOptions...) + for _, opt := range options.ClientOptions { + opt(o) + } }) retryable, err := options.Retryable(ctx, params, out, err) @@ -412,8 +424,17 @@ type BucketNotExistsWaiterOptions struct { // Set of options to modify how an operation is invoked. These apply to all // operations invoked for this client. Use functional options on operation call to // modify this list for per operation behavior. + // + // Passing options here is functionally equivalent to passing values to this + // config's ClientOptions field that extend the inner client's APIOptions directly. APIOptions []func(*middleware.Stack) error + // Functional options to be passed to all operations invoked by this client. + // + // Function values that modify the inner APIOptions are applied after the waiter + // config's own APIOptions modifiers. + ClientOptions []func(*Options) + // MinDelay is the minimum amount of time to delay between retries. If unset, // BucketNotExistsWaiter will use default minimum delay of 5 seconds. Note that // MinDelay must resolve to a value lesser than or equal to the MaxDelay. @@ -512,6 +533,9 @@ func (w *BucketNotExistsWaiter) WaitForOutput(ctx context.Context, params *HeadB out, err := w.client.HeadBucket(ctx, params, func(o *Options) { o.APIOptions = append(o.APIOptions, apiOptions...) + for _, opt := range options.ClientOptions { + opt(o) + } }) retryable, err := options.Retryable(ctx, params, out, err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadObject.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadObject.go index 5f7b55e56ad..ba2b495ba1c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadObject.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/api_op_HeadObject.go @@ -584,8 +584,17 @@ type ObjectExistsWaiterOptions struct { // Set of options to modify how an operation is invoked. These apply to all // operations invoked for this client. Use functional options on operation call to // modify this list for per operation behavior. + // + // Passing options here is functionally equivalent to passing values to this + // config's ClientOptions field that extend the inner client's APIOptions directly. APIOptions []func(*middleware.Stack) error + // Functional options to be passed to all operations invoked by this client. + // + // Function values that modify the inner APIOptions are applied after the waiter + // config's own APIOptions modifiers. + ClientOptions []func(*Options) + // MinDelay is the minimum amount of time to delay between retries. If unset, // ObjectExistsWaiter will use default minimum delay of 5 seconds. Note that // MinDelay must resolve to a value lesser than or equal to the MaxDelay. @@ -683,6 +692,9 @@ func (w *ObjectExistsWaiter) WaitForOutput(ctx context.Context, params *HeadObje out, err := w.client.HeadObject(ctx, params, func(o *Options) { o.APIOptions = append(o.APIOptions, apiOptions...) + for _, opt := range options.ClientOptions { + opt(o) + } }) retryable, err := options.Retryable(ctx, params, out, err) @@ -737,8 +749,17 @@ type ObjectNotExistsWaiterOptions struct { // Set of options to modify how an operation is invoked. These apply to all // operations invoked for this client. Use functional options on operation call to // modify this list for per operation behavior. + // + // Passing options here is functionally equivalent to passing values to this + // config's ClientOptions field that extend the inner client's APIOptions directly. APIOptions []func(*middleware.Stack) error + // Functional options to be passed to all operations invoked by this client. + // + // Function values that modify the inner APIOptions are applied after the waiter + // config's own APIOptions modifiers. + ClientOptions []func(*Options) + // MinDelay is the minimum amount of time to delay between retries. If unset, // ObjectNotExistsWaiter will use default minimum delay of 5 seconds. Note that // MinDelay must resolve to a value lesser than or equal to the MaxDelay. @@ -837,6 +858,9 @@ func (w *ObjectNotExistsWaiter) WaitForOutput(ctx context.Context, params *HeadO out, err := w.client.HeadObject(ctx, params, func(o *Options) { o.APIOptions = append(o.APIOptions, apiOptions...) + for _, opt := range options.ClientOptions { + opt(o) + } }) retryable, err := options.Retryable(ctx, params, out, err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoint_auth_resolver.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoint_auth_resolver.go index 91af48fc0de..bb5f4cf47af 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoint_auth_resolver.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoint_auth_resolver.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/aws/aws-sdk-go-v2/aws" smithyauth "github.com/aws/smithy-go/auth" ) @@ -18,6 +19,16 @@ func (r *endpointAuthResolver) ResolveAuthSchemes( ) ( []*smithyauth.Option, error, ) { + if params.endpointParams.Region == nil { + // #2502: We're correcting the endpoint binding behavior to treat empty + // Region as "unset" (nil), but auth resolution technically doesn't + // care and someone could be using V1 or non-default V2 endpoint + // resolution, both of which would bypass the required-region check. + // They shouldn't be broken because the region is technically required + // by this service's endpoint-based auth resolver, so we stub it here. + params.endpointParams.Region = aws.String("") + } + opts, err := r.resolveAuthSchemes(ctx, params) if err != nil { return nil, err diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoints.go index a1f2e36d63a..d65b7a86028 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/endpoints.go @@ -228,6 +228,13 @@ func resolveBaseEndpoint(cfg aws.Config, o *Options) { } } +func bindRegion(region string) *string { + if region == "" { + return nil + } + return aws.String(endpoints.MapFIPSRegion(region)) +} + // EndpointParameters provides the parameters that influence how endpoints are // resolved. type EndpointParameters struct { @@ -5668,7 +5675,7 @@ type endpointParamsBinder interface { func bindEndpointParams(input interface{}, options Options) *EndpointParameters { params := &EndpointParameters{} - params.Region = aws.String(endpoints.MapFIPSRegion(options.Region)) + params.Region = bindRegion(options.Region) params.UseFIPS = aws.Bool(options.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled) params.UseDualStack = aws.Bool(options.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled) params.Endpoint = options.BaseEndpoint diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/express_resolve.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/express_resolve.go index 18d6c06ada0..7c7a7b42400 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/express_resolve.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/express_resolve.go @@ -24,14 +24,9 @@ func finalizeExpressCredentials(o *Options, c *Client) { } // Operation config finalizer: update the sigv4 credentials on the default -// express provider if it changed to ensure different cache keys +// express provider in case it changed to ensure different cache keys func finalizeOperationExpressCredentials(o *Options, c Client) { - p, ok := o.ExpressCredentials.(*defaultS3ExpressCredentialsProvider) - if !ok { - return - } - - if c.options.Credentials != o.Credentials { + if p, ok := o.ExpressCredentials.(*defaultS3ExpressCredentialsProvider); ok { o.ExpressCredentials = p.CloneWithBaseCredentials(o.Credentials) } } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/go_module_metadata.go index 77e3ee12fd9..6f55bcd2210 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/go_module_metadata.go @@ -3,4 +3,4 @@ package s3 // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.48.0" +const goModuleVersion = "1.50.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations/signer_wrapper.go b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations/signer_wrapper.go index cc2bf9c1313..756823cb758 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations/signer_wrapper.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations/signer_wrapper.go @@ -182,15 +182,12 @@ func (p *PresignHTTPRequestMiddleware) HandleFinalize( switch signerVersion { case "aws.auth#sigv4a": - v4aCredentialProvider, ok := p.credentialsProvider.(v4a.CredentialsProvider) - if !ok { - return out, metadata, fmt.Errorf("invalid credential-provider provided for sigV4a Signer") - } - mw := v4a.NewPresignHTTPRequestMiddleware(v4a.PresignHTTPRequestMiddlewareOptions{ - CredentialsProvider: v4aCredentialProvider, - Presigner: p.v4aSigner, - LogSigning: p.logSigning, + CredentialsProvider: &v4a.SymmetricCredentialAdaptor{ + SymmetricProvider: p.credentialsProvider, + }, + Presigner: p.v4aSigner, + LogSigning: p.logSigning, }) return mw.HandleFinalize(ctx, in, next) case "aws.auth#sigv4": diff --git a/vendor/github.com/aws/smithy-go/.gitignore b/vendor/github.com/aws/smithy-go/.gitignore index c92d6105eb3..2518b349154 100644 --- a/vendor/github.com/aws/smithy-go/.gitignore +++ b/vendor/github.com/aws/smithy-go/.gitignore @@ -24,3 +24,6 @@ build/ # VS Code bin/ .vscode/ + +# make +c.out diff --git a/vendor/github.com/aws/smithy-go/CHANGELOG.md b/vendor/github.com/aws/smithy-go/CHANGELOG.md index 46b115083d1..e32eadf7e8c 100644 --- a/vendor/github.com/aws/smithy-go/CHANGELOG.md +++ b/vendor/github.com/aws/smithy-go/CHANGELOG.md @@ -1,3 +1,10 @@ +# Release (2024-02-13) + +## Module Highlights +* `github.com/aws/smithy-go`: v1.20.0 + * **Feature**: Add codegen definition for sigv4a trait. + * **Feature**: Bump minimum Go version to 1.20 per our language support policy. + # Release (2023-12-07) ## Module Highlights diff --git a/vendor/github.com/aws/smithy-go/Makefile b/vendor/github.com/aws/smithy-go/Makefile index 4b3c209373c..e66fa8caceb 100644 --- a/vendor/github.com/aws/smithy-go/Makefile +++ b/vendor/github.com/aws/smithy-go/Makefile @@ -33,13 +33,18 @@ smithy-clean: ################## # Linting/Verify # ################## -.PHONY: verify vet +.PHONY: verify vet cover verify: vet vet: go vet ${BUILD_TAGS} --all ./... +cover: + go test ${BUILD_TAGS} -coverprofile c.out ./... + @cover=`go tool cover -func c.out | grep '^total:' | awk '{ print $$3+0 }'`; \ + echo "total (statements): $$cover%"; + ################ # Unit Testing # ################ diff --git a/vendor/github.com/aws/smithy-go/go_module_metadata.go b/vendor/github.com/aws/smithy-go/go_module_metadata.go index cd6f7fa45c4..7fdb00dfb55 100644 --- a/vendor/github.com/aws/smithy-go/go_module_metadata.go +++ b/vendor/github.com/aws/smithy-go/go_module_metadata.go @@ -3,4 +3,4 @@ package smithy // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.19.0" +const goModuleVersion = "1.20.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index fd87b594c73..3a41bcb3250 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,7 +1,7 @@ # cloud.google.com/go/compute/metadata v0.2.3 ## explicit; go 1.19 -# github.com/aws/aws-sdk-go-v2 v1.24.1 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2 v1.25.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/aws github.com/aws/aws-sdk-go-v2/aws/arn github.com/aws/aws-sdk-go-v2/aws/defaults @@ -27,8 +27,8 @@ github.com/aws/aws-sdk-go-v2/internal/shareddefaults github.com/aws/aws-sdk-go-v2/internal/strings github.com/aws/aws-sdk-go-v2/internal/sync/singleflight github.com/aws/aws-sdk-go-v2/internal/timeconv -# github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi # github.com/aws/aws-sdk-go-v2/config v1.26.3 @@ -47,36 +47,36 @@ github.com/aws/aws-sdk-go-v2/credentials/stscreds ## explicit; go 1.19 github.com/aws/aws-sdk-go-v2/feature/ec2/imds github.com/aws/aws-sdk-go-v2/feature/ec2/imds/internal/config -# github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/internal/configsources -# github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 # github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 ## explicit; go 1.19 github.com/aws/aws-sdk-go-v2/internal/ini -# github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/internal/v4a github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4 -# github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding -# github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/service/internal/checksum -# github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url -# github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.0 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/service/internal/s3shared github.com/aws/aws-sdk-go-v2/service/internal/s3shared/arn github.com/aws/aws-sdk-go-v2/service/internal/s3shared/config -# github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0 -## explicit; go 1.19 +# github.com/aws/aws-sdk-go-v2/service/s3 v1.50.2 +## explicit; go 1.20 github.com/aws/aws-sdk-go-v2/service/s3 github.com/aws/aws-sdk-go-v2/service/s3/internal/arn github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations @@ -97,8 +97,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc/types github.com/aws/aws-sdk-go-v2/service/sts github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints github.com/aws/aws-sdk-go-v2/service/sts/types -# github.com/aws/smithy-go v1.19.0 -## explicit; go 1.19 +# github.com/aws/smithy-go v1.20.0 +## explicit; go 1.20 github.com/aws/smithy-go github.com/aws/smithy-go/auth github.com/aws/smithy-go/auth/bearer From a97e074b5a3e5e29124130042cccb55bbf3cd46e Mon Sep 17 00:00:00 2001 From: Samantha Date: Mon, 26 Feb 2024 16:47:08 -0500 Subject: [PATCH 04/17] WFE/ARI: Add method for tracking certificate replacement (#7298) Implement draft-ietf-acme-ari-02 changes in WFE newOrder: - Add a `replaces` field to the newOrder request object - Ensure that `replaces` values provided by subscribers are vetted according to the requirements set out in the draft specification - When a NewOrder request falls inside the suggested RenewalWindow, exempt from rate limits in the WFE and indicate exemption in the RA NewOrder request Part of #7038 --- core/objects.go | 6 ++ core/objects_test.go | 24 +++++++ wfe2/wfe.go | 155 +++++++++++++++++++++++++++++++++++++------ wfe2/wfe_test.go | 56 ++++++++++++++++ 4 files changed, 219 insertions(+), 22 deletions(-) diff --git a/core/objects.go b/core/objects.go index ab967f424ff..c58aaac0cb7 100644 --- a/core/objects.go +++ b/core/objects.go @@ -500,6 +500,12 @@ type SuggestedWindow struct { End time.Time `json:"end"` } +// IsWithin returns true if the given time is within the suggested window, +// inclusive of the start time and exclusive of the end time. +func (window SuggestedWindow) IsWithin(now time.Time) bool { + return !now.Before(window.Start) && now.Before(window.End) +} + // RenewalInfo is a type which is exposed to clients which query the renewalInfo // endpoint specified in draft-aaron-ari. type RenewalInfo struct { diff --git a/core/objects_test.go b/core/objects_test.go index 3144ede7d84..61ee2c5c87a 100644 --- a/core/objects_test.go +++ b/core/objects_test.go @@ -6,6 +6,7 @@ import ( "math/big" "net" "testing" + "time" "gopkg.in/go-jose/go-jose.v2" @@ -174,3 +175,26 @@ func TestFindChallengeByType(t *testing.T) { test.AssertEquals(t, 1, authz.FindChallengeByStringID(authz.Challenges[1].StringID())) test.AssertEquals(t, -1, authz.FindChallengeByStringID("hello")) } + +func TestRenewalInfoSuggestedWindowIsWithin(t *testing.T) { + now := time.Now().UTC() + window := SuggestedWindow{ + Start: now, + End: now.Add(time.Hour), + } + + // Exactly the beginning, inclusive of the first nanosecond. + test.Assert(t, window.IsWithin(now), "Start of window should be within the window") + + // Exactly the middle. + test.Assert(t, window.IsWithin(now.Add(time.Minute*30)), "Middle of window should be within the window") + + // Exactly the end time. + test.Assert(t, !window.IsWithin(now.Add(time.Hour)), "End of window should be outside the window") + + // Exactly the end of the window. + test.Assert(t, window.IsWithin(now.Add(time.Hour-time.Nanosecond)), "Should be just inside the window") + + // Just before the first nanosecond. + test.Assert(t, !window.IsWithin(now.Add(-time.Nanosecond)), "Before the window should not be within the window") +} diff --git a/wfe2/wfe.go b/wfe2/wfe.go index 6ae1ba097fa..26d198c1e23 100644 --- a/wfe2/wfe.go +++ b/wfe2/wfe.go @@ -2119,6 +2119,47 @@ func (wfe *WebFrontEndImpl) refundNewOrderLimits(ctx context.Context, transactio } } +// orderMatchesReplacement checks if the order matches the provided certificate +// as identified by the provided ARI CertID. This function ensures that: +// - the certificate being replaced exists, +// - the requesting account owns that certificate, and +// - a name in this new order matches a name in the certificate being +// replaced. +func (wfe *WebFrontEndImpl) orderMatchesReplacement(ctx context.Context, acct *core.Registration, names []string, serial string) error { + // It's okay to use GetCertificate (vs trying to get a precertificate), + // because we don't intend to serve ARI for certs that never made it past + // the precert stage. + oldCert, err := wfe.sa.GetCertificate(ctx, &sapb.Serial{Serial: serial}) + if err != nil { + if errors.Is(err, berrors.NotFound) { + return berrors.NotFoundError("request included `replaces` field, but no current certificate with serial %q exists", serial) + } + return errors.New("failed to retrieve existing certificate") + } + + if oldCert.RegistrationID != acct.ID { + return berrors.UnauthorizedError("requester account did not request the certificate being replaced by this order") + } + parsedCert, err := x509.ParseCertificate(oldCert.Der) + if err != nil { + return fmt.Errorf("error parsing certificate replaced by this order: %w", err) + } + + var nameMatch bool + for _, name := range names { + if parsedCert.VerifyHostname(name) == nil { + // At least one name in the new order matches a name in the + // predecessor certificate. + nameMatch = true + break + } + } + if !nameMatch { + return berrors.MalformedError("identifiers in this order do not match any names in the certificate being replaced") + } + return nil +} + func (wfe *WebFrontEndImpl) determineARIWindow(ctx context.Context, serial string) (core.RenewalInfo, error) { // Check if the serial is impacted by an incident. result, err := wfe.sa.IncidentsForSerial(ctx, &sapb.Serial{Serial: serial}) @@ -2147,12 +2188,71 @@ func (wfe *WebFrontEndImpl) determineARIWindow(ctx context.Context, serial strin // the precert stage. cert, err := wfe.sa.GetCertificate(ctx, &sapb.Serial{Serial: serial}) if err != nil { - return core.RenewalInfo{}, fmt.Errorf("retrieving existing certificate: %w", err) + if errors.Is(err, berrors.NotFound) { + return core.RenewalInfo{}, err + } + return core.RenewalInfo{}, fmt.Errorf("failed to retrieve existing certificate: %w", err) } return core.RenewalInfoSimple(cert.Issued.AsTime(), cert.Expires.AsTime()), nil } +// validateReplacementOrder implements draft-ietf-acme-ari-02. For a new order +// to be considered a replacement for an existing certificate, the existing +// certificate: +// 1. MUST NOT have been replaced by another finalized order, +// 2. MUST be associated with the same ACME account as this request, and +// 3. MUST have at least one identifier in common with this request. +// +// There are three values returned by this function: +// - The first return value is the serial number of the certificate being +// replaced. If the order is not a replacement, this value is an empty +// string. +// - The second return value is a boolean indicating whether the order is +// exempt from rate limits. If the order is a replacement and the request +// is made within the suggested renewal window, this value is true. +// Otherwise, this value is false. +// - The last value is an error, this is non-nil unless the order is not a +// replacement or there was an error while validating the replacement. +func (wfe *WebFrontEndImpl) validateReplacementOrder(ctx context.Context, acct *core.Registration, names []string, replaces string) (string, bool, error) { + if replaces == "" { + // No replacement indicated. + return "", false, nil + } + + certID, err := parseCertID(replaces, wfe.issuerCertificates) + if err != nil { + return "", false, fmt.Errorf("while parsing ARI CertID an error occurred: %w", err) + } + + exists, err := wfe.sa.ReplacementOrderExists(ctx, &sapb.Serial{Serial: certID.Serial()}) + if err != nil { + return "", false, fmt.Errorf("checking replacement status of existing certificate: %w", err) + } + if exists.Exists { + return "", false, berrors.MalformedError("cannot indicate an order replaces a certificate which already has a replacement order") + } + + err = wfe.orderMatchesReplacement(ctx, acct, names, certID.Serial()) + if err != nil { + // The provided replacement field value failed to meet the required + // criteria. We're going to return the error to the caller instead + // of trying to create a regular (non-replacement) order. + return "", false, fmt.Errorf("while checking that this order is a replacement: %w", err) + } + // This order is a replacement for an existing certificate. + replaces = certID.Serial() + + // For an order to be exempt from rate limits, it must be a replacement + // and the request must be made within the suggested renewal window. + renewalInfo, err := wfe.determineARIWindow(ctx, replaces) + if err != nil { + return "", false, err + } + + return replaces, renewalInfo.SuggestedWindow.IsWithin(wfe.clk.Now()), nil +} + // NewOrder is used by clients to create a new order object and a set of // authorizations to fulfill for issuance. func (wfe *WebFrontEndImpl) NewOrder( @@ -2168,12 +2268,14 @@ func (wfe *WebFrontEndImpl) NewOrder( return } - // We only allow specifying Identifiers in a new order request - if the - // `notBefore` and/or `notAfter` fields described in Section 7.4 of acme-08 - // are sent we return a probs.Malformed as we do not support them + // newOrderRequest is the JSON structure of the request body. We only + // support the identifiers and replaces fields. If notBefore or notAfter are + // sent we return a probs.Malformed as we do not support them. var newOrderRequest struct { - Identifiers []identifier.ACMEIdentifier `json:"identifiers"` - NotBefore, NotAfter string + Identifiers []identifier.ACMEIdentifier `json:"identifiers"` + NotBefore string + NotAfter string + Replaces string } err := json.Unmarshal(body, &newOrderRequest) if err != nil { @@ -2214,12 +2316,21 @@ func (wfe *WebFrontEndImpl) NewOrder( logEvent.DNSNames = names + replaces, limitsExempt, err := wfe.validateReplacementOrder(ctx, acct, names, newOrderRequest.Replaces) + if err != nil { + wfe.sendError(response, logEvent, web.ProblemDetailsForError(err, "While validating order as a replacement and error occurred"), err) + return + } + // TODO(#5545): Spending and Refunding can be async until these rate limits // are authoritative. This saves us from adding latency to each request. // Goroutines spun out below will respect a context deadline set by the // ratelimits package and cannot be prematurely canceled by the requester. - txns := wfe.newNewOrderLimitTransactions(acct.ID, names) - go wfe.checkNewOrderLimits(ctx, txns) + var txns []ratelimits.Transaction + if !limitsExempt { + txns = wfe.newNewOrderLimitTransactions(acct.ID, names) + go wfe.checkNewOrderLimits(ctx, txns) + } var newOrderSuccessful bool var errIsRateLimit bool @@ -2235,6 +2346,8 @@ func (wfe *WebFrontEndImpl) NewOrder( order, err := wfe.ra.NewOrder(ctx, &rapb.NewOrderRequest{ RegistrationID: acct.ID, Names: names, + ReplacesSerial: replaces, + LimitsExempt: limitsExempt, }) // TODO(#7153): Check each value via core.IsAnyNilOrZero if err != nil || order == nil || order.Id == 0 || order.RegistrationID == 0 || len(order.Names) == 0 || core.IsAnyNilOrZero(order.Created, order.Expires) { @@ -2547,15 +2660,15 @@ func (c certID) Serial() string { // certID struct with the keyIdentifier and serialNumber extracted and decoded. // For more details see: // https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-02#section-4.1. -func parseCertID(path string, issuerCertificates map[issuance.NameID]*issuance.Certificate) (ariCertID, *probs.ProblemDetails, error) { +func parseCertID(path string, issuerCertificates map[issuance.NameID]*issuance.Certificate) (ariCertID, error) { parts := strings.Split(path, ".") if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return certID{}, probs.Malformed("Invalid path"), nil + return certID{}, berrors.MalformedError("Invalid path") } akid, err := base64.RawURLEncoding.DecodeString(parts[0]) if err != nil { - return certID{}, probs.Malformed("Authority Key Identifier was not base64url-encoded or contained padding", err), err + return certID{}, berrors.MalformedError("Authority Key Identifier was not base64url-encoded or contained padding: %s", err) } var found bool @@ -2566,18 +2679,18 @@ func parseCertID(path string, issuerCertificates map[issuance.NameID]*issuance.C } } if !found { - return certID{}, probs.NotFound("Path contained an Authority Key Identifier that did not match a known issuer"), nil + return certID{}, berrors.NotFoundError("path contained an Authority Key Identifier that did not match a known issuer") } serialNumber, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { - return certID{}, probs.Malformed("Serial number was not base64url-encoded or contained padding", err), err + return certID{}, berrors.NotFoundError("serial number was not base64url-encoded or contained padding: %s", err) } return certID{ keyIdentifier: akid, serialNumber: new(big.Int).SetBytes(serialNumber), - }, nil, nil + }, nil } // RenewalInfo is used to get information about the suggested renewal window @@ -2603,10 +2716,9 @@ func (wfe *WebFrontEndImpl) RenewalInfo(ctx context.Context, logEvent *web.Reque certID, err := parseDeprecatedCertID(request.URL.Path) if err != nil { // Try parsing certID param using the draft-ietf-acme-ari-02 format. - var prob *probs.ProblemDetails - certID, prob, err = parseCertID(request.URL.Path, wfe.issuerCertificates) - if prob != nil { - wfe.sendError(response, logEvent, prob, err) + certID, err = parseCertID(request.URL.Path, wfe.issuerCertificates) + if err != nil { + wfe.sendError(response, logEvent, web.ProblemDetailsForError(err, "While parsing ARI CertID an error occurred"), err) return } } @@ -2665,10 +2777,9 @@ func (wfe *WebFrontEndImpl) UpdateRenewal(ctx context.Context, logEvent *web.Req certID, err := parseDeprecatedCertID(updateRenewalRequest.CertID) if err != nil { // Try parsing certID param using the draft-ietf-acme-ari-02 format. - var prob *probs.ProblemDetails - certID, prob, err = parseCertID(updateRenewalRequest.CertID, wfe.issuerCertificates) - if prob != nil { - wfe.sendError(response, logEvent, prob, err) + certID, err = parseCertID(updateRenewalRequest.CertID, wfe.issuerCertificates) + if err != nil { + wfe.sendError(response, logEvent, web.ProblemDetailsForError(err, "While parsing ARI CertID an error occurred"), err) return } } diff --git a/wfe2/wfe_test.go b/wfe2/wfe_test.go index 8e459d52c9a..5d7554dd394 100644 --- a/wfe2/wfe_test.go +++ b/wfe2/wfe_test.go @@ -3997,3 +3997,59 @@ func Test_sendError(t *testing.T) { // Ensure the Link header isn't populatsed. test.AssertEquals(t, testResponse.Header().Get("Link"), "") } + +type mockSA struct { + sapb.StorageAuthorityReadOnlyClient + cert *corepb.Certificate +} + +// GetCertificate returns the inner certificate if it matches the given serial. +func (sa *mockSA) GetCertificate(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) { + if req.Serial == sa.cert.Serial { + return sa.cert, nil + } + return nil, berrors.NotFoundError("certificate with serial %q not found", req.Serial) +} + +func TestOrderMatchesReplacement(t *testing.T) { + wfe, _, _ := setupWFE(t) + + expectExpiry := time.Now().AddDate(0, 0, 1) + expectSerial := big.NewInt(1337) + testKey, _ := rsa.GenerateKey(rand.Reader, 1024) + rawCert := x509.Certificate{ + NotAfter: expectExpiry, + DNSNames: []string{"example.com", "example-a.com"}, + SerialNumber: expectSerial, + } + mockDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) + test.AssertNotError(t, err, "failed to create test certificate") + + wfe.sa = &mockSA{ + cert: &corepb.Certificate{ + RegistrationID: 1, + Serial: expectSerial.String(), + Der: mockDer, + }, + } + + // Working with a single matching identifier. + err = wfe.orderMatchesReplacement(context.Background(), &core.Registration{ID: 1}, []string{"example.com"}, expectSerial.String()) + test.AssertNotError(t, err, "failed to check order is replacement") + + // Working with a different matching identifier. + err = wfe.orderMatchesReplacement(context.Background(), &core.Registration{ID: 1}, []string{"example-a.com"}, expectSerial.String()) + test.AssertNotError(t, err, "failed to check order is replacement") + + // No matching identifiers. + err = wfe.orderMatchesReplacement(context.Background(), &core.Registration{ID: 1}, []string{"example-b.com"}, expectSerial.String()) + test.AssertErrorIs(t, err, berrors.Malformed) + + // RegID for predecessor order does not match. + err = wfe.orderMatchesReplacement(context.Background(), &core.Registration{ID: 2}, []string{"example.com"}, expectSerial.String()) + test.AssertErrorIs(t, err, berrors.Unauthorized) + + // Predecessor certificate not found. + err = wfe.orderMatchesReplacement(context.Background(), &core.Registration{ID: 1}, []string{"example.com"}, "1") + test.AssertErrorIs(t, err, berrors.NotFound) +} From c2fe5f5d7c52e3927c7e7c028e41db38a6174f1b Mon Sep 17 00:00:00 2001 From: orangepizza Date: Tue, 5 Mar 2024 03:35:08 +0900 Subject: [PATCH 05/17] expiry mailer : typo fix (#7348) makes linter happy: not sure why 7 year old typo starts to hit by linter nowdays though not sure why github CI can't catch this but running t.sh locally marks this as typo: (and it is) --- cmd/expiration-mailer/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/expiration-mailer/main.go b/cmd/expiration-mailer/main.go index e1014ebab67..ec6bf7d0a9a 100644 --- a/cmd/expiration-mailer/main.go +++ b/cmd/expiration-mailer/main.go @@ -730,7 +730,7 @@ func initStats(stats prometheus.Registerer) mailerStats { nagsAtCapacity := prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: "nags_at_capacity", - Help: "Count of nag groups at capcacity", + Help: "Count of nag groups at capacity", }, []string{"nag_group"}) stats.MustRegister(nagsAtCapacity) From 751281b0b1b81d1eb39ca7295989a49e94f1f6fd Mon Sep 17 00:00:00 2001 From: Matthew McPherrin Date: Mon, 4 Mar 2024 13:48:10 -0500 Subject: [PATCH 06/17] Set MaxIdleConnsPerHost to MaxIdleConns (#7349) MaxIdleConns defaults to 100, but MaxIdleConnsPerHost is only 2. Because there's a new Transport per client, we should allow a single host to use all the idle connections. A CT Log operator has notified us we're churning a lot of connections. This should significantly help. We might want to make the value configurable, instead of just using the default value, but that can always come later if needed. --- publisher/publisher.go | 1 + 1 file changed, 1 insertion(+) diff --git a/publisher/publisher.go b/publisher/publisher.go index 2cdaac37947..03c94662eb8 100644 --- a/publisher/publisher.go +++ b/publisher/publisher.go @@ -123,6 +123,7 @@ func NewLog(uri, b64PK, userAgent string, logger blog.Logger) (*Log, error) { // "unlimited," which would be bad. Transport: &http.Transport{ MaxIdleConns: http.DefaultTransport.(*http.Transport).MaxIdleConns, + MaxIdleConnsPerHost: http.DefaultTransport.(*http.Transport).MaxIdleConns, IdleConnTimeout: http.DefaultTransport.(*http.Transport).IdleConnTimeout, TLSHandshakeTimeout: http.DefaultTransport.(*http.Transport).TLSHandshakeTimeout, // In Boulder Issue 3821[0] we found that HTTP/2 support was causing hard From bb827263a98abe21b77249cf24b2dd03f7343d64 Mon Sep 17 00:00:00 2001 From: Phil Porada Date: Tue, 5 Mar 2024 12:22:28 -0500 Subject: [PATCH 07/17] CA: gRPC plumbing for multiple certificate profiles (#7331) Adds a new `certProfileName` message to the `CA.IssueCertificateRequest`. This field contains a human-readable "name" set by the [WFE2](https://github.com/letsencrypt/boulder/issues/7332), and in turn the RA. At the time of precertificate issuance, the receiving CA will determine if it is capable of fulfilling the `ra.CA.IssuePrecertificate` request for the given `certProfileName`. If the name is found in the CA's map, the CA will return a `capb.IssuePrecertificateResponse` message with a populated `certProfileHash` field back to the RA. When that RA calls `ra.CA.IssueCertificateForPrecertificate`, it will send that same `certProfileHash` message to a CA which must ensure it contains a certificate profile matching the provided hash. If the hash in found in the CA's map a final certificate issuance attempt will proceed. This is done to prevent certificate profile changes in the duration between requests from causing a mismatch between precerticate and final certificate. Part of https://github.com/letsencrypt/boulder/issues/7309 Part of https://github.com/letsencrypt/boulder/issues/6966 --- ca/proto/ca.pb.go | 194 ++++++++++++++++++++++++++++------------------ ca/proto/ca.proto | 18 +++++ 2 files changed, 137 insertions(+), 75 deletions(-) diff --git a/ca/proto/ca.pb.go b/ca/proto/ca.pb.go index 3db9a210f3c..3d1c05ffa38 100644 --- a/ca/proto/ca.pb.go +++ b/ca/proto/ca.pb.go @@ -27,10 +27,15 @@ type IssueCertificateRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Next unused field number: 6 Csr []byte `protobuf:"bytes,1,opt,name=csr,proto3" json:"csr,omitempty"` RegistrationID int64 `protobuf:"varint,2,opt,name=registrationID,proto3" json:"registrationID,omitempty"` OrderID int64 `protobuf:"varint,3,opt,name=orderID,proto3" json:"orderID,omitempty"` IssuerNameID int64 `protobuf:"varint,4,opt,name=issuerNameID,proto3" json:"issuerNameID,omitempty"` + // certProfileName is a human readable name provided by the RA and used to + // determine if the CA can issue for that profile. A default name will be + // assigned during *Profile construction if no name is provided. + CertProfileName string `protobuf:"bytes,5,opt,name=certProfileName,proto3" json:"certProfileName,omitempty"` } func (x *IssueCertificateRequest) Reset() { @@ -93,12 +98,24 @@ func (x *IssueCertificateRequest) GetIssuerNameID() int64 { return 0 } +func (x *IssueCertificateRequest) GetCertProfileName() string { + if x != nil { + return x.CertProfileName + } + return "" +} + type IssuePrecertificateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Next unused field number: 3 DER []byte `protobuf:"bytes,1,opt,name=DER,proto3" json:"DER,omitempty"` + // certProfileHash is a hash over the exported fields of a certificate profile + // to ensure that the profile remains unchanged after multiple roundtrips + // through the RA and CA. + CertProfileHash []byte `protobuf:"bytes,2,opt,name=certProfileHash,proto3" json:"certProfileHash,omitempty"` } func (x *IssuePrecertificateResponse) Reset() { @@ -140,15 +157,27 @@ func (x *IssuePrecertificateResponse) GetDER() []byte { return nil } +func (x *IssuePrecertificateResponse) GetCertProfileHash() []byte { + if x != nil { + return x.CertProfileHash + } + return nil +} + type IssueCertificateForPrecertificateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Next unused field number: 6 DER []byte `protobuf:"bytes,1,opt,name=DER,proto3" json:"DER,omitempty"` SCTs [][]byte `protobuf:"bytes,2,rep,name=SCTs,proto3" json:"SCTs,omitempty"` RegistrationID int64 `protobuf:"varint,3,opt,name=registrationID,proto3" json:"registrationID,omitempty"` OrderID int64 `protobuf:"varint,4,opt,name=orderID,proto3" json:"orderID,omitempty"` + // certProfileHash is a hash over the exported fields of a certificate profile + // to ensure that the profile remains unchanged after multiple roundtrips + // through the RA and CA. + CertProfileHash []byte `protobuf:"bytes,5,opt,name=certProfileHash,proto3" json:"certProfileHash,omitempty"` } func (x *IssueCertificateForPrecertificateRequest) Reset() { @@ -211,6 +240,13 @@ func (x *IssueCertificateForPrecertificateRequest) GetOrderID() int64 { return 0 } +func (x *IssueCertificateForPrecertificateRequest) GetCertProfileHash() []byte { + if x != nil { + return x.CertProfileHash + } + return nil +} + // Exactly one of certDER or [serial and issuerID] must be set. type GenerateOCSPRequest struct { state protoimpl.MessageState @@ -538,7 +574,7 @@ var file_ca_proto_rawDesc = []byte{ 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x91, 0x01, 0x0a, 0x17, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbb, 0x01, 0x0a, 0x17, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x73, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x63, 0x73, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, @@ -547,80 +583,88 @@ var file_ca_proto_rawDesc = []byte{ 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x22, 0x2f, 0x0a, 0x1b, 0x49, 0x73, - 0x73, 0x75, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x44, 0x45, 0x52, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x44, 0x45, 0x52, 0x22, 0x92, 0x01, 0x0a, 0x28, - 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x46, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x44, 0x45, 0x52, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x44, 0x45, 0x52, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x43, - 0x54, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x43, 0x54, 0x73, 0x12, 0x26, - 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, - 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, - 0x22, 0xb9, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x53, - 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x6f, - 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x2a, 0x0a, 0x0c, - 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x76, 0x0a, 0x12, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, - 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x63, 0x61, 0x2e, 0x43, 0x52, 0x4c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x48, 0x00, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x26, 0x0a, - 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, - 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x05, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x22, 0x8f, 0x01, 0x0a, 0x0b, 0x43, 0x52, 0x4c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, - 0x6d, 0x65, 0x49, 0x44, 0x12, 0x3a, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x4a, 0x04, 0x08, 0x02, - 0x10, 0x03, 0x22, 0x2b, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x52, - 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, - 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x32, - 0xd5, 0x01, 0x0a, 0x14, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x55, 0x0a, 0x13, 0x49, 0x73, 0x73, 0x75, - 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, - 0x1b, 0x2e, 0x63, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, - 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x66, 0x0a, 0x21, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x63, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x50, 0x72, 0x65, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x00, 0x32, 0x4c, 0x0a, 0x0d, 0x4f, 0x43, 0x53, 0x50, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x0c, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x53, 0x50, 0x12, 0x17, 0x2e, 0x63, 0x61, 0x2e, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x10, 0x2e, 0x63, 0x61, 0x2e, 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0x54, 0x0a, 0x0c, 0x43, 0x52, 0x4c, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x0b, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x43, 0x52, 0x4c, 0x12, 0x16, 0x2e, 0x63, 0x61, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, - 0x61, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x74, 0x73, 0x65, 0x6e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x61, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x65, + 0x72, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x59, 0x0a, 0x1b, 0x49, 0x73, 0x73, 0x75, 0x65, 0x50, 0x72, 0x65, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x44, 0x45, 0x52, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x03, 0x44, 0x45, 0x52, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, + 0x63, 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x22, + 0xbc, 0x01, 0x0a, 0x28, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x44, 0x45, 0x52, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x44, 0x45, 0x52, 0x12, 0x12, + 0x0a, 0x04, 0x53, 0x43, 0x54, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x43, + 0x54, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, + 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x22, 0xb9, + 0x01, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x53, 0x50, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, + 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x64, 0x41, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x49, 0x44, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x2a, 0x0a, 0x0c, 0x4f, 0x43, + 0x53, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x76, 0x0a, 0x12, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x63, 0x61, 0x2e, 0x43, 0x52, 0x4c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, + 0x00, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x26, 0x0a, 0x05, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x05, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8f, + 0x01, 0x0a, 0x0b, 0x43, 0x52, 0x4c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x22, + 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x49, 0x44, 0x12, 0x3a, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, + 0x22, 0x2b, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x52, 0x4c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x32, 0xd5, 0x01, + 0x0a, 0x14, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x55, 0x0a, 0x13, 0x49, 0x73, 0x73, 0x75, 0x65, 0x50, + 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x2e, + 0x63, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x61, 0x2e, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x66, 0x0a, + 0x21, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x46, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x63, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x22, 0x00, 0x32, 0x4c, 0x0a, 0x0d, 0x4f, 0x43, 0x53, 0x50, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x4f, 0x43, 0x53, 0x50, 0x12, 0x17, 0x2e, 0x63, 0x61, 0x2e, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x10, 0x2e, 0x63, 0x61, 0x2e, 0x4f, 0x43, 0x53, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x32, 0x54, 0x0a, 0x0c, 0x43, 0x52, 0x4c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x0b, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, + 0x52, 0x4c, 0x12, 0x16, 0x2e, 0x63, 0x61, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x43, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x61, 0x2e, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x61, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/ca/proto/ca.proto b/ca/proto/ca.proto index 6251f84ab4e..8e743d8b345 100644 --- a/ca/proto/ca.proto +++ b/ca/proto/ca.proto @@ -13,21 +13,39 @@ service CertificateAuthority { } message IssueCertificateRequest { + // Next unused field number: 6 bytes csr = 1; int64 registrationID = 2; int64 orderID = 3; int64 issuerNameID = 4; + + // certProfileName is a human readable name provided by the RA and used to + // determine if the CA can issue for that profile. A default name will be + // assigned during *Profile construction if no name is provided. + string certProfileName = 5; } message IssuePrecertificateResponse { + // Next unused field number: 3 bytes DER = 1; + + // certProfileHash is a hash over the exported fields of a certificate profile + // to ensure that the profile remains unchanged after multiple roundtrips + // through the RA and CA. + bytes certProfileHash = 2; } message IssueCertificateForPrecertificateRequest { + // Next unused field number: 6 bytes DER = 1; repeated bytes SCTs = 2; int64 registrationID = 3; int64 orderID = 4; + + // certProfileHash is a hash over the exported fields of a certificate profile + // to ensure that the profile remains unchanged after multiple roundtrips + // through the RA and CA. + bytes certProfileHash = 5; } // OCSPGenerator generates OCSP. We separate this out from From 517efde4771fca6968ffec0f2532c607a5ac18bc Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Tue, 5 Mar 2024 12:36:29 -0800 Subject: [PATCH 08/17] Strip old admin-revoker down to bare bones (#7317) De-duplicate the code that has been replaced by `admin`, and cause all of its subcommands to print helpful messages indicating the corresponding `admin` command to run instead. --- cmd/admin-revoker/main.go | 642 +-------------------------------- cmd/admin-revoker/main_test.go | 503 -------------------------- 2 files changed, 20 insertions(+), 1125 deletions(-) delete mode 100644 cmd/admin-revoker/main_test.go diff --git a/cmd/admin-revoker/main.go b/cmd/admin-revoker/main.go index 85390053016..7d18bc74917 100644 --- a/cmd/admin-revoker/main.go +++ b/cmd/admin-revoker/main.go @@ -1,80 +1,13 @@ package notmain import ( - "bufio" - "context" - "crypto/x509" - "errors" - "flag" "fmt" - "io" "os" - "os/user" - "sort" - "strconv" - "sync" - - "github.com/jmhodges/clock" - "google.golang.org/protobuf/types/known/timestamppb" "github.com/letsencrypt/boulder/cmd" - "github.com/letsencrypt/boulder/core" - "github.com/letsencrypt/boulder/db" - berrors "github.com/letsencrypt/boulder/errors" "github.com/letsencrypt/boulder/features" - bgrpc "github.com/letsencrypt/boulder/grpc" - blog "github.com/letsencrypt/boulder/log" - "github.com/letsencrypt/boulder/metrics" - "github.com/letsencrypt/boulder/privatekey" - rapb "github.com/letsencrypt/boulder/ra/proto" - "github.com/letsencrypt/boulder/revocation" - "github.com/letsencrypt/boulder/sa" - sapb "github.com/letsencrypt/boulder/sa/proto" ) -const usageString = ` -usage: - list-reasons -config - serial-revoke -config - malformed-revoke -config - batched-serial-revoke -config - incident-table-revoke -config - reg-revoke -config - private-key-block -config -comment="" -dry-run= - private-key-revoke -config -comment="" -dry-run= - clear-email -config - - -descriptions: - list-reasons List all revocation reason codes. - serial-revoke Revoke a single certificate by the hex serial number. - malformed-revoke Revoke a single certificate by the hex serial number. Works even - if the certificate cannot be parsed from the database. - Note: This does not purge the Akamai cache. - Note: This cannot be used to revoke for key compromise. - batched-serial-revoke Revoke all certificates contained in a file of hex serial numbers. - incident-table-revoke Revoke all certificates in the provided incident table. - reg-revoke Revoke all certificates associated with a registration ID. - private-key-block Adds the SPKI hash, derived from the provided private key, to the - blocked keys table. is expected to be the path - to a PEM formatted file containing an RSA or ECDSA private key. - private-key-revoke Revoke all certificates matching the SPKI hash derived from the - provided private key. Then adds the hash to the blocked keys - table. is expected to be the path to a PEM - formatted file containing an RSA or ECDSA private key. - clear-email Delete all instances of a given email from all accounts (slow). - -flags: - all: - -config File path to the configuration file for this service (required) - - private-key-block | private-key-revoke: - -dry-run true (default): only queries for affected certificates. false: will - perform the requested block or revoke action. Only implemented for - private-key-block and private-key-revoke. - -comment Comment to include in the blocked keys table entry. (default: "") -` - type Config struct { Revoker struct { DB cmd.DBConfig @@ -92,578 +25,43 @@ type Config struct { Syslog cmd.SyslogConfig } -type revoker struct { - rac rapb.RegistrationAuthorityClient - sac sapb.StorageAuthorityClient - dbMap *db.WrappedMap - clk clock.Clock - log blog.Logger -} - -func newRevoker(c Config) *revoker { - logger := cmd.NewLogger(c.Syslog) - logger.Info(cmd.VersionString()) - - // TODO(#6840) Rework admin-revoker to export prometheus metrics. - tlsConfig, err := c.Revoker.TLS.Load(metrics.NoopRegisterer) - cmd.FailOnError(err, "TLS config") - - clk := cmd.Clock() - - raConn, err := bgrpc.ClientSetup(c.Revoker.RAService, tlsConfig, metrics.NoopRegisterer, clk) - cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to RA") - rac := rapb.NewRegistrationAuthorityClient(raConn) - - dbMap, err := sa.InitWrappedDb(c.Revoker.DB, nil, logger) - cmd.FailOnError(err, "While initializing dbMap") - - saConn, err := bgrpc.ClientSetup(c.Revoker.SAService, tlsConfig, metrics.NoopRegisterer, clk) - cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA") - sac := sapb.NewStorageAuthorityClient(saConn) - - return &revoker{ - rac: rac, - sac: sac, - dbMap: dbMap, - clk: clk, - log: logger, - } -} - -func (r *revoker) revokeCertificate(ctx context.Context, certObj core.Certificate, reasonCode revocation.Reason, skipBlockKey bool) error { - if reasonCode < 0 || reasonCode == 7 || reasonCode > 10 { - panic(fmt.Sprintf("Invalid reason code: %d", reasonCode)) - } - u, err := user.Current() - if err != nil { - return err - } - - var req *rapb.AdministrativelyRevokeCertificateRequest - if certObj.DER != nil { - cert, err := x509.ParseCertificate(certObj.DER) - if err != nil { - return err - } - req = &rapb.AdministrativelyRevokeCertificateRequest{ - Cert: cert.Raw, - Serial: core.SerialToString(cert.SerialNumber), - Code: int64(reasonCode), - AdminName: u.Username, - SkipBlockKey: skipBlockKey, - } - } else { - req = &rapb.AdministrativelyRevokeCertificateRequest{ - Serial: certObj.Serial, - Code: int64(reasonCode), - AdminName: u.Username, - SkipBlockKey: skipBlockKey, - } - } - _, err = r.rac.AdministrativelyRevokeCertificate(ctx, req) - if err != nil { - return err - } - r.log.Infof("Revoked certificate %s with reason '%s'", certObj.Serial, revocation.ReasonToString[reasonCode]) - return nil -} - -func (r *revoker) revokeBySerial(ctx context.Context, serial string, reasonCode revocation.Reason, skipBlockKey bool) error { - certObj, err := sa.SelectPrecertificate(ctx, r.dbMap, serial) - if err != nil { - if db.IsNoRows(err) { - return berrors.NotFoundError("precertificate with serial %q not found", serial) - } - return err - } - return r.revokeCertificate(ctx, certObj, reasonCode, skipBlockKey) -} - -func (r *revoker) revokeSerialBatchFile(ctx context.Context, serialPath string, reasonCode revocation.Reason, parallelism int) error { - file, err := os.Open(serialPath) - if err != nil { - return err - } - - scanner := bufio.NewScanner(file) - - wg := new(sync.WaitGroup) - work := make(chan string, parallelism) - for i := 0; i < parallelism; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for serial := range work { - // handle newlines gracefully - if serial == "" { - continue - } - err := r.revokeBySerial(ctx, serial, reasonCode, false) - if err != nil { - r.log.Errf("failed to revoke %q: %s", serial, err) - } - } - }() - } - - for scanner.Scan() { - serial := scanner.Text() - if serial == "" { - continue - } - work <- serial - } - close(work) - wg.Wait() - - return nil -} - -// clearEmailAddress clears the given email address from all accounts that have it. -// Finding relevant accounts will be very slow because it does not use an index. -func (r *revoker) clearEmailAddress(ctx context.Context, email string) error { - r.log.AuditInfof("Scanning database for accounts with email addresses matching %q in order to clear the email addresses.", email) - regIDs, err := r.getRegIDsMatchingEmail(ctx, email) - if err != nil { - return err - } - - r.log.Infof("Found %d registration IDs matching email %q.", len(regIDs), email) - - failures := 0 - for _, regID := range regIDs { - err := sa.ClearEmail(ctx, r.dbMap, regID, email) - if err != nil { - // Log, but don't fail, because it took a long time to find the relevant registration IDs - // and we don't want to have to redo that work. - r.log.AuditErrf("failed to clear email %q for registration ID %d: %s", email, regID, err) - failures++ - } else { - r.log.AuditInfof("cleared email %q for registration ID %d: %s", email, regID, err) - } - } - if failures > 0 { - return fmt.Errorf("failed to clear email for %d out of %d registration IDs", failures, len(regIDs)) - } - return nil -} - -func (r *revoker) revokeIncidentTableSerials(ctx context.Context, tableName string, reasonCode revocation.Reason, parallelism int) error { - wg := new(sync.WaitGroup) - work := make(chan string, parallelism) - for i := 0; i < parallelism; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for serial := range work { - err := r.revokeBySerial(ctx, serial, reasonCode, false) - if err != nil { - r.log.Errf("failed to revoke %q: %s", serial, err) - } - } - }() - } - - stream, err := r.sac.SerialsForIncident(ctx, &sapb.SerialsForIncidentRequest{IncidentTable: tableName}) - if err != nil { - return fmt.Errorf("setting up stream of serials from incident table %q: %s", tableName, err) - } - - var atLeastOne bool - for { - is, err := stream.Recv() - if err != nil { - if err == io.EOF { - break - } - return fmt.Errorf("streaming serials from incident table %q: %s", tableName, err) - } - atLeastOne = true - work <- is.Serial - } - if !atLeastOne { - r.log.AuditInfof("No serials found in incident table %q", tableName) - } - close(work) - wg.Wait() - - return nil -} - -func (r *revoker) revokeByReg(ctx context.Context, regID int64, reasonCode revocation.Reason) error { - _, err := r.sac.GetRegistration(ctx, &sapb.RegistrationID{Id: regID}) - if err != nil { - return fmt.Errorf("couldn't fetch registration: %w", err) - } - - certObjs, err := sa.SelectPrecertificates(ctx, r.dbMap, "WHERE registrationID = :regID", map[string]interface{}{"regID": regID}) - if err != nil { - return err - } - for _, certObj := range certObjs { - err = r.revokeCertificate(ctx, certObj.Certificate, reasonCode, false) - if err != nil { - return err - } - } - return nil -} - -func (r *revoker) revokeMalformedBySerial(ctx context.Context, serial string, reasonCode revocation.Reason) error { - return r.revokeCertificate(ctx, core.Certificate{Serial: serial}, reasonCode, false) -} - -// blockByPrivateKey blocks future issuance for certificates with a a public key -// matching the SubjectPublicKeyInfo hash generated from the PublicKey embedded -// in privateKey. The embedded PublicKey will be verified as an actual match for -// the provided private key before any blocking takes place. This method does -// not revoke any certificates directly. However, 'bad-key-revoker', which -// references the 'blockedKeys' table, will eventually revoke certificates with -// a matching SPKI hash. -func (r *revoker) blockByPrivateKey(ctx context.Context, comment string, privateKey string) error { - _, publicKey, err := privatekey.Load(privateKey) - if err != nil { - return err - } - - spkiHash, err := core.KeyDigest(publicKey) - if err != nil { - return err - } - - u, err := user.Current() - if err != nil { - return err - } - - dbcomment := fmt.Sprintf("%s: %s", u.Username, comment) - - req := &sapb.AddBlockedKeyRequest{ - KeyHash: spkiHash[:], - Added: timestamppb.New(r.clk.Now()), - Source: "admin-revoker", - Comment: dbcomment, - RevokedBy: 0, - } - - _, err = r.sac.AddBlockedKey(ctx, req) - if err != nil { - return err - } - return nil -} - -// revokeByPrivateKey revokes all certificates with a public key matching the -// SubjectPublicKeyInfo hash generated from the PublicKey embedded in -// privateKey. The embedded PublicKey will be verified as an actual match for the -// provided private key before any revocation takes place. The provided key will -// not be added to the 'blockedKeys' table. This is done to avoid a race between -// 'admin-revoker' and 'bad-key-revoker'. You MUST call blockByPrivateKey after -// calling this function, on pain of violating the BRs. -func (r *revoker) revokeByPrivateKey(ctx context.Context, privateKey string) error { - _, publicKey, err := privatekey.Load(privateKey) - if err != nil { - return err - } - - spkiHash, err := core.KeyDigest(publicKey) - if err != nil { - return err - } - - matches, err := r.getCertsMatchingSPKIHash(ctx, spkiHash) - if err != nil { - return err - } - - for i, match := range matches { - resp, err := r.sac.GetCertificateStatus(ctx, &sapb.Serial{Serial: match}) - if err != nil { - return fmt.Errorf( - "failed to get status for serial %q. Entry %d of %d affected certificates: %w", - match, - (i + 1), - len(matches), - err, - ) - } - - if resp.Status != string(core.OCSPStatusGood) { - r.log.AuditInfof("serial %q is already revoked, skipping", match) - continue - } - - err = r.revokeBySerial(ctx, match, revocation.Reason(1), true) - if err != nil { - return fmt.Errorf( - "failed to revoke serial %q. Entry %d of %d affected certificates: %w", - match, - (i + 1), - len(matches), - err, - ) - } - } - return nil -} - -func (r *revoker) spkiHashInBlockedKeys(ctx context.Context, spkiHash core.Sha256Digest) (bool, error) { - var count int - err := r.dbMap.SelectOne(ctx, &count, "SELECT COUNT(*) as count FROM blockedKeys WHERE keyHash = ?", spkiHash[:]) - if err != nil { - return false, err - } - - if count > 0 { - return true, nil - } - return false, nil -} - -func (r *revoker) countCertsMatchingSPKIHash(ctx context.Context, spkiHash core.Sha256Digest) (int, error) { - var count int - err := r.dbMap.SelectOne(ctx, &count, "SELECT COUNT(*) as count FROM keyHashToSerial WHERE keyHash = ?", spkiHash[:]) - if err != nil { - return 0, err - } - return count, nil -} - -// getRegIDsMatchingEmail returns a list of registration IDs where the contacts list -// contains the given email address. Since this uses a substring match, it is important -// to subsequently parse the JSON list of addresses and look for exact matches. -// Note: Since this does not use an index, it is very slow. -func (r *revoker) getRegIDsMatchingEmail(ctx context.Context, email string) ([]int64, error) { - // We use SQL `CONCAT` rather than interpolating with `+` or `%s` because we want to - // use a `?` placeholder for the email, which prevents SQL injection. - var regIDs []int64 - _, err := r.dbMap.Select(ctx, ®IDs, "SELECT id FROM registrations WHERE contact LIKE CONCAT('%\"mailto:', ?, '\"%')", email) - if err != nil { - return nil, err - } - return regIDs, nil -} - -// TODO(#5899) Use an non-wrapped sql.Db client to iterate over results and -// return them on a channel. -func (r *revoker) getCertsMatchingSPKIHash(ctx context.Context, spkiHash core.Sha256Digest) ([]string, error) { - var h []string - _, err := r.dbMap.Select(ctx, &h, "SELECT certSerial FROM keyHashToSerial WHERE keyHash = ?", spkiHash[:]) - if err != nil { - if db.IsNoRows(err) { - return nil, berrors.NotFoundError("no certificates with a matching SPKI hash were found") - } - return nil, err - } - return h, nil -} - -// This abstraction is needed so that we can use sort.Sort below -type revocationCodes []revocation.Reason - -func (rc revocationCodes) Len() int { return len(rc) } -func (rc revocationCodes) Less(i, j int) bool { return rc[i] < rc[j] } -func (rc revocationCodes) Swap(i, j int) { rc[i], rc[j] = rc[j], rc[i] } - -func privateKeyBlock(ctx context.Context, r *revoker, dryRun bool, comment string, count int, spkiHash core.Sha256Digest, keyPath string) error { - keyExists, err := r.spkiHashInBlockedKeys(ctx, spkiHash) - if err != nil { - return fmt.Errorf("while checking if the provided key already exists in the 'blockedKeys' table: %s", err) - } - if keyExists { - return errors.New("the provided key already exists in the 'blockedKeys' table") - } - - if dryRun { - r.log.AuditInfof( - "To block issuance for this key and revoke %d certificates via bad-key-revoker, run with -dry-run=false", - count, - ) - r.log.AuditInfo("No keys were blocked or certificates revoked, exiting...") - return nil - } - - r.log.AuditInfo("Attempting to block issuance for the provided key") - err = r.blockByPrivateKey(context.Background(), comment, keyPath) - if err != nil { - return fmt.Errorf("while attempting to block issuance for the provided key: %s", err) - } - r.log.AuditInfo("Issuance for the provided key has been successfully blocked, exiting...") - return nil -} - -func privateKeyRevoke(r *revoker, dryRun bool, comment string, count int, keyPath string) error { - if dryRun { - r.log.AuditInfof( - "To immediately revoke %d certificates and block issuance for this key, run with -dry-run=false", - count, - ) - r.log.AuditInfo("No keys were blocked or certificates revoked, exiting...") - return nil - } - - if count <= 0 { - // Do not revoke. - return nil - } - - // Revoke certificates. - r.log.AuditInfof("Attempting to revoke %d certificates", count) - err := r.revokeByPrivateKey(context.Background(), keyPath) - if err != nil { - return fmt.Errorf("while attempting to revoke certificates for the provided key: %s", err) - } - r.log.AuditInfo("All certificates matching using the provided key have been successfully") - - // Block future issuance. - r.log.AuditInfo("Attempting to block issuance for the provided key") - err = r.blockByPrivateKey(context.Background(), comment, keyPath) - if err != nil { - return fmt.Errorf("while attempting to block issuance for the provided key: %s", err) - } - r.log.AuditInfo("All certificates have been successfully revoked and issuance blocked, exiting...") - return nil -} - func main() { - usage := func() { - fmt.Fprint(os.Stderr, usageString) + if len(os.Args) == 1 { + fmt.Println("use `admin -h` to learn how to use the new admin tool") os.Exit(1) } - if len(os.Args) <= 2 { - usage() - } command := os.Args[1] - flagSet := flag.NewFlagSet(command, flag.ContinueOnError) - configFile := flagSet.String("config", "", "File path to the configuration file for this service") - dryRun := flagSet.Bool( - "dry-run", - true, - "true (default): only queries for affected certificates. false: will perform the requested block or revoke action", - ) - comment := flagSet.String("comment", "", "Comment to include in the blocked key database entry ") - err := flagSet.Parse(os.Args[2:]) - if err == flag.ErrHelp { - os.Exit(1) - } - cmd.FailOnError(err, "parsing flagset") - - if *configFile == "" { - usage() - } - - var c Config - err = cmd.ReadConfigFile(*configFile, &c) - cmd.FailOnError(err, "Reading JSON config file into config structure") - features.Set(c.Revoker.Features) - - ctx := context.Background() - r := newRevoker(c) - - args := flagSet.Args() switch { - case command == "serial-revoke" && len(args) == 2: - // 1: serial, 2: reasonCode - serial := args[0] - reasonCode, err := strconv.Atoi(args[1]) - cmd.FailOnError(err, "Reason code argument must be an integer") - - err = r.revokeBySerial(ctx, serial, revocation.Reason(reasonCode), false) - cmd.FailOnError(err, "Couldn't revoke certificate by serial") - - case command == "batched-serial-revoke" && len(args) == 3: - // 1: serial file path, 2: reasonCode, 3: parallelism - serialPath := args[0] - reasonCode, err := strconv.Atoi(args[1]) - cmd.FailOnError(err, "Reason code argument must be an integer") - parallelism, err := strconv.Atoi(args[2]) - cmd.FailOnError(err, "parallelism argument must be an integer") - if parallelism < 1 { - cmd.Fail("parallelism argument must be >= 1") - } + case command == "serial-revoke": + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -serial deadbeef -reason X` instead") - err = r.revokeSerialBatchFile(ctx, serialPath, revocation.Reason(reasonCode), parallelism) - cmd.FailOnError(err, "Batch revocation failed") + case command == "batched-serial-revoke": + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -serials-file path -reason X` instead") - case command == "reg-revoke" && len(args) == 2: - // 1: registration ID, 2: reasonCode - regID, err := strconv.ParseInt(args[0], 10, 64) - cmd.FailOnError(err, "Registration ID argument must be an integer") - reasonCode, err := strconv.Atoi(args[1]) - cmd.FailOnError(err, "Reason code argument must be an integer") + case command == "reg-revoke": + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -reg-id Y -reason X` instead") - err = r.revokeByReg(ctx, regID, revocation.Reason(reasonCode)) - cmd.FailOnError(err, "Couldn't revoke certificate by registration") - - case command == "malformed-revoke" && len(args) == 3: - // 1: serial, 2: reasonCode - serial := args[0] - reasonCode, err := strconv.Atoi(args[1]) - cmd.FailOnError(err, "Reason code argument must be an integer") - - err = r.revokeMalformedBySerial(ctx, serial, revocation.Reason(reasonCode)) - cmd.FailOnError(err, "Couldn't revoke certificate by serial") + case command == "malformed-revoke": + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -serial deadbeef -reason X -malformed` instead") case command == "list-reasons": - var codes revocationCodes - for k := range revocation.ReasonToString { - codes = append(codes, k) - } - sort.Sort(codes) - fmt.Printf("Revocation reason codes\n-----------------------\n\n") - for _, k := range codes { - fmt.Printf("%d: %s\n", k, revocation.ReasonToString[k]) - } - - case (command == "private-key-block" || command == "private-key-revoke") && len(args) == 1: - // 1: keyPath - keyPath := args[0] - - _, publicKey, err := privatekey.Load(keyPath) - cmd.FailOnError(err, "Failed to load the provided private key") - r.log.AuditInfo("The provided private key has been successfully verified") - - spkiHash, err := core.KeyDigest(publicKey) - cmd.FailOnError(err, "While obtaining the SPKI hash for the provided key") - - count, err := r.countCertsMatchingSPKIHash(ctx, spkiHash) - cmd.FailOnError(err, "While retrieving a count of certificates matching the provided key") - r.log.AuditInfof("Found %d certificates matching the provided key", count) - - if command == "private-key-block" { - err := privateKeyBlock(ctx, r, *dryRun, *comment, count, spkiHash, keyPath) - cmd.FailOnError(err, "") - } - - if command == "private-key-revoke" { - err := privateKeyRevoke(r, *dryRun, *comment, count, keyPath) - cmd.FailOnError(err, "") - } + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -h` instead") - case command == "incident-table-revoke" && len(args) == 3: - // 1: tableName, 2: reasonCode, 3: parallelism - tableName := args[0] + case command == "private-key-revoke": + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -private-key path -reason X` instead") - reasonCode, err := strconv.Atoi(args[1]) - cmd.FailOnError(err, "Reason code argument must be an integer") + case command == "private-key-block": + fmt.Println("use `admin -config path/to/cfg.json block-key -private-key path -comment foo` instead") - parallelism, err := strconv.Atoi(args[2]) - cmd.FailOnError(err, "parallelism argument must be an integer") - if parallelism < 1 { - cmd.Fail("parallelism argument must be >= 1") - } - err = r.revokeIncidentTableSerials(ctx, tableName, revocation.Reason(reasonCode), parallelism) - cmd.FailOnError(err, "Couldn't revoke serials in incident table") + case command == "incident-table-revoke": + fmt.Println("use `admin -config path/to/cfg.json revoke-cert -incident-table tablename -reason X` instead") - case command == "clear-email" && len(args) == 1: - email := args[0] - err := r.clearEmailAddress(ctx, email) - cmd.FailOnError(err, "Clearing email address") + case command == "clear-email": + fmt.Println("use `admin -config path/to/cfg.json update-email -address foo@bar.org -clear` instead") default: - fmt.Fprintf(os.Stderr, "unrecognized subcommand %q\n\n", command) - usage() + fmt.Println("use `admin -h` to see a list of flags and subcommands for the new admin tool") } } diff --git a/cmd/admin-revoker/main_test.go b/cmd/admin-revoker/main_test.go deleted file mode 100644 index 48a46d66fc3..00000000000 --- a/cmd/admin-revoker/main_test.go +++ /dev/null @@ -1,503 +0,0 @@ -package notmain - -import ( - "context" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "math/big" - "net" - "os" - "os/user" - "testing" - "time" - - "github.com/jmhodges/clock" - akamaipb "github.com/letsencrypt/boulder/akamai/proto" - capb "github.com/letsencrypt/boulder/ca/proto" - "github.com/letsencrypt/boulder/core" - corepb "github.com/letsencrypt/boulder/core/proto" - "github.com/letsencrypt/boulder/db" - "github.com/letsencrypt/boulder/goodkey" - "github.com/letsencrypt/boulder/issuance" - blog "github.com/letsencrypt/boulder/log" - "github.com/letsencrypt/boulder/metrics" - "github.com/letsencrypt/boulder/mocks" - "github.com/letsencrypt/boulder/ra" - "github.com/letsencrypt/boulder/sa" - sapb "github.com/letsencrypt/boulder/sa/proto" - "github.com/letsencrypt/boulder/test" - ira "github.com/letsencrypt/boulder/test/inmem/ra" - isa "github.com/letsencrypt/boulder/test/inmem/sa" - "github.com/letsencrypt/boulder/test/vars" - "google.golang.org/grpc" - "google.golang.org/protobuf/types/known/emptypb" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type mockOCSPA struct { - mocks.MockCA -} - -func (ca *mockOCSPA) GenerateOCSP(context.Context, *capb.GenerateOCSPRequest, ...grpc.CallOption) (*capb.OCSPResponse, error) { - return &capb.OCSPResponse{Response: []byte("fakeocspbytes")}, nil -} - -type mockPurger struct{} - -func (mp *mockPurger) Purge(context.Context, *akamaipb.PurgeRequest, ...grpc.CallOption) (*emptypb.Empty, error) { - return &emptypb.Empty{}, nil -} - -func TestRevokeSerialBatchFile(t *testing.T) { - testCtx := setup(t) - defer testCtx.cleanUp() - - entries, _ := setupUniqueTestEntries(t) - testCtx.createAndRegisterEntries(t, entries) - - serialFile, err := os.CreateTemp("", "serials") - test.AssertNotError(t, err, "failed to open temp file") - defer os.Remove(serialFile.Name()) - - for _, e := range entries { - _, err = serialFile.WriteString(fmt.Sprintf("%s\n", core.SerialToString(e.serial))) - test.AssertNotError(t, err, "failed to write serial to temp file") - } - err = testCtx.revoker.revokeSerialBatchFile(context.Background(), serialFile.Name(), 0, 2) - test.AssertNotError(t, err, "revokeBatch failed") - - for _, e := range entries { - status, err := testCtx.ssa.GetCertificateStatus(context.Background(), &sapb.Serial{Serial: core.SerialToString(e.serial)}) - test.AssertNotError(t, err, "failed to retrieve certificate status") - test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked) - } -} - -func TestRevokeIncidentTableSerials(t *testing.T) { - testCtx := setup(t) - defer testCtx.cleanUp() - - entries, _ := setupUniqueTestEntries(t) - testCtx.createAndRegisterEntries(t, entries) - - testIncidentsDbMap, err := sa.DBMapForTest(vars.DBConnIncidentsFullPerms) - test.AssertNotError(t, err, "Couldn't create test dbMap") - - // Ensure that an empty incident table results in the expected log output. - err = testCtx.revoker.revokeIncidentTableSerials(context.Background(), "incident_foo", 0, 1) - test.AssertNotError(t, err, "revokeIncidentTableSerials failed") - test.Assert(t, len(testCtx.log.GetAllMatching("No serials found in incident table")) > 0, "Expected log output not found") - testCtx.log.Clear() - - ctx := context.Background() - - _, err = testIncidentsDbMap.ExecContext( - ctx, - fmt.Sprintf("INSERT INTO incident_foo (%s) VALUES ('%s', %d, %d, '%s')", - "serial, registrationID, orderID, lastNoticeSent", - core.SerialToString(entries[0].serial), - entries[0].regId, - 42, - testCtx.revoker.clk.Now().Add(-time.Hour*24*7).Format(time.DateTime), - ), - ) - test.AssertNotError(t, err, "while inserting row into incident table") - - err = testCtx.revoker.revokeIncidentTableSerials(ctx, "incident_foo", 0, 1) - test.AssertNotError(t, err, "revokeIncidentTableSerials failed") - - // Ensure that a populated incident table results in the expected log output. - test.AssertNotError(t, err, "revokeIncidentTableSerials failed") - test.Assert(t, len(testCtx.log.GetAllMatching("No serials found in incident table")) <= 0, "Expected log output not found") - - status, err := testCtx.ssa.GetCertificateStatus(ctx, &sapb.Serial{Serial: core.SerialToString(entries[0].serial)}) - test.AssertNotError(t, err, "failed to retrieve certificate status") - test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked) -} - -func TestBlockAndRevokeByPrivateKey(t *testing.T) { - testCtx := setup(t) - defer testCtx.cleanUp() - - uniqueEntries, duplicateEntry := setupUniqueTestEntries(t) - testCtx.createAndRegisterEntries(t, uniqueEntries) - testCtx.createAndRegisterEntry(t, duplicateEntry) - - // Write the key contents of our duplicate entry to a temp file. - duplicateKeyFile, err := os.CreateTemp("", "key") - test.AssertNotError(t, err, "failed to create temp file") - der, err := x509.MarshalPKCS8PrivateKey(duplicateEntry.testKey) - test.AssertNotError(t, err, "failed to marshal testKey1 to DER") - err = pem.Encode(duplicateKeyFile, - &pem.Block{ - Type: "PRIVATE KEY", - Bytes: der, - }, - ) - test.AssertNotError(t, err, "failed to PEM encode test key 1") - test.AssertNotError(t, err, "failed to write to temp file") - defer os.Remove(duplicateKeyFile.Name()) - - // Get the SPKI hash for the provided keypair. - spkiHash, err := core.KeyDigest(&duplicateEntry.testKey.PublicKey) - test.AssertNotError(t, err, "Failed to get SPKI hash for dupe.") - - ctx := context.Background() - - // Ensure that the SPKI hash hasn't already been added to the blockedKeys - // table. - keyExists, err := testCtx.revoker.spkiHashInBlockedKeys(ctx, spkiHash) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys") - - // For some additional validation let's ensure that counts for all test - // entries, except our known duplicate, are 1. - for _, e := range uniqueEntries { - switch e.names[0] { - case uniqueEntries[0].names[0]: - // example-1337.com - count, err := testCtx.revoker.countCertsMatchingSPKIHash(ctx, e.spkiHash) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for entry failed") - test.AssertEquals(t, count, 2) - - case uniqueEntries[1].names[0]: - // example-1338.com - count, err := testCtx.revoker.countCertsMatchingSPKIHash(ctx, e.spkiHash) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for entry failed") - test.AssertEquals(t, count, 1) - - case uniqueEntries[2].names[0]: - // example-1339.com - count, err := testCtx.revoker.countCertsMatchingSPKIHash(ctx, e.spkiHash) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for entry failed") - test.AssertEquals(t, count, 1) - } - } - - // Revoke one of our two duplicate certificates by serial. This is to test - // that revokeByPrivateKey will continue if one of the two matching - // certificates has already been revoked. - err = testCtx.revoker.revokeBySerial(context.Background(), core.SerialToString(duplicateEntry.serial), 1, true) - test.AssertNotError(t, err, "While attempting to revoke 1 of our matching certificates ahead of time") - - // Revoke the certificates, but do not block issuance. - err = testCtx.revoker.revokeByPrivateKey(context.Background(), duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to revoke certificates for the provided key") - - // Ensure that the key is not blocked, yet. - keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(ctx, spkiHash) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys") - - // Block issuance for the key. - err = testCtx.revoker.blockByPrivateKey(context.Background(), "", duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to block issuance for the provided key") - - // Ensure that the key is now blocked. - keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(ctx, spkiHash) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.Assert(t, keyExists, "SPKI hash should not be in blockedKeys") - - // Ensure that blocking issuance is idempotent. - err = testCtx.revoker.blockByPrivateKey(context.Background(), "", duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to block issuance for the provided key") -} - -func TestPrivateKeyBlock(t *testing.T) { - ctx := context.Background() - testCtx := setup(t) - defer testCtx.cleanUp() - - uniqueEntries, duplicateEntry := setupUniqueTestEntries(t) - testCtx.createAndRegisterEntries(t, uniqueEntries) - testCtx.createAndRegisterEntry(t, duplicateEntry) - - // Write the key contents of our duplicate entry to a temp file. - duplicateKeyFile, err := os.CreateTemp("", "key") - test.AssertNotError(t, err, "failed to create temp file") - der, err := x509.MarshalPKCS8PrivateKey(duplicateEntry.testKey) - test.AssertNotError(t, err, "failed to marshal testKey1 to DER") - err = pem.Encode(duplicateKeyFile, - &pem.Block{ - Type: "PRIVATE KEY", - Bytes: der, - }, - ) - test.AssertNotError(t, err, "failed to PEM encode test key") - test.AssertNotError(t, err, "failed to write to temp file") - defer os.Remove(duplicateKeyFile.Name()) - - // Get the SPKI hash for the provided keypair. - duplicateKeySPKI, err := core.KeyDigest(&duplicateEntry.testKey.PublicKey) - test.AssertNotError(t, err, "Failed to get SPKI hash for dupe.") - - // Query the 'keyHashToSerial' table for certificates with a matching SPKI - // hash. We expect that since this key was re-used we'll find 2 matches. - count, err := testCtx.revoker.countCertsMatchingSPKIHash(ctx, duplicateKeySPKI) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.AssertEquals(t, count, 2) - - // With dryRun=true this should not block the key. - err = privateKeyBlock(ctx, &testCtx.revoker, true, "", count, duplicateKeySPKI, duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to block issuance for the provided key") - - // Ensure that the key is not blocked, yet. - keyExists, err := testCtx.revoker.spkiHashInBlockedKeys(ctx, duplicateKeySPKI) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys") - - // With dryRun=false this should block the key. - comment := "key blocked as part of test" - err = privateKeyBlock(ctx, &testCtx.revoker, false, comment, count, duplicateKeySPKI, duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to block issuance for the provided key") - - // With dryRun=false this should result in an error as the key is already blocked. - err = privateKeyBlock(ctx, &testCtx.revoker, false, "", count, duplicateKeySPKI, duplicateKeyFile.Name()) - test.AssertError(t, err, "Attempting to block a key which is already blocked should have failed.") - - // Ensure that the key is now blocked. - keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(ctx, duplicateKeySPKI) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.Assert(t, keyExists, "SPKI hash should not be in blockedKeys") - - // Ensure that the comment was set as expected - commentFromDB, err := testCtx.dbMap.SelectStr(ctx, "SELECT comment from blockedKeys WHERE keyHash = ?", duplicateKeySPKI[:]) - test.AssertNotError(t, err, "Failed to get comment from database") - u, err := user.Current() - test.AssertNotError(t, err, "Failed to get current user") - expectedDBComment := fmt.Sprintf("%s: %s", u.Username, comment) - test.AssertEquals(t, commentFromDB, expectedDBComment) -} - -func TestPrivateKeyRevoke(t *testing.T) { - ctx := context.Background() - testCtx := setup(t) - defer testCtx.cleanUp() - - uniqueEntries, duplicateEntry := setupUniqueTestEntries(t) - testCtx.createAndRegisterEntries(t, uniqueEntries) - testCtx.createAndRegisterEntry(t, duplicateEntry) - - // Write the key contents of our duplicate entry to a temp file. - duplicateKeyFile, err := os.CreateTemp("", "key") - test.AssertNotError(t, err, "failed to create temp file") - der, err := x509.MarshalPKCS8PrivateKey(duplicateEntry.testKey) - test.AssertNotError(t, err, "failed to marshal testKey1 to DER") - err = pem.Encode(duplicateKeyFile, - &pem.Block{ - Type: "PRIVATE KEY", - Bytes: der, - }, - ) - test.AssertNotError(t, err, "failed to PEM encode test key") - test.AssertNotError(t, err, "failed to write to temp file") - defer os.Remove(duplicateKeyFile.Name()) - - // Get the SPKI hash for the provided keypair. - duplicateKeySPKI, err := core.KeyDigest(&duplicateEntry.testKey.PublicKey) - test.AssertNotError(t, err, "Failed to get SPKI hash for dupe.") - - // Query the 'keyHashToSerial' table for certificates with a matching SPKI - // hash. We expect that since this key was re-used we'll find 2 matches. - count, err := testCtx.revoker.countCertsMatchingSPKIHash(ctx, duplicateKeySPKI) - test.AssertNotError(t, err, "countCertsMatchingSPKIHash for dupe failed") - test.AssertEquals(t, count, 2) - - // With dryRun=true this should not revoke certificates or block issuance. - err = privateKeyRevoke(&testCtx.revoker, true, "", count, duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to block issuance for the provided key") - - // Ensure that the key is not blocked, yet. - keyExists, err := testCtx.revoker.spkiHashInBlockedKeys(ctx, duplicateKeySPKI) - test.AssertNotError(t, err, "spkiHashInBlockedKeys failed for key that shouldn't be blocked yet") - test.Assert(t, !keyExists, "SPKI hash should not be in blockedKeys") - - // With dryRun=false this should revoke matching certificates and block the key. - comment := "key blocked as part of test" - err = privateKeyRevoke(&testCtx.revoker, false, comment, count, duplicateKeyFile.Name()) - test.AssertNotError(t, err, "While attempting to block issuance for the provided key") - - // Ensure that the key is now blocked. - keyExists, err = testCtx.revoker.spkiHashInBlockedKeys(ctx, duplicateKeySPKI) - test.AssertNotError(t, err, "spkiHashInBlockedKeys failed for key that should now be blocked") - test.Assert(t, keyExists, "SPKI hash should not be in blockedKeys") - - // Ensure that the comment was set as expected - commentFromDB, err := testCtx.dbMap.SelectStr(ctx, "SELECT comment from blockedKeys WHERE keyHash = ?", duplicateKeySPKI[:]) - test.AssertNotError(t, err, "Failed to get comment from database") - u, err := user.Current() - test.AssertNotError(t, err, "Failed to get current user") - expectedDBComment := fmt.Sprintf("%s: %s", u.Username, comment) - test.AssertEquals(t, commentFromDB, expectedDBComment) -} - -type entry struct { - jwk string - serial *big.Int - names []string - testKey *rsa.PrivateKey - regId int64 - spkiHash core.Sha256Digest -} - -func setupUniqueTestEntries(t *testing.T) ([]*entry, *entry) { - t.Helper() - - // Unique keys for each of our test certificates. - key1, err := rsa.GenerateKey(rand.Reader, 2048) - test.AssertNotError(t, err, "Generating test key 1") - key2, err := rsa.GenerateKey(rand.Reader, 2048) - test.AssertNotError(t, err, "Generating test key 2") - key3, err := rsa.GenerateKey(rand.Reader, 2048) - test.AssertNotError(t, err, "Generating test key 3") - - // Unique JWKs so we can register each of our entries. - testJWK1 := `{"kty":"RSA","n":"yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ","e":"AQAB"}` - testJWK2 := `{"kty":"RSA","n":"qnARLrT7Xz4gRcKyLdydmCr-ey9OuPImX4X40thk3on26FkMznR3fRjs66eLK7mmPcBZ6uOJseURU6wAaZNmemoYx1dMvqvWWIyiQleHSD7Q8vBrhR6uIoO4jAzJZR-ChzZuSDt7iHN-3xUVspu5XGwXU_MVJZshTwp4TaFx5elHIT_ObnTvTOU3Xhish07AbgZKmWsVbXh5s-CrIicU4OexJPgunWZ_YJJueOKmTvnLlTV4MzKR2oZlBKZ27S0-SfdV_QDx_ydle5oMAyKVtlAV35cyPMIsYNwgUGBCdY_2Uzi5eX0lTc7MPRwz6qR1kip-i59VcGcUQgqHV6Fyqw","e":"AQAB"}` - testJWK3 := `{"kty":"RSA","n":"uTQER6vUA1RDixS8xsfCRiKUNGRzzyIK0MhbS2biClShbb0hSx2mPP7gBvis2lizZ9r-y9hL57kNQoYCKndOBg0FYsHzrQ3O9AcoV1z2Mq-XhHZbFrVYaXI0M3oY9BJCWog0dyi3XC0x8AxC1npd1U61cToHx-3uSvgZOuQA5ffEn5L38Dz1Ti7OV3E4XahnRJvejadUmTkki7phLBUXm5MnnyFm0CPpf6ApV7zhLjN5W-nV0WL17o7v8aDgV_t9nIdi1Y26c3PlCEtiVHZcebDH5F1Deta3oLLg9-g6rWnTqPbY3knffhp4m0scLD6e33k8MtzxDX_D7vHsg0_X1w","e":"AQAB"}` - testJWK4 := `{"kty":"RSA","n":"qih-cx32M0wq8MhhN-kBi2xPE-wnw4_iIg1hWO5wtBfpt2PtWikgPuBT6jvK9oyQwAWbSfwqlVZatMPY_-3IyytMNb9R9OatNr6o5HROBoyZnDVSiC4iMRd7bRl_PWSIqj_MjhPNa9cYwBdW5iC3jM5TaOgmp0-YFm4tkLGirDcIBDkQYlnv9NKILvuwqkapZ7XBixeqdCcikUcTRXW5unqygO6bnapzw-YtPsPPlj4Ih3SvK4doyziPV96U8u5lbNYYEzYiW1mbu9n0KLvmKDikGcdOpf6-yRa_10kMZyYQatY1eclIKI0xb54kbluEl0GQDaL5FxLmiKeVnsapzw","e":"AQAB"}` - return []*entry{ - {jwk: testJWK1, serial: big.NewInt(1), names: []string{"example-1337.com"}, testKey: key1}, - {jwk: testJWK2, serial: big.NewInt(2), names: []string{"example-1338.com"}, testKey: key2}, - {jwk: testJWK3, serial: big.NewInt(3), names: []string{"example-1339.com"}, testKey: key3}, - }, - &entry{jwk: testJWK4, serial: big.NewInt(4), names: []string{"example-1336.com"}, testKey: key1} -} - -type testCtx struct { - revoker revoker - ssa sapb.StorageAuthorityClient - dbMap *db.WrappedMap - cleanUp func() - issuer *issuance.Certificate - signer crypto.Signer - log *blog.Mock -} - -func (c testCtx) addRegistration(t *testing.T, names []string, jwk string) int64 { - t.Helper() - initialIP, err := net.ParseIP("127.0.0.1").MarshalText() - test.AssertNotError(t, err, "Failed to create initialIP") - - reg := &corepb.Registration{ - Id: 1, - Contact: []string{fmt.Sprintf("hello@%s", names[0])}, - Key: []byte(jwk), - InitialIP: initialIP, - } - - reg, err = c.ssa.NewRegistration(context.Background(), reg) - test.AssertNotError(t, err, "Failed to store test registration") - return reg.Id -} - -func (c testCtx) addCertificate(t *testing.T, serial *big.Int, names []string, pubKey rsa.PublicKey, regId int64) *x509.Certificate { - t.Helper() - template := &x509.Certificate{ - SerialNumber: serial, - Subject: pkix.Name{Organization: []string{"tests"}}, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(0, 0, 1), - DNSNames: names, - } - - rawCert, err := x509.CreateCertificate(rand.Reader, template, c.issuer.Certificate, &pubKey, c.signer) - test.AssertNotError(t, err, "Failed to generate test cert") - - _, err = c.ssa.AddPrecertificate( - context.Background(), &sapb.AddCertificateRequest{ - Der: rawCert, - RegID: regId, - Issued: timestamppb.New(time.Now()), - IssuerNameID: 1, - }, - ) - test.AssertNotError(t, err, "Failed to add test precert") - - cert, err := x509.ParseCertificate(rawCert) - test.AssertNotError(t, err, "Failed to parse test cert") - return cert -} - -func (c testCtx) createAndRegisterEntries(t *testing.T, entries []*entry) { - t.Helper() - for _, entry := range entries { - c.createAndRegisterEntry(t, entry) - } -} - -func (c testCtx) createAndRegisterEntry(t *testing.T, e *entry) { - t.Helper() - e.regId = c.addRegistration(t, e.names, e.jwk) - cert := c.addCertificate(t, e.serial, e.names, e.testKey.PublicKey, e.regId) - var err error - e.spkiHash, err = core.KeyDigest(cert.PublicKey) - test.AssertNotError(t, err, "Failed to get SPKI hash") -} - -func setup(t *testing.T) testCtx { - t.Helper() - log := blog.UseMock() - fc := clock.NewFake() - - // Set some non-zero time for GRPC requests to be non-nil. - fc.Set(time.Now()) - - dbMap, err := sa.DBMapForTest(vars.DBConnSA) - if err != nil { - t.Fatalf("Failed to create dbMap: %s", err) - } - incidentsDbMap, err := sa.DBMapForTest(vars.DBConnIncidents) - test.AssertNotError(t, err, "Couldn't create test dbMap") - - ssa, err := sa.NewSQLStorageAuthority(dbMap, dbMap, incidentsDbMap, 1, 0, fc, log, metrics.NoopRegisterer) - if err != nil { - t.Fatalf("Failed to create SA: %s", err) - } - cleanUp := func() { - test.ResetBoulderTestDatabase(t) - test.ResetIncidentsTestDatabase(t) - } - - issuer, err := issuance.LoadCertificate("../../test/hierarchy/int-r3.cert.pem") - test.AssertNotError(t, err, "Failed to load test issuer") - - signer, err := test.LoadSigner("../../test/hierarchy/int-r3.key.pem") - test.AssertNotError(t, err, "Failed to load test signer") - - ra := ra.NewRegistrationAuthorityImpl( - fc, - log, - metrics.NoopRegisterer, - 1, - goodkey.KeyPolicy{}, - 100, - 300*24*time.Hour, - 7*24*time.Hour, - nil, - nil, - 0, - 0, - nil, - &mockPurger{}, - []*issuance.Certificate{issuer}, - ) - ra.SA = isa.SA{Impl: ssa} - ra.OCSP = &mockOCSPA{} - rac := ira.RA{Impl: ra} - - return testCtx{ - revoker: revoker{rac, isa.SA{Impl: ssa}, dbMap, fc, log}, - ssa: isa.SA{Impl: ssa}, - dbMap: dbMap, - cleanUp: cleanUp, - issuer: issuer, - signer: signer, - log: log, - } -} From 7ddb2be3f950785b1fbf1f7e2f906a5481555565 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Tue, 5 Mar 2024 14:13:21 -0800 Subject: [PATCH 09/17] Update CI to go1.21.8 and go1.22.1 (#7356) Security releases announced here: https://groups.google.com/g/golang-announce/c/5pwGVUPoMbg --- .github/workflows/boulder-ci.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- .github/workflows/try-release.yml | 4 ++-- docker-compose.yml | 4 ++-- test/boulder-tools/tag_and_upload.sh | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/boulder-ci.yml b/.github/workflows/boulder-ci.yml index f1ef9997ef1..9ff8b102d13 100644 --- a/.github/workflows/boulder-ci.yml +++ b/.github/workflows/boulder-ci.yml @@ -36,8 +36,8 @@ jobs: matrix: # Add additional docker image tags here and all tests will be run with the additional image. BOULDER_TOOLS_TAG: - - go1.21.5_2024-02-14 - - go1.22.0_2024-02-14 + - go1.21.8_2024-03-05 + - go1.22.1_2024-03-05 # Tests command definitions. Use the entire "docker compose" command you want to run. tests: # Run ./test.sh --help for a description of each of the flags. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 621db8c60bd..017d9fa0ddb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,8 +15,8 @@ jobs: fail-fast: false matrix: GO_VERSION: - - "1.21.5" - - "1.22.0" + - "1.21.8" + - "1.22.1" runs-on: ubuntu-20.04 permissions: contents: write diff --git a/.github/workflows/try-release.yml b/.github/workflows/try-release.yml index 3dcb7787742..d3194d7160e 100644 --- a/.github/workflows/try-release.yml +++ b/.github/workflows/try-release.yml @@ -15,8 +15,8 @@ jobs: fail-fast: false matrix: GO_VERSION: - - "1.21.5" - - "1.22.0" + - "1.21.8" + - "1.22.1" runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 diff --git a/docker-compose.yml b/docker-compose.yml index 928c11bec25..54cb2700ed6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,9 @@ services: image: letsencrypt/boulder-tools:${BOULDER_TOOLS_TAG:-latest} build: context: test/boulder-tools/ - # Should match one of the GO_DEV_VERSIONS in test/boulder-tools/tag_and_upload.sh. + # Should match one of the GO_CI_VERSIONS in test/boulder-tools/tag_and_upload.sh. args: - GO_VERSION: 1.21.5 + GO_VERSION: 1.21.8 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. diff --git a/test/boulder-tools/tag_and_upload.sh b/test/boulder-tools/tag_and_upload.sh index e0f6c57556f..0a02167eb01 100755 --- a/test/boulder-tools/tag_and_upload.sh +++ b/test/boulder-tools/tag_and_upload.sh @@ -12,7 +12,7 @@ DOCKER_REPO="letsencrypt/boulder-tools" # .github/workflows/release.yml, # .github/workflows/try-release.yml if appropriate, # and .github/workflows/boulder-ci.yml with the new container tag. -GO_CI_VERSIONS=( "1.21.5" "1.22.0" ) +GO_CI_VERSIONS=( "1.21.8" "1.22.1" ) echo "Please login to allow push to DockerHub" docker login From 76705b60a222d6f1d23b16998df54fd5d547b0bb Mon Sep 17 00:00:00 2001 From: Shiloh Heurich <1778483+sheurich@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:59:25 -0500 Subject: [PATCH 10/17] s3-test-srv: sync r/w to srv.allShards (#7361) Fixes https://github.com/letsencrypt/boulder/issues/7353 --- test/s3-test-srv/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/s3-test-srv/main.go b/test/s3-test-srv/main.go index 10a3dce2b82..0a0bc985fdf 100644 --- a/test/s3-test-srv/main.go +++ b/test/s3-test-srv/main.go @@ -58,6 +58,8 @@ func (srv *s3TestSrv) handleUpload(w http.ResponseWriter, r *http.Request) { } func (srv *s3TestSrv) handleDownload(w http.ResponseWriter, r *http.Request) { + srv.RLock() + defer srv.RUnlock() body, ok := srv.allShards[r.URL.Path] if !ok { w.WriteHeader(404) From 51231a3942e2b5619f913ab4a71c24bc4dcb84a6 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Wed, 6 Mar 2024 10:10:26 -0800 Subject: [PATCH 11/17] va: log internal error (#7335) In addition to the user-facing error, it's sometimes useful to have the fully detailed internal error. Fixes #7289 --- va/caa.go | 3 +++ va/va.go | 5 +++++ va/va_test.go | 13 +++++++++++++ 3 files changed, 21 insertions(+) diff --git a/va/caa.go b/va/caa.go index 374fa3dea49..4f41b49d6d7 100644 --- a/va/caa.go +++ b/va/caa.go @@ -73,6 +73,7 @@ func (va *ValidationAuthorityImpl) IsCAAValid(ctx context.Context, req *vapb.IsC if err != nil { prob = detailedError(err) logEvent.Error = prob.Error() + logEvent.InternalError = err.Error() prob.Detail = fmt.Sprintf("While processing CAA for %s: %s", req.Domain, prob.Detail) checkResult = "failure" } else if remoteCAAResults != nil { @@ -97,6 +98,8 @@ func (va *ValidationAuthorityImpl) IsCAAValid(ctx context.Context, req *vapb.IsC // If the remote result was a non-nil problem then fail the CAA check if remoteProb != nil { prob = remoteProb + // We only set .Error here, not InternalError, because the remote VA doesn't send + // us the internal error. But that's okay, because it got logged at the remote VA. logEvent.Error = remoteProb.Error() checkResult = "failure" va.log.Infof("CAA check failed due to remote failures: identifier=%v err=%s", diff --git a/va/va.go b/va/va.go index dd743b593bf..c97539083b1 100644 --- a/va/va.go +++ b/va/va.go @@ -320,6 +320,7 @@ type verificationRequestEvent struct { ValidationLatency float64 UsedRSAKEX bool `json:",omitempty"` Error string `json:",omitempty"` + InternalError string `json:",omitempty"` } // ipError is an error type used to pass though the IP address of the remote @@ -714,6 +715,7 @@ func (va *ValidationAuthorityImpl) PerformValidation(ctx context.Context, req *v challenge.Status = core.StatusInvalid challenge.Error = prob logEvent.Error = prob.Error() + logEvent.InternalError = err.Error() } else if remoteResults != nil { if !features.Get().EnforceMultiVA && features.Get().MultiVAFullResults { go func() { @@ -740,6 +742,9 @@ func (va *ValidationAuthorityImpl) PerformValidation(ctx context.Context, req *v prob = remoteProb challenge.Status = core.StatusInvalid challenge.Error = remoteProb + // We only set .Error here, not .InternalError, because the + // remote VA doesn't send us the internal error. But that's ok, + // it got logged at the remote VA. logEvent.Error = remoteProb.Error() va.log.Infof("Validation failed due to remote failures: identifier=%v err=%s", req.Domain, remoteProb) diff --git a/va/va_test.go b/va/va_test.go index ca7c990029c..2aa26daa677 100644 --- a/va/va_test.go +++ b/va/va_test.go @@ -278,6 +278,19 @@ func TestPerformValidationInvalid(t *testing.T) { }, 1) } +func TestInternalErrorLogged(t *testing.T) { + va, mockLog := setup(nil, 0, "", nil, nil) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) + defer cancel() + req := createValidationRequest("nonexistent.com", core.ChallengeTypeHTTP01) + _, err := va.PerformValidation(ctx, req) + test.AssertNotError(t, err, "failed validation should not be an error") + matchingLogs := mockLog.GetAllMatching( + `Validation result JSON=.*"InternalError":"127.0.0.1: Get.*nonexistent.com/\.well-known.*: context deadline exceeded`) + test.AssertEquals(t, len(matchingLogs), 1) +} + func TestPerformValidationValid(t *testing.T) { va, mockLog := setup(nil, 0, "", nil, nil) From 529157ce562fd9cf71c05cabdc5bbea15cc2174b Mon Sep 17 00:00:00 2001 From: Samantha Date: Wed, 6 Mar 2024 13:48:32 -0500 Subject: [PATCH 12/17] ratelimits: Fix transaction building for Failed Authorizations Limit (#7344) - Update the failed authorizations limit to use 'enum:regId:domain' for transactions while maintaining 'enum:regId' for overrides. - Modify the failed authorizations transaction builder to generate a transaction for each order name. - Rename the `FailedAuthorizationsPerAccount` enum to `FailedAuthorizationsPerDomainPerAccount` to align with its corrected implementation. This change is possible because the limit isn't yet deployed in staging or production. Blocks #7346 Part of #5545 --- ratelimits/bucket.go | 91 +++++++++++++++----- ratelimits/names.go | 40 ++++++--- ratelimits/testdata/working_overrides.yml | 6 ++ test/config-next/wfe2-ratelimit-defaults.yml | 2 +- wfe2/wfe.go | 10 +-- 5 files changed, 106 insertions(+), 43 deletions(-) diff --git a/ratelimits/bucket.go b/ratelimits/bucket.go index b382ca536a2..764766c5ff0 100644 --- a/ratelimits/bucket.go +++ b/ratelimits/bucket.go @@ -235,39 +235,84 @@ func (builder *TransactionBuilder) OrdersPerAccountTransaction(regId int64) (Tra return newTransaction(limit, bucketKey, 1) } -// FailedAuthorizationsPerAccountCheckOnlyTransaction returns a check-only -// Transaction for the provided ACME registration Id for the -// FailedAuthorizationsPerAccount limit. -func (builder *TransactionBuilder) FailedAuthorizationsPerAccountCheckOnlyTransaction(regId int64) (Transaction, error) { - bucketKey, err := newRegIdBucketKey(FailedAuthorizationsPerAccount, regId) - if err != nil { - return Transaction{}, err +// FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions returns a slice +// of Transactions for the provided order domain names. An error is returned if +// any of the order domain names are invalid. This method should be used for +// checking capacity, before allowing more authorizations to be created. +func (builder *TransactionBuilder) FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions(regId int64, orderDomains []string, maxNames int) ([]Transaction, error) { + if len(orderDomains) > maxNames { + return nil, fmt.Errorf("order contains more than %d DNS names", maxNames) } - limit, err := builder.getLimit(FailedAuthorizationsPerAccount, bucketKey) + + // FailedAuthorizationsPerDomainPerAccount limit uses the 'enum:regId' + // bucket key format for overrides. + perAccountBucketKey, err := newRegIdBucketKey(FailedAuthorizationsPerDomainPerAccount, regId) if err != nil { - if errors.Is(err, errLimitDisabled) { - return newAllowOnlyTransaction() + return nil, err + } + limit, err := builder.getLimit(FailedAuthorizationsPerDomainPerAccount, perAccountBucketKey) + if err != nil && !errors.Is(err, errLimitDisabled) { + return nil, err + } + + var txns []Transaction + for _, name := range DomainsForRateLimiting(orderDomains) { + // FailedAuthorizationsPerDomainPerAccount limit uses the + // 'enum:regId:domain' bucket key format for transactions. + perDomainPerAccountBucketKey, err := newRegIdDomainBucketKey(FailedAuthorizationsPerDomainPerAccount, regId, name) + if err != nil { + return nil, err } - return Transaction{}, err + + // Add a check-only transaction for each per domain per account bucket. + // The cost is 0, as we are only checking that the account and domain + // pair aren't already over the limit. + txn, err := newCheckOnlyTransaction(limit, perDomainPerAccountBucketKey, 0) + if err != nil { + return nil, err + } + txns = append(txns, txn) } - return newCheckOnlyTransaction(limit, bucketKey, 1) + return txns, nil } -// FailedAuthorizationsPerAccountTransaction returns a Transaction for the -// FailedAuthorizationsPerAccount limit for the provided ACME registration Id. -func (builder *TransactionBuilder) FailedAuthorizationsPerAccountTransaction(regId int64) (Transaction, error) { - bucketKey, err := newRegIdBucketKey(FailedAuthorizationsPerAccount, regId) - if err != nil { - return Transaction{}, err +// FailedAuthorizationsPerDomainPerAccountSpendOnlyTransactions returns a slice +// of Transactions for the provided order domain names. An error is returned if +// any of the order domain names are invalid. This method should be used for +// spending capacity, as a result of a failed authorization. +func (builder *TransactionBuilder) FailedAuthorizationsPerDomainPerAccountSpendOnlyTransactions(regId int64, orderDomains []string, maxNames int) ([]Transaction, error) { + if len(orderDomains) > maxNames { + return nil, fmt.Errorf("order contains more than %d DNS names", maxNames) } - limit, err := builder.getLimit(FailedAuthorizationsPerAccount, bucketKey) + + // FailedAuthorizationsPerDomainPerAccount limit uses the 'enum:regId' + // bucket key format for overrides. + perAccountBucketKey, err := newRegIdBucketKey(FailedAuthorizationsPerDomainPerAccount, regId) if err != nil { - if errors.Is(err, errLimitDisabled) { - return newAllowOnlyTransaction() + return nil, err + } + limit, err := builder.getLimit(FailedAuthorizationsPerDomainPerAccount, perAccountBucketKey) + if err != nil && !errors.Is(err, errLimitDisabled) { + return nil, err + } + + var txns []Transaction + for _, name := range DomainsForRateLimiting(orderDomains) { + // FailedAuthorizationsPerDomainPerAccount limit uses the + // 'enum:regId:domain' bucket key format for transactions. + perDomainPerAccountBucketKey, err := newRegIdDomainBucketKey(FailedAuthorizationsPerDomainPerAccount, regId, name) + if err != nil { + return nil, err } - return Transaction{}, err + + // Add an allow-only transaction for each per domain per account bucket. + txn, err := newSpendOnlyTransaction(limit, perDomainPerAccountBucketKey, 1) + if err != nil { + return nil, err + } + txns = append(txns, txn) } - return newTransaction(limit, bucketKey, 1) + return txns, nil } // CertificatesPerDomainTransactions returns a slice of Transactions for the diff --git a/ratelimits/names.go b/ratelimits/names.go index 4a541d1e657..c92970498b0 100644 --- a/ratelimits/names.go +++ b/ratelimits/names.go @@ -40,11 +40,14 @@ const ( // NewOrdersPerAccount uses bucket key 'enum:regId'. NewOrdersPerAccount - // FailedAuthorizationsPerAccount uses bucket key 'enum:regId', where regId - // is the ACME registration Id of the account. Cost MUST be consumed from - // this bucket only when the authorization is considered "failed". It SHOULD - // be checked before new authorizations are created. - FailedAuthorizationsPerAccount + // FailedAuthorizationsPerDomainPerAccount uses two different bucket keys + // depending on the context: + // - When referenced in an overrides file: uses bucket key 'enum:regId', + // where regId is the ACME registration Id of the account. + // - When referenced in a transaction: uses bucket key 'enum:regId:domain', + // where regId is the ACME registration Id of the account and domain is a + // domain name in the certificate. + FailedAuthorizationsPerDomainPerAccount // CertificatesPerDomain uses bucket key 'enum:domain', where domain is a // domain name in the certificate. @@ -96,14 +99,14 @@ func (n Name) EnumString() string { // nameToString is a map of Name values to string names. var nameToString = map[Name]string{ - Unknown: "Unknown", - NewRegistrationsPerIPAddress: "NewRegistrationsPerIPAddress", - NewRegistrationsPerIPv6Range: "NewRegistrationsPerIPv6Range", - NewOrdersPerAccount: "NewOrdersPerAccount", - FailedAuthorizationsPerAccount: "FailedAuthorizationsPerAccount", - CertificatesPerDomain: "CertificatesPerDomain", - CertificatesPerDomainPerAccount: "CertificatesPerDomainPerAccount", - CertificatesPerFQDNSet: "CertificatesPerFQDNSet", + Unknown: "Unknown", + NewRegistrationsPerIPAddress: "NewRegistrationsPerIPAddress", + NewRegistrationsPerIPv6Range: "NewRegistrationsPerIPv6Range", + NewOrdersPerAccount: "NewOrdersPerAccount", + FailedAuthorizationsPerDomainPerAccount: "FailedAuthorizationsPerDomainPerAccount", + CertificatesPerDomain: "CertificatesPerDomain", + CertificatesPerDomainPerAccount: "CertificatesPerDomainPerAccount", + CertificatesPerFQDNSet: "CertificatesPerFQDNSet", } // validIPAddress validates that the provided string is a valid IP address. @@ -202,10 +205,19 @@ func validateIdForName(name Name, id string) error { // 'enum:ipv6rangeCIDR' return validIPv6RangeCIDR(id) - case NewOrdersPerAccount, FailedAuthorizationsPerAccount: + case NewOrdersPerAccount: // 'enum:regId' return validateRegId(id) + case FailedAuthorizationsPerDomainPerAccount: + // 'enum:regId:domain' for transaction + err := validateRegIdDomain(id) + if err == nil { + return nil + } + // 'enum:regId' for overrides + return validateRegId(id) + case CertificatesPerDomainPerAccount: // 'enum:regId:domain' for transaction err := validateRegIdDomain(id) diff --git a/ratelimits/testdata/working_overrides.yml b/ratelimits/testdata/working_overrides.yml index b07b1c09ef3..23618fda666 100644 --- a/ratelimits/testdata/working_overrides.yml +++ b/ratelimits/testdata/working_overrides.yml @@ -8,3 +8,9 @@ count: 50 period: 2s ids: [2001:0db8:0000::/48] +- FailedAuthorizationsPerDomainPerAccount: + burst: 60 + count: 60 + period: 3s + ids: [1234, 5678] + diff --git a/test/config-next/wfe2-ratelimit-defaults.yml b/test/config-next/wfe2-ratelimit-defaults.yml index f10b5966d30..0192c4bb340 100644 --- a/test/config-next/wfe2-ratelimit-defaults.yml +++ b/test/config-next/wfe2-ratelimit-defaults.yml @@ -10,7 +10,7 @@ CertificatesPerDomain: count: 2 burst: 2 period: 2160h -FailedAuthorizationsPerAccount: +FailedAuthorizationsPerDomainPerAccount: count: 3 burst: 3 period: 5m diff --git a/wfe2/wfe.go b/wfe2/wfe.go index 26d198c1e23..55a0c4e84dc 100644 --- a/wfe2/wfe.go +++ b/wfe2/wfe.go @@ -2064,19 +2064,19 @@ func (wfe *WebFrontEndImpl) newNewOrderLimitTransactions(regId int64, names []st } transactions = append(transactions, txn) - txn, err = wfe.txnBuilder.FailedAuthorizationsPerAccountCheckOnlyTransaction(regId) + failedAuthzTxns, err := wfe.txnBuilder.FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions(regId, names, wfe.maxNames) if err != nil { - logTxnErr(err, ratelimits.FailedAuthorizationsPerAccount) + logTxnErr(err, ratelimits.FailedAuthorizationsPerDomainPerAccount) return nil } - transactions = append(transactions, txn) + transactions = append(transactions, failedAuthzTxns...) - txns, err := wfe.txnBuilder.CertificatesPerDomainTransactions(regId, names, wfe.maxNames) + certsPerDomainTxns, err := wfe.txnBuilder.CertificatesPerDomainTransactions(regId, names, wfe.maxNames) if err != nil { logTxnErr(err, ratelimits.CertificatesPerDomain) return nil } - transactions = append(transactions, txns...) + transactions = append(transactions, certsPerDomainTxns...) txn, err = wfe.txnBuilder.CertificatesPerFQDNSetTransaction(names) if err != nil { From 9b05c38eb38a1a2a69d3f41749169c233b25c31e Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Wed, 6 Mar 2024 11:06:18 -0800 Subject: [PATCH 13/17] Bump Go version used by govulncheck (#7362) --- .github/workflows/boulder-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/boulder-ci.yml b/.github/workflows/boulder-ci.yml index 9ff8b102d13..206c89a01c6 100644 --- a/.github/workflows/boulder-ci.yml +++ b/.github/workflows/boulder-ci.yml @@ -104,7 +104,7 @@ jobs: # When set to true, GitHub cancels all in-progress jobs if any matrix job fails. Default: true fail-fast: false matrix: - go-version: [ '1.21.5' ] + go-version: [ '1.21.8' ] steps: # Checks out your repository under $GITHUB_WORKSPACE, so your job can access it From 62153579dba3415d25c79533254fc25175c07e19 Mon Sep 17 00:00:00 2001 From: Phil Porada Date: Thu, 7 Mar 2024 13:03:10 -0500 Subject: [PATCH 14/17] ceremony: Add post-issuance linting (#7364) Adds post-issuance zlint linting to the `rootCeremony`, `intermediateCeremony`, and `crossCertCeremony` ceremonies. It calls zlint directly rather than using the existing `issueLintCertAndPerformLinting` because the throwaway linting key pair is unnecessary at this point. Fixes https://github.com/letsencrypt/boulder/issues/7354 --- cmd/ceremony/main.go | 52 ++++++++++++++++++++++++++++++++++++++- cmd/ceremony/main_test.go | 28 +++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/cmd/ceremony/main.go b/cmd/ceremony/main.go index f01f057d097..ee881f8a038 100644 --- a/cmd/ceremony/main.go +++ b/cmd/ceremony/main.go @@ -21,6 +21,9 @@ import ( "golang.org/x/crypto/ocsp" "gopkg.in/yaml.v3" + zlintx509 "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3" + "github.com/letsencrypt/boulder/goodkey" "github.com/letsencrypt/boulder/linter" "github.com/letsencrypt/boulder/pkcs11helpers" @@ -60,6 +63,38 @@ func issueLintCertAndPerformLinting(tbs, issuer *x509.Certificate, subjectPubKey return lc, nil } +// postIssuanceLinting performs post-issuance linting on the raw bytes of a +// given certificate with the same set of lints as +// issueLintCertAndPerformLinting. The public key is also checked by the GoodKey +// package. +func postIssuanceLinting(fc *x509.Certificate, skipLints []string) error { + if fc == nil { + return fmt.Errorf("certificate was not provided") + } + parsed, err := zlintx509.ParseCertificate(fc.Raw) + if err != nil { + // If zlintx509.ParseCertificate fails, the certificate is too broken to + // lint. This should be treated as ZLint rejecting the certificate + return fmt.Errorf("unable to parse certificate: %s", err) + } + registry, err := linter.NewRegistry(skipLints) + if err != nil { + return fmt.Errorf("unable to create zlint registry: %s", err) + } + lintRes := zlint.LintCertificateEx(parsed, registry) + err = linter.ProcessResultSet(lintRes) + if err != nil { + return err + } + err = kp.GoodKey(context.Background(), fc.PublicKey) + if err != nil { + return err + } + fmt.Print() + + return nil +} + type keyGenConfig struct { Type string `yaml:"type"` RSAModLength uint `yaml:"rsa-mod-length"` @@ -615,10 +650,15 @@ func rootCeremony(configBytes []byte) error { if !bytes.Equal(lintCert.RawSubject, lintCert.RawIssuer) { return fmt.Errorf("mismatch between self-signed lintCert RawSubject and RawIssuer DER bytes: \"%x\" != \"%x\"", lintCert.RawSubject, lintCert.RawIssuer) } - _, err = signAndWriteCert(template, template, lintCert, keyInfo.key, signer, config.Outputs.CertificatePath) + finalCert, err := signAndWriteCert(template, template, lintCert, keyInfo.key, signer, config.Outputs.CertificatePath) + if err != nil { + return err + } + err = postIssuanceLinting(finalCert, config.SkipLints) if err != nil { return err } + log.Printf("Post issuance linting completed for %s\n", config.Outputs.CertificatePath) return nil } @@ -673,6 +713,11 @@ func intermediateCeremony(configBytes []byte, ct certType) error { if !bytes.Equal(lintCert.RawTBSCertificate, finalCert.RawTBSCertificate) { return fmt.Errorf("mismatch between lintCert and finalCert RawTBSCertificate DER bytes: \"%x\" != \"%x\"", lintCert.RawTBSCertificate, finalCert.RawTBSCertificate) } + err = postIssuanceLinting(finalCert, config.SkipLints) + if err != nil { + return err + } + log.Printf("Post issuance linting completed for %s\n", config.Outputs.CertificatePath) return nil } @@ -761,6 +806,11 @@ func crossCertCeremony(configBytes []byte, ct certType) error { if !bytes.Equal(lintCert.RawTBSCertificate, finalCert.RawTBSCertificate) { return fmt.Errorf("mismatch between lintCert and finalCert RawTBSCertificate DER bytes: \"%x\" != \"%x\"", lintCert.RawTBSCertificate, finalCert.RawTBSCertificate) } + err = postIssuanceLinting(finalCert, config.SkipLints) + if err != nil { + return err + } + log.Printf("Post issuance linting completed for %s\n", config.Outputs.CertificatePath) return nil } diff --git a/cmd/ceremony/main_test.go b/cmd/ceremony/main_test.go index 1f7572d9ecd..1f0a3fb445b 100644 --- a/cmd/ceremony/main_test.go +++ b/cmd/ceremony/main_test.go @@ -1,10 +1,18 @@ package main import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" "fmt" "io/fs" + "math/big" "strings" "testing" + "time" + + "github.com/jmhodges/clock" "github.com/letsencrypt/boulder/test" ) @@ -1392,3 +1400,23 @@ func TestSignAndWriteNoLintCert(t *testing.T) { test.AssertError(t, err, "should have failed because no lintCert was provided") test.AssertDeepEquals(t, err, fmt.Errorf("linting was not performed prior to issuance")) } + +func TestPostIssuanceLinting(t *testing.T) { + clk := clock.New() + err := postIssuanceLinting(nil, nil) + test.AssertError(t, err, "should have failed because no certificate was provided") + + testKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + test.AssertNotError(t, err, "unable to generate ECDSA private key") + template := &x509.Certificate{ + NotAfter: clk.Now().Add(1 * time.Hour), + DNSNames: []string{"example.com"}, + SerialNumber: big.NewInt(1), + } + certDer, err := x509.CreateCertificate(rand.Reader, template, template, &testKey.PublicKey, testKey) + test.AssertNotError(t, err, "unable to create certificate") + parsedCert, err := x509.ParseCertificate(certDer) + test.AssertNotError(t, err, "unable to parse DER bytes") + err = postIssuanceLinting(parsedCert, nil) + test.AssertNotError(t, err, "should not have errored") +} From 8a74de18abe9c3255ff07fd20e2831dfa3540e3b Mon Sep 17 00:00:00 2001 From: Phil Porada Date: Thu, 7 Mar 2024 15:17:23 -0500 Subject: [PATCH 15/17] ceremony: Remove unnecessary fmt.Print (#7368) I accidentally left this print line in while working on https://github.com/letsencrypt/boulder/pull/7364 and forgot to clean it up. --- cmd/ceremony/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/ceremony/main.go b/cmd/ceremony/main.go index ee881f8a038..a68512f9bc8 100644 --- a/cmd/ceremony/main.go +++ b/cmd/ceremony/main.go @@ -90,7 +90,6 @@ func postIssuanceLinting(fc *x509.Certificate, skipLints []string) error { if err != nil { return err } - fmt.Print() return nil } From c110a3e6c956377f4955190fe70446b694a9e911 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Thu, 7 Mar 2024 12:47:33 -0800 Subject: [PATCH 16/17] Update Review Requirements (#7363) Make the Review Requirements section of CONTRIBUTING.md more accurately reflect our actual policy and behavior, and include a clarification for external contributions. --- docs/CONTRIBUTING.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 09b311fd881..7cefe6dde94 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -12,12 +12,18 @@ guidelines for Boulder contributions. # Review Requirements -* All pull requests must receive at least one approval through the GitHub UI. -* We indicate review approval through GitHub's code review facility. +* All pull requests must receive at least one approval by a [CODEOWNER](../CODEOWNERS) other than the author. This is enforced by GitHub itself. +* All pull requests should receive at least two approvals by [Trusted Contributors](https://github.com/letsencrypt/cp-cps/blob/main/CP-CPS.md#161-definitions). + This requirement may be waived when: + * the change only modifies documentation; + * the change only modifies tests; + * in exceptional circumstances, such as when no second reviewer is available at all. + + This requirement should not be waived when: + * the change is not written by a Trusted Contributor, to ensure that at least two TCs have eyes on it. * New commits pushed to a branch invalidate previous reviews. In other words, a reviewer must give positive reviews of a branch after its most recent pushed commit. -* You cannot review your own code. * If a branch contains commits from multiple authors, it needs a reviewer who is not an author of commits on that branch. * Review changes to or addition of tests just as rigorously as you review code From 74328338a0f6aee91e0d436cca46136edab6ec66 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Thu, 7 Mar 2024 14:18:42 -0800 Subject: [PATCH 17/17] Centralize IDP construction and make IDP comparison smarter (#7341) Change crl-storer to only require that 1 of the IssuingDistributionPoint URIs remain consistent between consecutive CRLs in the same sequence. This allows us to add and remove IDP URIs, so we can change our IDP scheme over time. To facilitate this, also move all code which builds or parses IDP extensions into a single place, so that we don't have to have multiple definitions of the same types and similar code in many places. Fixes https://github.com/letsencrypt/boulder/issues/7340 Part of https://github.com/letsencrypt/boulder/issues/7296 --- cmd/ceremony/crl.go | 32 +----------- crl/idp/idp.go | 102 ++++++++++++++++++++++++++++++++++++++ crl/idp/idp_test.go | 40 +++++++++++++++ crl/storer/storer.go | 41 ++++++++------- crl/storer/storer_test.go | 7 +++ issuance/crl.go | 53 +------------------- issuance/crl_test.go | 34 ------------- 7 files changed, 176 insertions(+), 133 deletions(-) create mode 100644 crl/idp/idp.go create mode 100644 crl/idp/idp_test.go diff --git a/cmd/ceremony/crl.go b/cmd/ceremony/crl.go index 65d00a7b6cd..98790d906df 100644 --- a/cmd/ceremony/crl.go +++ b/cmd/ceremony/crl.go @@ -3,14 +3,13 @@ package main import ( "crypto" "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" "encoding/pem" "errors" "fmt" "math/big" "time" + "github.com/letsencrypt/boulder/crl/idp" "github.com/letsencrypt/boulder/linter" ) @@ -37,7 +36,7 @@ func generateCRL(signer crypto.Signer, issuer *x509.Certificate, thisUpdate, nex return nil, errors.New("nextUpdate must be less than 12 months after thisUpdate") } // Add the Issuing Distribution Point extension. - idp, err := makeIDPExt() + idp, err := idp.MakeCACertsExt() if err != nil { return nil, fmt.Errorf("creating IDP extension: %w", err) } @@ -60,30 +59,3 @@ func generateCRL(signer crypto.Signer, issuer *x509.Certificate, thisUpdate, nex return pem.EncodeToMemory(&pem.Block{Type: "X509 CRL", Bytes: crlBytes}), nil } - -// issuingDistributionPoint represents the ASN.1 IssuingDistributionPoint -// SEQUENCE as defined in RFC 5280 Section 5.2.5. We only use one of the fields, -// all others are omitted. -// https://datatracker.ietf.org/doc/html/rfc5280#page-66 -type issuingDistributionPoint struct { - OnlyContainsCACerts bool `asn1:"optional,tag:2"` -} - -// makeIDPExt returns a critical IssuingDistributionPoint extension enabling the -// OnlyContainsCACerts boolean. -func makeIDPExt() (*pkix.Extension, error) { - val := issuingDistributionPoint{ - OnlyContainsCACerts: true, - } - - valBytes, err := asn1.Marshal(val) - if err != nil { - return nil, err - } - - return &pkix.Extension{ - Id: asn1.ObjectIdentifier{2, 5, 29, 28}, // id-ce-issuingDistributionPoint - Value: valBytes, - Critical: true, - }, nil -} diff --git a/crl/idp/idp.go b/crl/idp/idp.go new file mode 100644 index 00000000000..05409628817 --- /dev/null +++ b/crl/idp/idp.go @@ -0,0 +1,102 @@ +package idp + +import ( + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" +) + +var idpOID = asn1.ObjectIdentifier{2, 5, 29, 28} // id-ce-issuingDistributionPoint + +// issuingDistributionPoint represents the ASN.1 IssuingDistributionPoint +// SEQUENCE as defined in RFC 5280 Section 5.2.5. We only use three of the +// fields, so the others are omitted. +type issuingDistributionPoint struct { + DistributionPoint distributionPointName `asn1:"optional,tag:0"` + OnlyContainsUserCerts bool `asn1:"optional,tag:1"` + OnlyContainsCACerts bool `asn1:"optional,tag:2"` +} + +// distributionPointName represents the ASN.1 DistributionPointName CHOICE as +// defined in RFC 5280 Section 4.2.1.13. We only use one of the fields, so the +// others are omitted. +type distributionPointName struct { + // Technically, FullName is of type GeneralNames, which is of type SEQUENCE OF + // GeneralName. But GeneralName itself is of type CHOICE, and the ans1.Marhsal + // function doesn't support marshalling structs to CHOICEs, so we have to use + // asn1.RawValue and encode the GeneralName ourselves. + FullName []asn1.RawValue `asn1:"optional,tag:0"` +} + +// MakeUserCertsExt returns a critical IssuingDistributionPoint extension +// containing the given URLs and with the OnlyContainsUserCerts boolean set to +// true. +func MakeUserCertsExt(urls []string) (pkix.Extension, error) { + var gns []asn1.RawValue + for _, url := range urls { + gns = append(gns, asn1.RawValue{ // GeneralName + Class: 2, // context-specific + Tag: 6, // uniformResourceIdentifier, IA5String + Bytes: []byte(url), + }) + } + + val := issuingDistributionPoint{ + DistributionPoint: distributionPointName{FullName: gns}, + OnlyContainsUserCerts: true, + } + + valBytes, err := asn1.Marshal(val) + if err != nil { + return pkix.Extension{}, err + } + + return pkix.Extension{ + Id: idpOID, + Value: valBytes, + Critical: true, + }, nil +} + +// MakeCACertsExt returns a critical IssuingDistributionPoint extension +// asserting the OnlyContainsCACerts boolean. +func MakeCACertsExt() (*pkix.Extension, error) { + val := issuingDistributionPoint{ + OnlyContainsCACerts: true, + } + + valBytes, err := asn1.Marshal(val) + if err != nil { + return nil, err + } + + return &pkix.Extension{ + Id: idpOID, + Value: valBytes, + Critical: true, + }, nil +} + +// GetIDPURIs returns the URIs contained within the issuingDistributionPoint +// extension, if present, or an error otherwise. +func GetIDPURIs(exts []pkix.Extension) ([]string, error) { + for _, ext := range exts { + if ext.Id.Equal(idpOID) { + val := issuingDistributionPoint{} + rest, err := asn1.Unmarshal(ext.Value, &val) + if err != nil { + return nil, fmt.Errorf("parsing IssuingDistributionPoint extension: %w", err) + } + if len(rest) != 0 { + return nil, fmt.Errorf("parsing IssuingDistributionPoint extension: got %d unexpected trailing bytes", len(rest)) + } + var uris []string + for _, generalName := range val.DistributionPoint.FullName { + uris = append(uris, string(generalName.Bytes)) + } + return uris, nil + } + } + return nil, errors.New("no IssuingDistributionPoint extension found") +} diff --git a/crl/idp/idp_test.go b/crl/idp/idp_test.go new file mode 100644 index 00000000000..a142a5913b6 --- /dev/null +++ b/crl/idp/idp_test.go @@ -0,0 +1,40 @@ +package idp + +import ( + "encoding/hex" + "testing" + + "github.com/letsencrypt/boulder/test" +) + +func TestMakeUserCertsExt(t *testing.T) { + t.Parallel() + dehex := func(s string) []byte { r, _ := hex.DecodeString(s); return r } + tests := []struct { + name string + urls []string + want []byte + }{ + { + name: "one (real) url", + urls: []string{"http://prod.c.lencr.org/20506757847264211/126.crl"}, + want: dehex("303AA035A0338631687474703A2F2F70726F642E632E6C656E63722E6F72672F32303530363735373834373236343231312F3132362E63726C8101FF"), + }, + { + name: "two urls", + urls: []string{"http://old.style/12345678/90.crl", "http://new.style/90.crl"}, + want: dehex("3042A03DA03B8620687474703A2F2F6F6C642E7374796C652F31323334353637382F39302E63726C8617687474703A2F2F6E65772E7374796C652F39302E63726C8101FF"), + }, + } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + got, err := MakeUserCertsExt(tc.urls) + test.AssertNotError(t, err, "should never fail to marshal asn1 to bytes") + test.AssertDeepEquals(t, got.Id, idpOID) + test.AssertEquals(t, got.Critical, true) + test.AssertDeepEquals(t, got.Value, tc.want) + }) + } +} diff --git a/crl/storer/storer.go b/crl/storer/storer.go index 29685241530..10b1753c7a7 100644 --- a/crl/storer/storer.go +++ b/crl/storer/storer.go @@ -5,13 +5,12 @@ import ( "context" "crypto/sha256" "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" "encoding/base64" "errors" "fmt" "io" "math/big" + "slices" "time" "github.com/aws/aws-sdk-go-v2/service/s3" @@ -22,6 +21,7 @@ import ( "google.golang.org/protobuf/types/known/emptypb" "github.com/letsencrypt/boulder/crl" + "github.com/letsencrypt/boulder/crl/idp" cspb "github.com/letsencrypt/boulder/crl/storer/proto" "github.com/letsencrypt/boulder/issuance" blog "github.com/letsencrypt/boulder/log" @@ -186,15 +186,30 @@ func (cs *crlStorer) UploadCRL(stream cspb.CRLStorer_UploadCRLServer) error { return fmt.Errorf("parsing previous CRL for %s: %w", crlId, err) } - idp := getIDPExt(crl.Extensions) - prevIdp := getIDPExt(prevCRL.Extensions) - if !bytes.Equal(idp, prevIdp) { - return fmt.Errorf("IDP does not match previous: %x != %x", idp, prevIdp) - } - if crl.Number.Cmp(prevCRL.Number) <= 0 { return fmt.Errorf("crlNumber not strictly increasing: %d <= %d", crl.Number, prevCRL.Number) } + + idpURIs, err := idp.GetIDPURIs(crl.Extensions) + if err != nil { + return fmt.Errorf("getting IDP for %s: %w", crlId, err) + } + + prevURIs, err := idp.GetIDPURIs(prevCRL.Extensions) + if err != nil { + return fmt.Errorf("getting previous IDP for %s: %w", crlId, err) + } + + uriMatch := false + for _, uri := range idpURIs { + if slices.Contains(prevURIs, uri) { + uriMatch = true + break + } + } + if !uriMatch { + return fmt.Errorf("IDP does not match previous: %v !∩ %v", idpURIs, prevURIs) + } } // Finally actually upload the new CRL. @@ -230,13 +245,3 @@ func (cs *crlStorer) UploadCRL(stream cspb.CRLStorer_UploadCRLServer) error { return stream.SendAndClose(&emptypb.Empty{}) } - -// getIDPExt returns the contents of the issuingDistributionPoint extension, if present. -func getIDPExt(exts []pkix.Extension) []byte { - for _, ext := range exts { - if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 28}) { // id-ce-issuingDistributionPoint - return ext.Value - } - } - return nil -} diff --git a/crl/storer/storer_test.go b/crl/storer/storer_test.go index a07d6cc12c7..0c80dfe4b94 100644 --- a/crl/storer/storer_test.go +++ b/crl/storer/storer_test.go @@ -7,6 +7,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/x509" + "crypto/x509/pkix" "errors" "io" "math/big" @@ -20,6 +21,7 @@ import ( "google.golang.org/grpc" "google.golang.org/protobuf/types/known/emptypb" + "github.com/letsencrypt/boulder/crl/idp" cspb "github.com/letsencrypt/boulder/crl/storer/proto" "github.com/letsencrypt/boulder/issuance" blog "github.com/letsencrypt/boulder/log" @@ -307,6 +309,9 @@ func TestUploadCRLSuccess(t *testing.T) { storer, iss := setupTestUploadCRL(t) errs := make(chan error, 1) + idpExt, err := idp.MakeUserCertsExt([]string{"http://c.ex.org"}) + test.AssertNotError(t, err, "creating test IDP extension") + ins := make(chan *cspb.UploadCRLRequest) go func() { errs <- storer.UploadCRL(&fakeUploadCRLServerStream{input: ins}) @@ -329,6 +334,7 @@ func TestUploadCRLSuccess(t *testing.T) { RevokedCertificateEntries: []x509.RevocationListEntry{ {SerialNumber: big.NewInt(123), RevocationTime: time.Now().Add(-time.Hour)}, }, + ExtraExtensions: []pkix.Extension{idpExt}, }, iss.Cert.Certificate, iss.Signer, @@ -346,6 +352,7 @@ func TestUploadCRLSuccess(t *testing.T) { RevokedCertificateEntries: []x509.RevocationListEntry{ {SerialNumber: big.NewInt(123), RevocationTime: time.Now().Add(-time.Hour)}, }, + ExtraExtensions: []pkix.Extension{idpExt}, }, iss.Cert.Certificate, iss.Signer, diff --git a/issuance/crl.go b/issuance/crl.go index 2f36d695cbc..c962bb03fd0 100644 --- a/issuance/crl.go +++ b/issuance/crl.go @@ -3,8 +3,6 @@ package issuance import ( "crypto/rand" "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" "fmt" "math/big" "time" @@ -12,6 +10,7 @@ import ( "github.com/zmap/zlint/v3/lint" "github.com/letsencrypt/boulder/config" + "github.com/letsencrypt/boulder/crl/idp" "github.com/letsencrypt/boulder/linter" ) @@ -92,7 +91,7 @@ func (i *Issuer) IssueCRL(prof *CRLProfile, req *CRLRequest) ([]byte, error) { // contain the new-style CRLDP URL instead. idps = append(idps, fmt.Sprintf("%s/%d/%d.crl", req.DeprecatedIDPBaseURL, i.NameID(), req.Shard)) } - idp, err := makeIDPExt(idps) + idp, err := idp.MakeUserCertsExt(idps) if err != nil { return nil, fmt.Errorf("creating IDP extension: %w", err) } @@ -115,51 +114,3 @@ func (i *Issuer) IssueCRL(prof *CRLProfile, req *CRLRequest) ([]byte, error) { return crlBytes, nil } - -// distributionPointName represents the ASN.1 DistributionPointName CHOICE as -// defined in RFC 5280 Section 4.2.1.13. We only use one of the fields, so the -// others are omitted. -type distributionPointName struct { - // Technically, FullName is of type GeneralNames, which is of type SEQUENCE OF - // GeneralName. But GeneralName itself is of type CHOICE, and the ans1.Marhsal - // function doesn't support marshalling structs to CHOICEs, so we have to use - // asn1.RawValue and encode the GeneralName ourselves. - FullName []asn1.RawValue `asn1:"optional,tag:0"` -} - -// issuingDistributionPoint represents the ASN.1 IssuingDistributionPoint -// SEQUENCE as defined in RFC 5280 Section 5.2.5. We only use two of the fields, -// so the others are omitted. -type issuingDistributionPoint struct { - DistributionPoint distributionPointName `asn1:"optional,tag:0"` - OnlyContainsUserCerts bool `asn1:"optional,tag:1"` -} - -// makeIDPExt returns a critical IssuingDistributionPoint extension containing -// the given URLs and with the OnlyContainsUserCerts boolean set to true. -func makeIDPExt(urls []string) (pkix.Extension, error) { - var gns []asn1.RawValue - for _, url := range urls { - gns = append(gns, asn1.RawValue{ // GeneralName - Class: 2, // context-specific - Tag: 6, // uniformResourceIdentifier, IA5String - Bytes: []byte(url), - }) - } - - val := issuingDistributionPoint{ - DistributionPoint: distributionPointName{FullName: gns}, - OnlyContainsUserCerts: true, - } - - valBytes, err := asn1.Marshal(val) - if err != nil { - return pkix.Extension{}, err - } - - return pkix.Extension{ - Id: asn1.ObjectIdentifier{2, 5, 29, 28}, // id-ce-issuingDistributionPoint - Value: valBytes, - Critical: true, - }, nil -} diff --git a/issuance/crl_test.go b/issuance/crl_test.go index 2f56d8b6867..adc5e089f4d 100644 --- a/issuance/crl_test.go +++ b/issuance/crl_test.go @@ -2,8 +2,6 @@ package issuance import ( "crypto/x509" - "encoding/asn1" - "encoding/hex" "math/big" "testing" "time" @@ -148,35 +146,3 @@ func TestIssueCRL(t *testing.T) { test.AssertError(t, err, "crl issuance with no IDP should fail") test.AssertContains(t, err.Error(), "must contain an issuingDistributionPoint") } - -func TestMakeIDPExt(t *testing.T) { - t.Parallel() - dehex := func(s string) []byte { r, _ := hex.DecodeString(s); return r } - tests := []struct { - name string - urls []string - want []byte - }{ - { - name: "one (real) url", - urls: []string{"http://prod.c.lencr.org/20506757847264211/126.crl"}, - want: dehex("303AA035A0338631687474703A2F2F70726F642E632E6C656E63722E6F72672F32303530363735373834373236343231312F3132362E63726C8101FF"), - }, - { - name: "two urls", - urls: []string{"http://old.style/12345678/90.crl", "http://new.style/90.crl"}, - want: dehex("3042A03DA03B8620687474703A2F2F6F6C642E7374796C652F31323334353637382F39302E63726C8617687474703A2F2F6E65772E7374796C652F39302E63726C8101FF"), - }, - } - for _, tc := range tests { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - got, err := makeIDPExt(tc.urls) - test.AssertNotError(t, err, "should never fail to marshal asn1 to bytes") - test.AssertDeepEquals(t, got.Id, asn1.ObjectIdentifier{2, 5, 29, 28}) - test.AssertEquals(t, got.Critical, true) - test.AssertDeepEquals(t, got.Value, tc.want) - }) - } -}