Skip to content

Commit 5ca646c

Browse files
Disallow the use of valid authorizations that used currently disabled challenges for issuance
1 parent b16e788 commit 5ca646c

File tree

6 files changed

+93
-0
lines changed

6 files changed

+93
-0
lines changed

core/interfaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ type PolicyAuthority interface {
108108
WillingToIssue(domain AcmeIdentifier) error
109109
WillingToIssueWildcard(domain AcmeIdentifier) error
110110
ChallengesFor(domain AcmeIdentifier) (challenges []Challenge, validCombinations [][]int, err error)
111+
ChallengeStillAllowed(authz *Authorization) bool
111112
}
112113

113114
// StorageGetter are the Boulder SA's read-only methods

policy/pa.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,3 +453,14 @@ func extractDomainIANASuffix(name string) (string, error) {
453453

454454
return suffix, nil
455455
}
456+
457+
// AuthzStillValid checks if the challenge type that was used in a valid authorization
458+
// is still enabled
459+
func (pa *AuthorityImpl) ChallengeStillAllowed(authz *core.Authorization) bool {
460+
for _, chall := range authz.Challenges {
461+
if chall.Status == core.StatusValid {
462+
return pa.enabledChallenges[chall.Type]
463+
}
464+
}
465+
return false
466+
}

policy/pa_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,3 +461,13 @@ func TestMalformedExactBlacklist(t *testing.T) {
461461
test.AssertError(t, err, "Loaded invalid exact blacklist content without error")
462462
test.AssertEquals(t, err.Error(), "Malformed exact blacklist entry, only one label: \"com\"")
463463
}
464+
465+
func TestChallengeStillAllowed(t *testing.T) {
466+
pa := paImpl(t)
467+
pa.enabledChallenges[core.ChallengeTypeHTTP01] = false
468+
test.Assert(t, !pa.ChallengeStillAllowed(&core.Authorization{}), "pa.ChallengeStillAllowed didn't fail with empty authorization")
469+
test.Assert(t, !pa.ChallengeStillAllowed(&core.Authorization{Challenges: []core.Challenge{{Status: core.StatusPending}}}), "pa.ChallengeStillAllowed didn't fail with no valid challenges")
470+
test.Assert(t, !pa.ChallengeStillAllowed(&core.Authorization{Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}}}), "pa.ChallengeStillAllowed didn't fail with disabled challenge")
471+
472+
test.Assert(t, pa.ChallengeStillAllowed(&core.Authorization{Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeTLSSNI01}}}), "pa.ChallengeStillAllowed failed with enabled challenge")
473+
}

ra/ra.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,9 @@ func (ra *RegistrationAuthorityImpl) checkAuthorizationsCAA(
721721
// Ensure that CAA is rechecked for this name
722722
recheckNames = append(recheckNames, name)
723723
}
724+
if authz != nil && !ra.PA.ChallengeStillAllowed(authz) {
725+
return berrors.UnauthorizedError("challenge used to validate authorization with ID %q no longer allowed", authz.ID)
726+
}
724727
}
725728

726729
if err := ra.recheckCAA(ctx, recheckNames); err != nil {

ra/ra_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,22 +1958,27 @@ func (m *mockSAWithRecentAndOlder) GetValidAuthorizations(
19581958
"recent.com": &core.Authorization{
19591959
Identifier: makeIdentifier("recent.com"),
19601960
Expires: &m.recent,
1961+
Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}},
19611962
},
19621963
"older.com": &core.Authorization{
19631964
Identifier: makeIdentifier("older.com"),
19641965
Expires: &m.older,
1966+
Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}},
19651967
},
19661968
"older2.com": &core.Authorization{
19671969
Identifier: makeIdentifier("older2.com"),
19681970
Expires: &m.older,
1971+
Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}},
19691972
},
19701973
"wildcard.com": &core.Authorization{
19711974
Identifier: makeIdentifier("wildcard.com"),
19721975
Expires: &m.older,
1976+
Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}},
19731977
},
19741978
"*.wildcard.com": &core.Authorization{
19751979
Identifier: makeIdentifier("*.wildcard.com"),
19761980
Expires: &m.older,
1981+
Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}},
19771982
},
19781983
}, nil
19791984
}
@@ -2862,6 +2867,48 @@ func TestUpdateMissingAuthorization(t *testing.T) {
28622867
test.AssertEquals(t, berrors.Is(err, berrors.NotFound), true)
28632868
}
28642869

2870+
func TestDisabledChallengeValidAuthz(t *testing.T) {
2871+
_, _, ra, fc, cleanUp := initAuthorities(t)
2872+
defer cleanUp()
2873+
2874+
challenges := map[string]bool{
2875+
core.ChallengeTypeHTTP01: true,
2876+
}
2877+
pa, err := policy.New(challenges)
2878+
test.AssertNotError(t, err, "Couldn't create PA")
2879+
ra.PA = pa
2880+
2881+
exp := fc.Now().Add(10 * time.Hour)
2882+
2883+
err = ra.checkAuthorizationsCAA(
2884+
context.Background(),
2885+
[]string{"test.com"},
2886+
map[string]*core.Authorization{"test.com": &core.Authorization{
2887+
Expires: &exp,
2888+
Challenges: []core.Challenge{
2889+
{Status: core.StatusValid, Type: core.ChallengeTypeTLSSNI01},
2890+
},
2891+
}},
2892+
0,
2893+
fc.Now(),
2894+
)
2895+
test.AssertError(t, err, "RA didn't prevent use of an authorization which used an disabled challenge type")
2896+
2897+
err = ra.checkAuthorizationsCAA(
2898+
context.Background(),
2899+
[]string{"test.com"},
2900+
map[string]*core.Authorization{"test.com": &core.Authorization{
2901+
Expires: &exp,
2902+
Challenges: []core.Challenge{
2903+
{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01},
2904+
},
2905+
}},
2906+
0,
2907+
fc.Now(),
2908+
)
2909+
test.AssertNotError(t, err, "RA prevented use of an authorization which used an enabled challenge type")
2910+
}
2911+
28652912
var CAkeyPEM = `
28662913
-----BEGIN RSA PRIVATE KEY-----
28672914
MIIJKQIBAAKCAgEAqmM0dEf/J9MCk2ItzevL0dKJ84lVUtf/vQ7AXFi492vFXc3b

sa/sa.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,27 @@ func (ssa *SQLStorageAuthority) getAuthorizations(ctx context.Context, table str
16211621
if auth.Expires == nil {
16221622
continue
16231623
}
1624+
1625+
// Retrieve challenges for the authzvar challObjs []challModel
1626+
var challObjs []challModel
1627+
_, err = ssa.dbMap.Select(
1628+
&challObjs,
1629+
getChallengesQuery,
1630+
map[string]interface{}{"authID": auth.ID},
1631+
)
1632+
if err != nil {
1633+
return nil, err
1634+
}
1635+
var challs []core.Challenge
1636+
for _, c := range challObjs {
1637+
chall, err := modelToChallenge(&c)
1638+
if err != nil {
1639+
return nil, err
1640+
}
1641+
challs = append(challs, chall)
1642+
}
1643+
auth.Challenges = challs
1644+
16241645
if auth.Identifier.Type != core.IdentifierDNS {
16251646
return nil, fmt.Errorf("unknown identifier type: %q on authz id %q", auth.Identifier.Type, auth.ID)
16261647
}

0 commit comments

Comments
 (0)