github.com/letsencrypt/boulder@v0.20251208.0/test/load-generator/acme/challenge.go (about) 1 package acme 2 3 import ( 4 "errors" 5 "fmt" 6 mrand "math/rand/v2" 7 "strings" 8 9 "github.com/letsencrypt/boulder/core" 10 ) 11 12 // ChallengeStrategy is an interface describing a strategy for picking 13 // a challenge from a given authorization. 14 type ChallengeStrategy interface { 15 PickChallenge(*core.Authorization) (*core.Challenge, error) 16 } 17 18 const ( 19 // RandomChallengeStrategy is the name for a random challenge selection 20 // strategy that will choose one of the authorization's challenges at random. 21 RandomChallengeStrategy = "RANDOM" 22 // The following challenge strategies will always pick the named challenge 23 // type or return an error if there isn't a challenge of that type to pick. 24 HTTP01ChallengeStrategy = "HTTP-01" 25 DNS01ChallengeStrategy = "DNS-01" 26 TLSALPN01ChallengeStrategy = "TLS-ALPN-01" 27 ) 28 29 // NewChallengeStrategy returns the ChallengeStrategy for the given 30 // ChallengeStrategyName, or an error if it is unknown. 31 func NewChallengeStrategy(rawName string) (ChallengeStrategy, error) { 32 var preferredType core.AcmeChallenge 33 switch name := strings.ToUpper(rawName); name { 34 case RandomChallengeStrategy: 35 return &randomChallengeStrategy{}, nil 36 case HTTP01ChallengeStrategy: 37 preferredType = core.ChallengeTypeHTTP01 38 case DNS01ChallengeStrategy: 39 preferredType = core.ChallengeTypeDNS01 40 case TLSALPN01ChallengeStrategy: 41 preferredType = core.ChallengeTypeTLSALPN01 42 default: 43 return nil, fmt.Errorf("ChallengeStrategy %q unknown", name) 44 } 45 46 return &preferredTypeChallengeStrategy{ 47 preferredType: preferredType, 48 }, nil 49 } 50 51 var ( 52 ErrPickChallengeNilAuthz = errors.New("PickChallenge: provided authorization can not be nil") 53 ErrPickChallengeAuthzMissingChallenges = errors.New("PickChallenge: provided authorization had no challenges") 54 ) 55 56 // randomChallengeStrategy is a ChallengeStrategy implementation that always 57 // returns a random challenge from the given authorization. 58 type randomChallengeStrategy struct { 59 } 60 61 // PickChallenge for a randomChallengeStrategy returns a random challenge from 62 // the authorization. 63 func (strategy randomChallengeStrategy) PickChallenge(authz *core.Authorization) (*core.Challenge, error) { 64 if authz == nil { 65 return nil, ErrPickChallengeNilAuthz 66 } 67 if len(authz.Challenges) == 0 { 68 return nil, ErrPickChallengeAuthzMissingChallenges 69 } 70 return &authz.Challenges[mrand.IntN(len(authz.Challenges))], nil 71 } 72 73 // preferredTypeChallengeStrategy is a ChallengeStrategy implementation that 74 // always returns the authorization's challenge with type matching the 75 // preferredType. 76 type preferredTypeChallengeStrategy struct { 77 preferredType core.AcmeChallenge 78 } 79 80 // PickChallenge for a preferredTypeChallengeStrategy returns the authorization 81 // challenge that has Type equal the preferredType. An error is returned if the 82 // challenge doesn't have an authorization matching the preferredType. 83 func (strategy preferredTypeChallengeStrategy) PickChallenge(authz *core.Authorization) (*core.Challenge, error) { 84 if authz == nil { 85 return nil, ErrPickChallengeNilAuthz 86 } 87 if len(authz.Challenges) == 0 { 88 return nil, ErrPickChallengeAuthzMissingChallenges 89 } 90 for _, chall := range authz.Challenges { 91 if chall.Type == strategy.preferredType { 92 return &chall, nil 93 } 94 } 95 return nil, fmt.Errorf("authorization (ID %q) had no %q type challenge", 96 authz.ID, 97 strategy.preferredType) 98 }