Compare commits

..

No commits in common. "main" and "v0.20250721.0" have entirely different histories.

13 changed files with 29 additions and 84 deletions

View File

@ -25,11 +25,6 @@ func TLSALPNChallenge01(token string) Challenge {
return newChallenge(ChallengeTypeTLSALPN01, token) return newChallenge(ChallengeTypeTLSALPN01, token)
} }
// DNSAccountChallenge01 constructs a dns-account-01 challenge.
func DNSAccountChallenge01(token string) Challenge {
return newChallenge(ChallengeTypeDNSAccount01, token)
}
// NewChallenge constructs a challenge of the given kind. It returns an // NewChallenge constructs a challenge of the given kind. It returns an
// error if the challenge type is unrecognized. // error if the challenge type is unrecognized.
func NewChallenge(kind AcmeChallenge, token string) (Challenge, error) { func NewChallenge(kind AcmeChallenge, token string) (Challenge, error) {
@ -40,8 +35,6 @@ func NewChallenge(kind AcmeChallenge, token string) (Challenge, error) {
return DNSChallenge01(token), nil return DNSChallenge01(token), nil
case ChallengeTypeTLSALPN01: case ChallengeTypeTLSALPN01:
return TLSALPNChallenge01(token), nil return TLSALPNChallenge01(token), nil
case ChallengeTypeDNSAccount01:
return DNSAccountChallenge01(token), nil
default: default:
return Challenge{}, fmt.Errorf("unrecognized challenge type %q", kind) return Challenge{}, fmt.Errorf("unrecognized challenge type %q", kind)
} }

View File

@ -32,16 +32,12 @@ func TestChallenges(t *testing.T) {
dns01 := DNSChallenge01(token) dns01 := DNSChallenge01(token)
test.AssertNotError(t, dns01.CheckPending(), "CheckConsistencyForClientOffer returned an error") test.AssertNotError(t, dns01.CheckPending(), "CheckConsistencyForClientOffer returned an error")
dnsAccount01 := DNSAccountChallenge01(token)
test.AssertNotError(t, dnsAccount01.CheckPending(), "CheckConsistencyForClientOffer returned an error")
tlsalpn01 := TLSALPNChallenge01(token) tlsalpn01 := TLSALPNChallenge01(token)
test.AssertNotError(t, tlsalpn01.CheckPending(), "CheckConsistencyForClientOffer returned an error") test.AssertNotError(t, tlsalpn01.CheckPending(), "CheckConsistencyForClientOffer returned an error")
test.Assert(t, ChallengeTypeHTTP01.IsValid(), "Refused valid challenge") test.Assert(t, ChallengeTypeHTTP01.IsValid(), "Refused valid challenge")
test.Assert(t, ChallengeTypeDNS01.IsValid(), "Refused valid challenge") test.Assert(t, ChallengeTypeDNS01.IsValid(), "Refused valid challenge")
test.Assert(t, ChallengeTypeTLSALPN01.IsValid(), "Refused valid challenge") test.Assert(t, ChallengeTypeTLSALPN01.IsValid(), "Refused valid challenge")
test.Assert(t, ChallengeTypeDNSAccount01.IsValid(), "Refused valid challenge")
test.Assert(t, !AcmeChallenge("nonsense-71").IsValid(), "Accepted invalid challenge") test.Assert(t, !AcmeChallenge("nonsense-71").IsValid(), "Accepted invalid challenge")
} }

View File

@ -53,16 +53,15 @@ type AcmeChallenge string
// These types are the available challenges // These types are the available challenges
const ( const (
ChallengeTypeHTTP01 = AcmeChallenge("http-01") ChallengeTypeHTTP01 = AcmeChallenge("http-01")
ChallengeTypeDNS01 = AcmeChallenge("dns-01") ChallengeTypeDNS01 = AcmeChallenge("dns-01")
ChallengeTypeTLSALPN01 = AcmeChallenge("tls-alpn-01") ChallengeTypeTLSALPN01 = AcmeChallenge("tls-alpn-01")
ChallengeTypeDNSAccount01 = AcmeChallenge("dns-account-01")
) )
// IsValid tests whether the challenge is a known challenge // IsValid tests whether the challenge is a known challenge
func (c AcmeChallenge) IsValid() bool { func (c AcmeChallenge) IsValid() bool {
switch c { switch c {
case ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01, ChallengeTypeDNSAccount01: case ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01:
return true return true
default: default:
return false return false
@ -229,7 +228,7 @@ func (ch Challenge) RecordsSane() bool {
(ch.ValidationRecord[0].AddressUsed == netip.Addr{}) || len(ch.ValidationRecord[0].AddressesResolved) == 0 { (ch.ValidationRecord[0].AddressUsed == netip.Addr{}) || len(ch.ValidationRecord[0].AddressesResolved) == 0 {
return false return false
} }
case ChallengeTypeDNS01, ChallengeTypeDNSAccount01: case ChallengeTypeDNS01:
if len(ch.ValidationRecord) > 1 { if len(ch.ValidationRecord) > 1 {
return false return false
} }
@ -430,6 +429,16 @@ type CertificateStatus struct {
IssuerNameID int64 `db:"issuerID"` IssuerNameID int64 `db:"issuerID"`
} }
// FQDNSet contains the SHA256 hash of the lowercased, comma joined dNSNames
// contained in a certificate.
type FQDNSet struct {
ID int64
SetHash []byte
Serial string
Issued time.Time
Expires time.Time
}
// SCTDERs is a convenience type // SCTDERs is a convenience type
type SCTDERs [][]byte type SCTDERs [][]byte

View File

@ -59,7 +59,7 @@ func TestChallengeSanityCheck(t *testing.T) {
}`), &accountKey) }`), &accountKey)
test.AssertNotError(t, err, "Error unmarshaling JWK") test.AssertNotError(t, err, "Error unmarshaling JWK")
types := []AcmeChallenge{ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01, ChallengeTypeDNSAccount01} types := []AcmeChallenge{ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01}
for _, challengeType := range types { for _, challengeType := range types {
chall := Challenge{ chall := Challenge{
Type: challengeType, Type: challengeType,
@ -152,8 +152,6 @@ func TestChallengeStringID(t *testing.T) {
test.AssertEquals(t, ch.StringID(), "iFVMwA") test.AssertEquals(t, ch.StringID(), "iFVMwA")
ch.Type = ChallengeTypeHTTP01 ch.Type = ChallengeTypeHTTP01
test.AssertEquals(t, ch.StringID(), "0Gexug") test.AssertEquals(t, ch.StringID(), "0Gexug")
ch.Type = ChallengeTypeDNSAccount01
test.AssertEquals(t, ch.StringID(), "8z2wSg")
} }
func TestFindChallengeByType(t *testing.T) { func TestFindChallengeByType(t *testing.T) {

View File

@ -79,7 +79,7 @@ services:
- setup - setup
bmysql: bmysql:
image: mariadb:10.11.13 image: mariadb:10.6.22
networks: networks:
bouldernet: bouldernet:
aliases: aliases:

2
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.29.17 github.com/aws/aws-sdk-go-v2/config v1.29.17
github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0 github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0
github.com/aws/smithy-go v1.22.4 github.com/aws/smithy-go v1.22.4
github.com/eggsampler/acme/v3 v3.6.2 github.com/eggsampler/acme/v3 v3.6.2-0.20250208073118-0466a0230941
github.com/go-jose/go-jose/v4 v4.1.0 github.com/go-jose/go-jose/v4 v4.1.0
github.com/go-logr/stdr v1.2.2 github.com/go-logr/stdr v1.2.2
github.com/go-sql-driver/mysql v1.9.1 github.com/go-sql-driver/mysql v1.9.1

4
go.sum
View File

@ -70,8 +70,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/eggsampler/acme/v3 v3.6.2 h1:gvyZbQ92wNQLDASVftGpHEdFwPSfg0+17P0lLt09Tp8= github.com/eggsampler/acme/v3 v3.6.2-0.20250208073118-0466a0230941 h1:CnQwymLMJ3MSfjbZQ/bpaLfuXBZuM3LUgAHJ0gO/7d8=
github.com/eggsampler/acme/v3 v3.6.2/go.mod h1:/qh0rKC/Dh7Jj+p4So7DbWmFNzC4dpcpK53r226Fhuo= github.com/eggsampler/acme/v3 v3.6.2-0.20250208073118-0466a0230941/go.mod h1:/qh0rKC/Dh7Jj+p4So7DbWmFNzC4dpcpK53r226Fhuo=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=

View File

@ -142,10 +142,10 @@ func (p *Profile) GenerateValidity(now time.Time) (time.Time, time.Time) {
// Don't use the full maxBackdate, to ensure that the actual backdate remains // Don't use the full maxBackdate, to ensure that the actual backdate remains
// acceptable throughout the rest of the issuance process. // acceptable throughout the rest of the issuance process.
backdate := time.Duration(float64(p.maxBackdate.Nanoseconds()) * 0.9) backdate := time.Duration(float64(p.maxBackdate.Nanoseconds()) * 0.9)
notBefore := now.Add(-1 * backdate).Truncate(time.Second) notBefore := now.Add(-1 * backdate)
// Subtract one second, because certificate validity periods are *inclusive* // Subtract one second, because certificate validity periods are *inclusive*
// of their final second (Baseline Requirements, Section 1.6.1). // of their final second (Baseline Requirements, Section 1.6.1).
notAfter := notBefore.Add(p.maxValidity).Add(-1 * time.Second).Truncate(time.Second) notAfter := notBefore.Add(p.maxValidity).Add(-1 * time.Second)
return notBefore, notAfter return notBefore, notAfter
} }

View File

@ -271,7 +271,7 @@ func initTables(dbMap *borp.DbMap) {
dbMap.AddTableWithName(issuedNameModel{}, "issuedNames").SetKeys(true, "ID") dbMap.AddTableWithName(issuedNameModel{}, "issuedNames").SetKeys(true, "ID")
dbMap.AddTableWithName(core.Certificate{}, "certificates").SetKeys(true, "ID") dbMap.AddTableWithName(core.Certificate{}, "certificates").SetKeys(true, "ID")
dbMap.AddTableWithName(certificateStatusModel{}, "certificateStatus").SetKeys(true, "ID") dbMap.AddTableWithName(certificateStatusModel{}, "certificateStatus").SetKeys(true, "ID")
dbMap.AddTableWithName(fqdnSet{}, "fqdnSets").SetKeys(true, "ID") dbMap.AddTableWithName(core.FQDNSet{}, "fqdnSets").SetKeys(true, "ID")
tableMap := dbMap.AddTableWithName(orderModel{}, "orders").SetKeys(true, "ID") tableMap := dbMap.AddTableWithName(orderModel{}, "orders").SetKeys(true, "ID")
if !features.Get().StoreARIReplacesInOrders { if !features.Get().StoreARIReplacesInOrders {
tableMap.ColMap("Replaces").SetTransient(true) tableMap.ColMap("Replaces").SetTransient(true)

View File

@ -416,17 +416,15 @@ func modelToOrder(om *orderModel) (*corepb.Order, error) {
} }
var challTypeToUint = map[string]uint8{ var challTypeToUint = map[string]uint8{
"http-01": 0, "http-01": 0,
"dns-01": 1, "dns-01": 1,
"tls-alpn-01": 2, "tls-alpn-01": 2,
"dns-account-01": 3,
} }
var uintToChallType = map[uint8]string{ var uintToChallType = map[uint8]string{
0: "http-01", 0: "http-01",
1: "dns-01", 1: "dns-01",
2: "tls-alpn-01", 2: "tls-alpn-01",
3: "dns-account-01",
} }
var identifierTypeToUint = map[string]uint8{ var identifierTypeToUint = map[string]uint8{
@ -901,16 +899,6 @@ type crlEntryModel struct {
RevokedDate time.Time `db:"revokedDate"` RevokedDate time.Time `db:"revokedDate"`
} }
// fqdnSet contains the SHA256 hash of the lowercased, comma joined dNSNames
// contained in a certificate.
type fqdnSet struct {
ID int64
SetHash []byte
Serial string
Issued time.Time
Expires time.Time
}
// orderFQDNSet contains the SHA256 hash of the lowercased, comma joined names // orderFQDNSet contains the SHA256 hash of the lowercased, comma joined names
// from a new-order request, along with the corresponding orderID, the // from a new-order request, along with the corresponding orderID, the
// registration ID, and the order expiry. This is used to find // registration ID, and the order expiry. This is used to find
@ -924,7 +912,7 @@ type orderFQDNSet struct {
} }
func addFQDNSet(ctx context.Context, db db.Inserter, idents identifier.ACMEIdentifiers, serial string, issued time.Time, expires time.Time) error { func addFQDNSet(ctx context.Context, db db.Inserter, idents identifier.ACMEIdentifiers, serial string, issued time.Time, expires time.Time) error {
return db.Insert(ctx, &fqdnSet{ return db.Insert(ctx, &core.FQDNSet{
SetHash: core.HashIdentifiers(idents), SetHash: core.HashIdentifiers(idents),
Serial: serial, Serial: serial,
Issued: issued, Issued: issued,

View File

@ -2632,36 +2632,6 @@ func TestGetValidAuthorizations2(t *testing.T) {
aaa = am.ID aaa = am.ID
} }
var dac int64
{
tokenStr := core.NewToken()
token, err := base64.RawURLEncoding.DecodeString(tokenStr)
test.AssertNotError(t, err, "computing test authorization challenge token")
profile := "test"
attempted := challTypeToUint[string(core.ChallengeTypeDNSAccount01)]
attemptedAt := fc.Now()
vr, _ := json.Marshal([]core.ValidationRecord{})
am := authzModel{
IdentifierType: identifierTypeToUint[string(identifier.TypeDNS)],
IdentifierValue: "aaa",
RegistrationID: 3,
CertificateProfileName: &profile,
Status: statusToUint[core.StatusValid],
Expires: fc.Now().Add(24 * time.Hour),
Challenges: 1 << challTypeToUint[string(core.ChallengeTypeDNSAccount01)],
Attempted: &attempted,
AttemptedAt: &attemptedAt,
Token: token,
ValidationError: nil,
ValidationRecord: vr,
}
err = sa.dbMap.Insert(context.Background(), &am)
test.AssertNotError(t, err, "failed to insert valid authz with dns-account-01")
dac = am.ID
}
for _, tc := range []struct { for _, tc := range []struct {
name string name string
regID int64 regID int64
@ -2678,14 +2648,6 @@ func TestGetValidAuthorizations2(t *testing.T) {
validUntil: fc.Now().Add(time.Hour), validUntil: fc.Now().Add(time.Hour),
wantIDs: []int64{aaa}, wantIDs: []int64{aaa},
}, },
{
name: "happy path, dns-account-01 challenge",
regID: 3,
identifiers: []*corepb.Identifier{identifier.NewDNS("aaa").ToProto()},
profile: "test",
validUntil: fc.Now().Add(time.Hour),
wantIDs: []int64{dac},
},
{ {
name: "different identifier type", name: "different identifier type",
regID: 1, regID: 1,

View File

@ -60,11 +60,10 @@ boulder_setup:
-git clone --depth 1 https://github.com/letsencrypt/boulder.git $(BOULDER_PATH) -git clone --depth 1 https://github.com/letsencrypt/boulder.git $(BOULDER_PATH)
(cd $(BOULDER_PATH); git checkout -f main && git reset --hard HEAD && git pull -q) (cd $(BOULDER_PATH); git checkout -f main && git reset --hard HEAD && git pull -q)
make boulder_stop make boulder_stop
(cd $(BOULDER_PATH); docker compose run --rm bsetup)
# runs an instance of boulder # runs an instance of boulder
boulder_start: boulder_start:
docker-compose -f $(BOULDER_PATH)/docker-compose.yml -f $(BOULDER_PATH)/docker-compose.next.yml -f docker-compose.boulder-temp.yml up -d docker-compose -f $(BOULDER_PATH)/docker-compose.yml -f docker-compose.boulder-temp.yml up -d
# waits until boulder responds # waits until boulder responds
boulder_wait: boulder_wait:

2
vendor/modules.txt vendored
View File

@ -140,7 +140,7 @@ github.com/cespare/xxhash/v2
# github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f # github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
## explicit ## explicit
github.com/dgryski/go-rendezvous github.com/dgryski/go-rendezvous
# github.com/eggsampler/acme/v3 v3.6.2 # github.com/eggsampler/acme/v3 v3.6.2-0.20250208073118-0466a0230941
## explicit; go 1.11 ## explicit; go 1.11
github.com/eggsampler/acme/v3 github.com/eggsampler/acme/v3
# github.com/felixge/httpsnoop v1.0.4 # github.com/felixge/httpsnoop v1.0.4