Skip to content

Commit

Permalink
Merge branch 'main' into newnewtxnbuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
jprenken authored Dec 10, 2024
2 parents 655ccfe + 1b7b9a7 commit 81b616b
Show file tree
Hide file tree
Showing 21 changed files with 1,520 additions and 371 deletions.
2 changes: 1 addition & 1 deletion cmd/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func newAdmin(configFile string, dryRun bool) (*admin, error) {
return nil, fmt.Errorf("parsing config file: %w", err)
}

scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.Admin.DebugAddr)
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, "")
defer oTelShutdown(context.Background())
logger.Info(cmd.VersionString())

Expand Down
1 change: 1 addition & 0 deletions cmd/admin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Config struct {
RAService *cmd.GRPCClientConfig
SAService *cmd.GRPCClientConfig

// Deprecated: DebugAddr is no longer used.
DebugAddr string

Features features.Config
Expand Down
7 changes: 5 additions & 2 deletions cmd/boulder-ra/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/letsencrypt/boulder/ratelimits"
bredis "github.com/letsencrypt/boulder/redis"
sapb "github.com/letsencrypt/boulder/sa/proto"
"github.com/letsencrypt/boulder/va"
vapb "github.com/letsencrypt/boulder/va/proto"
)

Expand Down Expand Up @@ -288,7 +289,6 @@ func main() {
authorizationLifetime,
pendingAuthorizationLifetime,
pubc,
caaClient,
c.RA.OrderLifetime.Duration,
c.RA.FinalizeTimeout.Duration,
ctp,
Expand All @@ -301,7 +301,10 @@ func main() {
cmd.FailOnError(policyErr, "Couldn't load rate limit policies file")
rai.PA = pa

rai.VA = vac
rai.VA = va.RemoteClients{
VAClient: vac,
CAAClient: caaClient,
}
rai.CA = cac
rai.OCSP = ocspc
rai.SA = sac
Expand Down
10 changes: 6 additions & 4 deletions cmd/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,12 @@ func newVersionCollector() prometheus.Collector {

func newStatsRegistry(addr string, logger blog.Logger) prometheus.Registerer {
registry := prometheus.NewRegistry()

if addr == "" {
logger.Info("No debug listen address specified")
return registry
}

registry.MustRegister(collectors.NewGoCollector())
registry.MustRegister(collectors.NewProcessCollector(
collectors.ProcessCollectorOpts{}))
Expand All @@ -287,10 +293,6 @@ func newStatsRegistry(addr string, logger blog.Logger) prometheus.Registerer {
ErrorLog: promLogger{logger},
}))

if addr == "" {
logger.Err("Debug listen address is not configured")
os.Exit(1)
}
logger.Infof("Debug server listening on %s", addr)

server := http.Server{
Expand Down
18 changes: 18 additions & 0 deletions features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ type Config struct {
// functionality (valid authz reuse) while letting us simplify our code by
// removing pending authz reuse.
NoPendingAuthzReuse bool

// EnforceMPIC enforces SC-067 V3: Require Multi-Perspective Issuance
// Corroboration by:
// - Requiring at least three distinct perspectives, as outlined in the
// "Phased Implementation Timeline" in BRs section 3.2.2.9 ("Effective
// March 15, 2025").
// - Ensuring that corroborating (passing) perspectives reside in at least
// 2 distinct Regional Internet Registries (RIRs) per the "Phased
// Implementation Timeline" in BRs section 3.2.2.9 ("Effective March 15,
// 2026").
// - Including an MPIC summary consisting of: passing perspectives, failing
// perspectives, passing RIRs, and a quorum met for issuance (e.g., 2/3
// or 3/3) in each validation audit log event, per BRs Section 5.4.1,
// Requirement 2.8.
//
// This feature flag also causes CAA checks to happen after all remote VAs
// have passed DCV.
EnforceMPIC bool
}

var fMu = new(sync.RWMutex)
Expand Down
96 changes: 64 additions & 32 deletions ra/ra.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/jmhodges/clock"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/crypto/ocsp"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/emptypb"
Expand Down Expand Up @@ -52,6 +51,7 @@ import (
"github.com/letsencrypt/boulder/ratelimits"
"github.com/letsencrypt/boulder/revocation"
sapb "github.com/letsencrypt/boulder/sa/proto"
"github.com/letsencrypt/boulder/va"
vapb "github.com/letsencrypt/boulder/va/proto"

"github.com/letsencrypt/boulder/web"
Expand All @@ -68,14 +68,6 @@ var (
caaRecheckDuration = -7 * time.Hour
)

type caaChecker interface {
IsCAAValid(
ctx context.Context,
in *vapb.IsCAAValidRequest,
opts ...grpc.CallOption,
) (*vapb.IsCAAValidResponse, error)
}

// RegistrationAuthorityImpl defines an RA.
//
// NOTE: All of the fields in RegistrationAuthorityImpl need to be
Expand All @@ -84,11 +76,10 @@ type RegistrationAuthorityImpl struct {
rapb.UnsafeRegistrationAuthorityServer
CA capb.CertificateAuthorityClient
OCSP capb.OCSPGeneratorClient
VA vapb.VAClient
VA va.RemoteClients
SA sapb.StorageAuthorityClient
PA core.PolicyAuthority
publisher pubpb.PublisherClient
caa caaChecker

clk clock.Clock
log blog.Logger
Expand Down Expand Up @@ -140,7 +131,6 @@ func NewRegistrationAuthorityImpl(
authorizationLifetime time.Duration,
pendingAuthorizationLifetime time.Duration,
pubc pubpb.PublisherClient,
caaClient caaChecker,
orderLifetime time.Duration,
finalizeTimeout time.Duration,
ctp *ctpolicy.CTPolicy,
Expand Down Expand Up @@ -265,7 +255,6 @@ func NewRegistrationAuthorityImpl(
txnBuilder: txnBuilder,
maxNames: maxNames,
publisher: pubc,
caa: caaClient,
orderLifetime: orderLifetime,
finalizeTimeout: finalizeTimeout,
ctpolicy: ctp,
Expand Down Expand Up @@ -849,12 +838,21 @@ func (ra *RegistrationAuthorityImpl) recheckCAA(ctx context.Context, authzs []*c
}
return
}

resp, err := ra.caa.IsCAAValid(ctx, &vapb.IsCAAValidRequest{
Domain: name,
ValidationMethod: method,
AccountURIID: authz.RegistrationID,
})
var resp *vapb.IsCAAValidResponse
var err error
if !features.Get().EnforceMPIC {
resp, err = ra.VA.IsCAAValid(ctx, &vapb.IsCAAValidRequest{
Domain: name,
ValidationMethod: method,
AccountURIID: authz.RegistrationID,
})
} else {
resp, err = ra.VA.DoCAA(ctx, &vapb.IsCAAValidRequest{
Domain: name,
ValidationMethod: method,
AccountURIID: authz.RegistrationID,
})
}
if err != nil {
ra.log.AuditErrf("Rechecking CAA: %s", err)
err = berrors.InternalServerError(
Expand Down Expand Up @@ -1832,6 +1830,35 @@ func (ra *RegistrationAuthorityImpl) resetAccountPausingLimit(ctx context.Contex
}
}

// doDCVAndCAA performs DCV and CAA checks. When EnforceMPIC is enabled, the
// checks are executed sequentially: DCV is performed first and CAA is only
// checked if DCV is successful. Validation records from the DCV check are
// returned even if the CAA check fails. When EnforceMPIC is disabled, DCV and
// CAA checks are performed in the same request.
func (ra *RegistrationAuthorityImpl) checkDCVAndCAA(ctx context.Context, dcvReq *vapb.PerformValidationRequest, caaReq *vapb.IsCAAValidRequest) (*corepb.ProblemDetails, []*corepb.ValidationRecord, error) {
if !features.Get().EnforceMPIC {
performValidationRes, err := ra.VA.PerformValidation(ctx, dcvReq)
if err != nil {
return nil, nil, err
}
return performValidationRes.Problem, performValidationRes.Records, nil
} else {
doDCVRes, err := ra.VA.DoDCV(ctx, dcvReq)
if err != nil {
return nil, nil, err
}
if doDCVRes.Problem != nil {
return doDCVRes.Problem, doDCVRes.Records, nil
}

doCAAResp, err := ra.VA.IsCAAValid(ctx, caaReq)
if err != nil {
return nil, nil, err
}
return doCAAResp.Problem, doDCVRes.Records, nil
}
}

// PerformValidation initiates validation for a specific challenge associated
// with the given base authorization. The authorization and challenge are
// updated based on the results.
Expand Down Expand Up @@ -1916,32 +1943,37 @@ func (ra *RegistrationAuthorityImpl) PerformValidation(
copy(challenges, authz.Challenges)
authz.Challenges = challenges
chall, _ := bgrpc.ChallengeToPB(authz.Challenges[challIndex])
req := vapb.PerformValidationRequest{
DnsName: authz.Identifier.Value,
Challenge: chall,
Authz: &vapb.AuthzMeta{
Id: authz.ID,
RegID: authz.RegistrationID,
checkProb, checkRecords, err := ra.checkDCVAndCAA(
vaCtx,
&vapb.PerformValidationRequest{
DnsName: authz.Identifier.Value,
Challenge: chall,
Authz: &vapb.AuthzMeta{Id: authz.ID, RegID: authz.RegistrationID},
ExpectedKeyAuthorization: expectedKeyAuthorization,
},
ExpectedKeyAuthorization: expectedKeyAuthorization,
}
res, err := ra.VA.PerformValidation(vaCtx, &req)
&vapb.IsCAAValidRequest{
Domain: authz.Identifier.Value,
ValidationMethod: chall.Type,
AccountURIID: authz.RegistrationID,
AuthzID: authz.ID,
},
)
challenge := &authz.Challenges[challIndex]
var prob *probs.ProblemDetails
if err != nil {
prob = probs.ServerInternal("Could not communicate with VA")
ra.log.AuditErrf("Could not communicate with VA: %s", err)
} else {
if res.Problem != nil {
prob, err = bgrpc.PBToProblemDetails(res.Problem)
if checkProb != nil {
prob, err = bgrpc.PBToProblemDetails(checkProb)
if err != nil {
prob = probs.ServerInternal("Could not communicate with VA")
ra.log.AuditErrf("Could not communicate with VA: %s", err)
}
}
// Save the updated records
records := make([]core.ValidationRecord, len(res.Records))
for i, r := range res.Records {
records := make([]core.ValidationRecord, len(checkRecords))
for i, r := range checkRecords {
records[i], err = bgrpc.PBToValidationRecord(r)
if err != nil {
prob = probs.ServerInternal("Records for validation corrupt")
Expand Down
Loading

0 comments on commit 81b616b

Please sign in to comment.