diff --git a/grpc/pb-marshalling.go b/grpc/pb-marshalling.go index fc34acf51da..c62a5e1417d 100644 --- a/grpc/pb-marshalling.go +++ b/grpc/pb-marshalling.go @@ -188,13 +188,13 @@ func ValidationResultToPB(records []core.ValidationRecord, prob *probs.ProblemDe return nil, err } } - marshalledProbs, err := ProblemDetailsToPB(prob) + marshalledProb, err := ProblemDetailsToPB(prob) if err != nil { return nil, err } return &vapb.ValidationResult{ Records: recordAry, - Problems: marshalledProbs, + Problem: marshalledProb, Perspective: perspective, Rir: rir, }, nil @@ -212,7 +212,7 @@ func pbToValidationResult(in *vapb.ValidationResult) ([]core.ValidationRecord, * return nil, nil, err } } - prob, err := PBToProblemDetails(in.Problems) + prob, err := PBToProblemDetails(in.Problem) if err != nil { return nil, nil, err } diff --git a/ra/ra.go b/ra/ra.go index 9dfcb1d454c..62da21cb1e4 100644 --- a/ra/ra.go +++ b/ra/ra.go @@ -1762,7 +1762,7 @@ func (ra *RegistrationAuthorityImpl) recordValidation(ctx context.Context, authI Attempted: string(challenge.Type), AttemptedAt: validated, ValidationRecords: vr.Records, - ValidationError: vr.Problems, + ValidationError: vr.Problem, }) return err } @@ -1929,8 +1929,8 @@ func (ra *RegistrationAuthorityImpl) PerformValidation( prob = probs.ServerInternal("Could not communicate with VA") ra.log.AuditErrf("Could not communicate with VA: %s", err) } else { - if res.Problems != nil { - prob, err = bgrpc.PBToProblemDetails(res.Problems) + if res.Problem != nil { + prob, err = bgrpc.PBToProblemDetails(res.Problem) if err != nil { prob = probs.ServerInternal("Could not communicate with VA") ra.log.AuditErrf("Could not communicate with VA: %s", err) diff --git a/ra/ra_test.go b/ra/ra_test.go index 594edc17ec4..8969ad8aa4a 100644 --- a/ra/ra_test.go +++ b/ra/ra_test.go @@ -728,7 +728,7 @@ func TestPerformValidationAlreadyValid(t *testing.T) { Url: "http://example.com/", }, }, - Problems: nil, + Problem: nil, } // A subsequent call to perform validation should return nil due @@ -758,7 +758,7 @@ func TestPerformValidationSuccess(t *testing.T) { ResolverAddrs: []string{"rebound"}, }, }, - Problems: nil, + Problem: nil, } now := fc.Now() @@ -901,7 +901,7 @@ func TestPerformValidation_FailedValidationsTriggerPauseIdentifiersRatelimit(t * ResolverAddrs: []string{"rebound"}, }, }, - Problems: &corepb.ProblemDetails{ + Problem: &corepb.ProblemDetails{ Detail: fmt.Sprintf("CAA invalid for %s", domain), }, } @@ -954,7 +954,7 @@ func TestPerformValidation_FailedValidationsTriggerPauseIdentifiersRatelimit(t * ResolverAddrs: []string{"rebound"}, }, }, - Problems: &corepb.ProblemDetails{ + Problem: &corepb.ProblemDetails{ Detail: fmt.Sprintf("CAA invalid for %s", domain), }, } @@ -1034,7 +1034,7 @@ func TestPerformValidation_FailedThenSuccessfulValidationResetsPauseIdentifiersR ResolverAddrs: []string{"rebound"}, }, }, - Problems: &corepb.ProblemDetails{ + Problem: &corepb.ProblemDetails{ Detail: fmt.Sprintf("CAA invalid for %s", domain), }, } @@ -1092,7 +1092,7 @@ func TestPerformValidation_FailedThenSuccessfulValidationResetsPauseIdentifiersR ResolverAddrs: []string{"rebound"}, }, }, - Problems: nil, + Problem: nil, } challIdx = dnsChallIdx(t, authzPB.Challenges) diff --git a/test/v2_integration.py b/test/v2_integration.py index c129eef1358..230d63ba289 100644 --- a/test/v2_integration.py +++ b/test/v2_integration.py @@ -1083,8 +1083,8 @@ def test_http_multiva_threshold_fail(): raise(Exception("no HTTP-01 challenge in failed authz")) if httpChall.error.typ != "urn:ietf:params:acme:error:unauthorized": raise(Exception("expected unauthorized prob, found {0}".format(httpChall.error.typ))) - if not httpChall.error.detail.startswith("During secondary domain validation: "): - raise(Exception("expected 'During secondary domain validation' problem detail, found {0}".format(httpChall.error.detail))) + if not httpChall.error.detail.startswith("During secondary validation: "): + raise(Exception("expected 'During secondary validation' problem detail, found {0}".format(httpChall.error.detail))) class FakeH2ServerHandler(socketserver.BaseRequestHandler): """ diff --git a/va/dns_test.go b/va/dns_test.go index 92a07a47d54..c75fa156149 100644 --- a/va/dns_test.go +++ b/va/dns_test.go @@ -25,8 +25,8 @@ func TestDNSValidationEmpty(t *testing.T) { // metrics checked below are incremented. req := createValidationRequest("empty-txts.com", core.ChallengeTypeDNS01) res, _ := va.PerformValidation(context.Background(), req) - test.AssertEquals(t, res.Problems.ProblemType, "unauthorized") - test.AssertEquals(t, res.Problems.Detail, "No TXT record found at _acme-challenge.empty-txts.com") + test.AssertEquals(t, res.Problem.ProblemType, "unauthorized") + test.AssertEquals(t, res.Problem.Detail, "No TXT record found at _acme-challenge.empty-txts.com") test.AssertMetricWithLabelsEquals(t, va.metrics.validationLatency, prometheus.Labels{ "operation": opChallAndCAA, diff --git a/va/proto/va.pb.go b/va/proto/va.pb.go index f73970cdee5..1e33a925407 100644 --- a/va/proto/va.pb.go +++ b/va/proto/va.pb.go @@ -91,7 +91,9 @@ type IsCAAValidResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Problem *proto.ProblemDetails `protobuf:"bytes,1,opt,name=problem,proto3" json:"problem,omitempty"` + Problem *proto.ProblemDetails `protobuf:"bytes,1,opt,name=problem,proto3" json:"problem,omitempty"` + Perspective string `protobuf:"bytes,3,opt,name=perspective,proto3" json:"perspective,omitempty"` + Rir string `protobuf:"bytes,4,opt,name=rir,proto3" json:"rir,omitempty"` } func (x *IsCAAValidResponse) Reset() { @@ -133,6 +135,20 @@ func (x *IsCAAValidResponse) GetProblem() *proto.ProblemDetails { return nil } +func (x *IsCAAValidResponse) GetPerspective() string { + if x != nil { + return x.Perspective + } + return "" +} + +func (x *IsCAAValidResponse) GetRir() string { + if x != nil { + return x.Rir + } + return "" +} + type PerformValidationRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -265,7 +281,7 @@ type ValidationResult struct { unknownFields protoimpl.UnknownFields Records []*proto.ValidationRecord `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"` - Problems *proto.ProblemDetails `protobuf:"bytes,2,opt,name=problems,proto3" json:"problems,omitempty"` + Problem *proto.ProblemDetails `protobuf:"bytes,2,opt,name=problem,proto3" json:"problem,omitempty"` Perspective string `protobuf:"bytes,3,opt,name=perspective,proto3" json:"perspective,omitempty"` Rir string `protobuf:"bytes,4,opt,name=rir,proto3" json:"rir,omitempty"` } @@ -309,9 +325,9 @@ func (x *ValidationResult) GetRecords() []*proto.ValidationRecord { return nil } -func (x *ValidationResult) GetProblems() *proto.ProblemDetails { +func (x *ValidationResult) GetProblem() *proto.ProblemDetails { if x != nil { - return x.Problems + return x.Problem } return nil } @@ -343,50 +359,53 @@ var file_va_proto_rawDesc = []byte{ 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x52, 0x49, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x52, 0x49, - 0x49, 0x44, 0x22, 0x44, 0x0a, 0x12, 0x49, 0x73, 0x43, 0x41, 0x41, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x49, 0x44, 0x22, 0x78, 0x0a, 0x12, 0x49, 0x73, 0x43, 0x41, 0x41, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, - 0x07, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x22, 0xc4, 0x01, 0x0a, 0x18, 0x50, 0x65, 0x72, - 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x2d, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, - 0x6e, 0x67, 0x65, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x23, - 0x0a, 0x05, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, - 0x76, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x05, 0x61, 0x75, - 0x74, 0x68, 0x7a, 0x12, 0x3a, 0x0a, 0x18, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4b, - 0x65, 0x79, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4b, - 0x65, 0x79, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x31, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x72, 0x65, 0x67, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x72, 0x65, 0x67, - 0x49, 0x44, 0x22, 0xaa, 0x01, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x30, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x30, 0x0a, 0x08, 0x70, 0x72, 0x6f, - 0x62, 0x6c, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, - 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, - 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x70, 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x72, 0x69, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x69, 0x72, 0x32, - 0x4f, 0x0a, 0x02, 0x56, 0x41, 0x12, 0x49, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x76, 0x61, 0x2e, - 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x76, 0x61, 0x2e, 0x56, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, - 0x32, 0x44, 0x0a, 0x03, 0x43, 0x41, 0x41, 0x12, 0x3d, 0x0a, 0x0a, 0x49, 0x73, 0x43, 0x41, 0x41, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x15, 0x2e, 0x76, 0x61, 0x2e, 0x49, 0x73, 0x43, 0x41, 0x41, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x76, - 0x61, 0x2e, 0x49, 0x73, 0x43, 0x41, 0x41, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 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, 0x76, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x07, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, + 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x69, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x69, 0x72, 0x22, 0xc4, 0x01, 0x0a, + 0x18, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6e, 0x73, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6e, 0x73, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x68, + 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, + 0x67, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x4d, 0x65, 0x74, 0x61, + 0x52, 0x05, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x12, 0x3a, 0x0a, 0x18, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x31, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x67, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x72, 0x65, 0x67, 0x49, 0x44, 0x22, 0xa8, 0x01, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x30, 0x0a, 0x07, 0x72, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, + 0x6f, 0x72, 0x65, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2e, 0x0a, + 0x07, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x12, 0x20, 0x0a, + 0x0b, 0x70, 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, + 0x10, 0x0a, 0x03, 0x72, 0x69, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x69, + 0x72, 0x32, 0x4f, 0x0a, 0x02, 0x56, 0x41, 0x12, 0x49, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x66, 0x6f, + 0x72, 0x6d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x76, + 0x61, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x76, 0x61, 0x2e, + 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x22, 0x00, 0x32, 0x44, 0x0a, 0x03, 0x43, 0x41, 0x41, 0x12, 0x3d, 0x0a, 0x0a, 0x49, 0x73, 0x43, + 0x41, 0x41, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x15, 0x2e, 0x76, 0x61, 0x2e, 0x49, 0x73, 0x43, + 0x41, 0x41, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x76, 0x61, 0x2e, 0x49, 0x73, 0x43, 0x41, 0x41, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 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, 0x76, 0x61, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -417,7 +436,7 @@ var file_va_proto_depIdxs = []int32{ 6, // 1: va.PerformValidationRequest.challenge:type_name -> core.Challenge 3, // 2: va.PerformValidationRequest.authz:type_name -> va.AuthzMeta 7, // 3: va.ValidationResult.records:type_name -> core.ValidationRecord - 5, // 4: va.ValidationResult.problems:type_name -> core.ProblemDetails + 5, // 4: va.ValidationResult.problem:type_name -> core.ProblemDetails 2, // 5: va.VA.PerformValidation:input_type -> va.PerformValidationRequest 0, // 6: va.CAA.IsCAAValid:input_type -> va.IsCAAValidRequest 4, // 7: va.VA.PerformValidation:output_type -> va.ValidationResult diff --git a/va/proto/va.proto b/va/proto/va.proto index 3be26241330..c42313990a1 100644 --- a/va/proto/va.proto +++ b/va/proto/va.proto @@ -23,6 +23,8 @@ message IsCAAValidRequest { // If CAA is valid for the requested domain, the problem will be empty message IsCAAValidResponse { core.ProblemDetails problem = 1; + string perspective = 3; + string rir = 4; } message PerformValidationRequest { @@ -39,7 +41,7 @@ message AuthzMeta { message ValidationResult { repeated core.ValidationRecord records = 1; - core.ProblemDetails problems = 2; + core.ProblemDetails problem = 2; string perspective = 3; string rir = 4; } diff --git a/va/va.go b/va/va.go index a9ddcae1528..a2e229d3707 100644 --- a/va/va.go +++ b/va/va.go @@ -18,9 +18,11 @@ import ( "github.com/jmhodges/clock" "github.com/prometheus/client_golang/prometheus" + "google.golang.org/protobuf/proto" "github.com/letsencrypt/boulder/bdns" "github.com/letsencrypt/boulder/core" + corepb "github.com/letsencrypt/boulder/core/proto" berrors "github.com/letsencrypt/boulder/errors" bgrpc "github.com/letsencrypt/boulder/grpc" "github.com/letsencrypt/boulder/identifier" @@ -452,15 +454,35 @@ func (va *ValidationAuthorityImpl) observeLatency(op, perspective, challType, pr va.metrics.validationLatency.With(labels).Observe(latency.Seconds()) } -// performRemoteValidation coordinates the whole process of kicking off and -// collecting results from calls to remote VAs' PerformValidation function. It -// returns a problem if too many remote perspectives failed to corroborate -// domain control, or nil if enough succeeded to surpass our corroboration -// threshold. -func (va *ValidationAuthorityImpl) performRemoteValidation( - ctx context.Context, - req *vapb.PerformValidationRequest, -) *probs.ProblemDetails { +// remoteOperation is a func type that encapsulates the operation and request +// passed to va.performRemoteOperation. The operation must be a method on +// vapb.VAClient or vapb.CAAClient, and the request must be the corresponding +// proto.Message passed to that method. +type remoteOperation = func(context.Context, RemoteVA, proto.Message) (remoteResult, error) + +// remoteResult is an interface that must be implemented by the results of a +// remoteOperation, such as *vapb.ValidationResult and *vapb.IsCAAValidResponse. +// It provides methods to access problem details, the associated perspective, +// and the RIR. +type remoteResult interface { + proto.Message + GetProblem() *corepb.ProblemDetails + GetPerspective() string + GetRir() string +} + +var _ remoteResult = (*vapb.ValidationResult)(nil) +var _ remoteResult = (*vapb.IsCAAValidResponse)(nil) + +// performRemoteOperation concurrently calls the provided operation with `req` and a +// RemoteVA once for each configured RemoteVA. It cancels remaining operations and returns +// early if either the required number of successful results is obtained or the number of +// failures exceeds va.maxRemoteFailures. +// +// Internal logic errors are logged. If the number of operation failures exceeds +// va.maxRemoteFailures, the first encountered problem is returned as a +// *probs.ProblemDetails. +func (va *ValidationAuthorityImpl) performRemoteOperation(ctx context.Context, op remoteOperation, req proto.Message) *probs.ProblemDetails { remoteVACount := len(va.remoteVAs) if remoteVACount == 0 { return nil @@ -470,7 +492,7 @@ func (va *ValidationAuthorityImpl) performRemoteValidation( addr string perspective string rir string - result *vapb.ValidationResult + result remoteResult err error } @@ -480,7 +502,7 @@ func (va *ValidationAuthorityImpl) performRemoteValidation( responses := make(chan *response, remoteVACount) for _, i := range rand.Perm(remoteVACount) { go func(rva RemoteVA) { - res, err := rva.PerformValidation(subCtx, req) + res, err := op(subCtx, rva, req) responses <- &response{rva.Address, rva.Perspective, rva.RIR, res, err} }(va.remoteVAs[i]) } @@ -498,20 +520,20 @@ func (va *ValidationAuthorityImpl) performRemoteValidation( failed = append(failed, resp.perspective) if core.IsCanceled(resp.err) { - currProb = probs.ServerInternal("Secondary domain validation RPC canceled") + currProb = probs.ServerInternal("Secondary validation RPC canceled") } else { - va.log.Errf("Remote VA %q.PerformValidation failed: %s", resp.addr, resp.err) - currProb = probs.ServerInternal("Secondary domain validation RPC failed") + va.log.Errf("Operation on remote VA (%s) failed: %s", resp.addr, resp.err) + currProb = probs.ServerInternal("Secondary validation RPC failed") } - } else if resp.result.Problems != nil { + } else if resp.result.GetProblem() != nil { // The remote VA returned a problem. failed = append(failed, resp.perspective) var err error - currProb, err = bgrpc.PBToProblemDetails(resp.result.Problems) + currProb, err = bgrpc.PBToProblemDetails(resp.result.GetProblem()) if err != nil { - va.log.Errf("Remote VA %q.PerformValidation returned malformed problem: %s", resp.addr, err) - currProb = probs.ServerInternal("Secondary domain validation RPC returned malformed result") + va.log.Errf("Operation on Remote VA (%s) returned malformed problem: %s", resp.addr, err) + currProb = probs.ServerInternal("Secondary validation RPC returned malformed result") } } else { // The remote VA returned a successful result. @@ -542,12 +564,12 @@ func (va *ValidationAuthorityImpl) performRemoteValidation( if len(passed) >= required { return nil } else if len(failed) > va.maxRemoteFailures { - firstProb.Detail = fmt.Sprintf("During secondary domain validation: %s", firstProb.Detail) + firstProb.Detail = fmt.Sprintf("During secondary validation: %s", firstProb.Detail) return firstProb } else { // This condition should not occur - it indicates the passed/failed counts // neither met the required threshold nor the maxRemoteFailures threshold. - return probs.ServerInternal("Too few remote PerformValidation RPC results") + return probs.ServerInternal("Too few remote RPC results") } } @@ -734,6 +756,13 @@ func (va *ValidationAuthorityImpl) PerformValidation(ctx context.Context, req *v // singular problem, because the remote VAs have already audit-logged their // own validation records, and it's not helpful to present multiple large // errors to the end user. - prob = va.performRemoteValidation(ctx, req) + op := func(ctx context.Context, remoteva RemoteVA, req proto.Message) (remoteResult, error) { + validationRequest, ok := req.(*vapb.PerformValidationRequest) + if !ok { + return nil, fmt.Errorf("got type %T, want *vapb.PerformValidationRequest", req) + } + return remoteva.PerformValidation(ctx, validationRequest) + } + prob = va.performRemoteOperation(ctx, op, req) return bgrpc.ValidationResultToPB(records, filterProblemDetails(prob), va.perspective, va.rir) } diff --git a/va/va_test.go b/va/va_test.go index 33701d95e63..172a595fd08 100644 --- a/va/va_test.go +++ b/va/va_test.go @@ -21,6 +21,7 @@ import ( "github.com/jmhodges/clock" "github.com/prometheus/client_golang/prometheus" "google.golang.org/grpc" + "google.golang.org/protobuf/proto" "github.com/letsencrypt/boulder/bdns" "github.com/letsencrypt/boulder/core" @@ -346,7 +347,7 @@ func TestPerformValidationInvalid(t *testing.T) { req := createValidationRequest("foo.com", core.ChallengeTypeDNS01) res, _ := va.PerformValidation(context.Background(), req) - test.Assert(t, res.Problems != nil, "validation succeeded") + test.Assert(t, res.Problem != nil, "validation succeeded") test.AssertMetricWithLabelsEquals(t, va.metrics.validationLatency, prometheus.Labels{ "operation": opChallAndCAA, "perspective": va.perspective, @@ -375,7 +376,7 @@ func TestPerformValidationValid(t *testing.T) { // create a challenge with well known token req := createValidationRequest("good-dns01.com", core.ChallengeTypeDNS01) res, _ := va.PerformValidation(context.Background(), req) - test.Assert(t, res.Problems == nil, fmt.Sprintf("validation failed: %#v", res.Problems)) + test.Assert(t, res.Problem == nil, fmt.Sprintf("validation failed: %#v", res.Problem)) test.AssertMetricWithLabelsEquals(t, va.metrics.validationLatency, prometheus.Labels{ "operation": opChallAndCAA, @@ -402,7 +403,7 @@ func TestPerformValidationWildcard(t *testing.T) { req := createValidationRequest("*.good-dns01.com", core.ChallengeTypeDNS01) // perform a validation for a wildcard name res, _ := va.PerformValidation(context.Background(), req) - test.Assert(t, res.Problems == nil, fmt.Sprintf("validation failed: %#v", res.Problems)) + test.Assert(t, res.Problem == nil, fmt.Sprintf("validation failed: %#v", res.Problem)) test.AssertMetricWithLabelsEquals(t, va.metrics.validationLatency, prometheus.Labels{ "operation": opChallAndCAA, @@ -435,7 +436,7 @@ func TestDCVAndCAASequencing(t *testing.T) { req := createValidationRequest("good-dns01.com", core.ChallengeTypeDNS01) res, err := va.PerformValidation(context.Background(), req) test.AssertNotError(t, err, "performing validation") - test.Assert(t, res.Problems == nil, fmt.Sprintf("validation failed: %#v", res.Problems)) + test.Assert(t, res.Problem == nil, fmt.Sprintf("validation failed: %#v", res.Problem)) caaLog := mockLog.GetAllMatching(`Checked CAA records for`) test.AssertEquals(t, len(caaLog), 1) @@ -444,11 +445,75 @@ func TestDCVAndCAASequencing(t *testing.T) { req = createValidationRequest("bad-dns01.com", core.ChallengeTypeDNS01) res, err = va.PerformValidation(context.Background(), req) test.AssertNotError(t, err, "performing validation") - test.Assert(t, res.Problems != nil, "validation succeeded") + test.Assert(t, res.Problem != nil, "validation succeeded") caaLog = mockLog.GetAllMatching(`Checked CAA records for`) test.AssertEquals(t, len(caaLog), 0) } +func TestPerformRemoteOperation(t *testing.T) { + va, _ := setupWithRemotes(nil, "", []remoteConf{ + {ua: pass, rir: arin}, + {ua: pass, rir: ripe}, + {ua: pass, rir: apnic}, + }, nil) + + testCases := []struct { + name string + req proto.Message + expectedType string + expectedDetail string + op func(ctx context.Context, rva RemoteVA, req proto.Message) (remoteResult, error) + }{ + { + name: "ValidationResult", + req: &vapb.PerformValidationRequest{}, + expectedType: string(probs.BadNonceProblem), + expectedDetail: "quite surprising", + op: func(ctx context.Context, rva RemoteVA, req proto.Message) (remoteResult, error) { + prob := &corepb.ProblemDetails{ + ProblemType: string(probs.BadNonceProblem), + Detail: "quite surprising", + } + return &vapb.ValidationResult{Problem: prob, Perspective: rva.Perspective, Rir: rva.RIR}, nil + }, + }, + { + name: "IsCAAValidResponse", + req: &vapb.IsCAAValidRequest{}, + expectedType: string(probs.PausedProblem), + expectedDetail: "quite surprising, indeed", + op: func(ctx context.Context, rva RemoteVA, req proto.Message) (remoteResult, error) { + prob := &corepb.ProblemDetails{ + ProblemType: string(probs.PausedProblem), + Detail: "quite surprising, indeed", + } + return &vapb.IsCAAValidResponse{Problem: prob, Perspective: rva.Perspective, Rir: rva.RIR}, nil + }, + }, + { + name: "IsCAAValidRequestWithValidationResult", + req: &vapb.IsCAAValidRequest{}, + expectedType: string(probs.BadPublicKeyProblem), + expectedDetail: "a shocking result", + op: func(ctx context.Context, rva RemoteVA, req proto.Message) (remoteResult, error) { + prob := &corepb.ProblemDetails{ + ProblemType: string(probs.BadPublicKeyProblem), + Detail: "a shocking result", + } + return &vapb.ValidationResult{Problem: prob, Perspective: rva.Perspective, Rir: rva.RIR}, nil + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + prob := va.performRemoteOperation(context.Background(), tc.op, tc.req) + test.AssertEquals(t, string(prob.Type), tc.expectedType) + test.AssertContains(t, prob.Detail, tc.expectedDetail) + }) + } +} + func TestMultiVA(t *testing.T) { t.Parallel() @@ -581,7 +646,7 @@ func TestMultiVA(t *testing.T) { }, PrimaryUA: pass, ExpectedProbType: string(probs.UnauthorizedProblem), - ExpectedLogContains: "During secondary domain validation: The key authorization file from the server", + ExpectedLogContains: "During secondary validation: The key authorization file from the server", }, { // If one remote VA cancels, it should succeed @@ -603,7 +668,7 @@ func TestMultiVA(t *testing.T) { }, PrimaryUA: pass, ExpectedProbType: string(probs.ServerInternalProblem), - ExpectedLogContains: "During secondary domain validation: Secondary domain validation RPC canceled", + ExpectedLogContains: "During secondary validation: Secondary validation RPC canceled", }, { // With the local and remote VAs seeing diff problems, we expect a problem. @@ -615,7 +680,7 @@ func TestMultiVA(t *testing.T) { }, PrimaryUA: pass, ExpectedProbType: string(probs.UnauthorizedProblem), - ExpectedLogContains: "During secondary domain validation: The key authorization file from the server", + ExpectedLogContains: "During secondary validation: The key authorization file from the server", }, } @@ -632,13 +697,13 @@ func TestMultiVA(t *testing.T) { // Perform all validations res, _ := localVA.PerformValidation(ctx, req) - if res.Problems == nil && tc.ExpectedProbType != "" { + if res.Problem == nil && tc.ExpectedProbType != "" { t.Errorf("expected prob %v, got nil", tc.ExpectedProbType) - } else if res.Problems != nil && tc.ExpectedProbType == "" { - t.Errorf("expected no prob, got %v", res.Problems) - } else if res.Problems != nil && tc.ExpectedProbType != "" { + } else if res.Problem != nil && tc.ExpectedProbType == "" { + t.Errorf("expected no prob, got %v", res.Problem) + } else if res.Problem != nil && tc.ExpectedProbType != "" { // That result should match expected. - test.AssertEquals(t, res.Problems.ProblemType, tc.ExpectedProbType) + test.AssertEquals(t, res.Problem.ProblemType, tc.ExpectedProbType) } if tc.ExpectedLogContains != "" { @@ -701,7 +766,7 @@ func TestMultiVAEarlyReturn(t *testing.T) { res, _ := localVA.PerformValidation(ctx, req) // It should always fail - if res.Problems == nil { + if res.Problem == nil { t.Error("expected prob from PerformValidation, got nil") } @@ -739,7 +804,7 @@ func TestMultiVAPolicy(t *testing.T) { req := createValidationRequest("letsencrypt.org", core.ChallengeTypeHTTP01) res, _ := localVA.PerformValidation(ctx, req) // It should fail - if res.Problems == nil { + if res.Problem == nil { t.Error("expected prob from PerformValidation, got nil") } } @@ -758,7 +823,7 @@ func TestMultiVALogging(t *testing.T) { va, _ := setupWithRemotes(ms.Server, pass, remoteConfs, nil) req := createValidationRequest("letsencrypt.org", core.ChallengeTypeHTTP01) res, err := va.PerformValidation(ctx, req) - test.Assert(t, res.Problems == nil, fmt.Sprintf("validation failed with: %#v", res.Problems)) + test.Assert(t, res.Problem == nil, fmt.Sprintf("validation failed with: %#v", res.Problem)) test.AssertNotError(t, err, "performing validation") }