Merge pull request #2394 from letsencrypt/master

Merge master to staging.
This commit is contained in:
Daniel McCarney 2016-12-05 11:42:11 -05:00 committed by GitHub
commit 0f2af77660
100 changed files with 5516 additions and 760 deletions

47
Godeps/Godeps.json generated
View File

@ -142,7 +142,8 @@
},
{
"ImportPath": "github.com/letsencrypt/pkcs11key",
"Rev": "bda7cf218ae2225f745ead23f9b65901dfebbf45"
"Comment": "v1.0.0",
"Rev": "c47dab18ddd8c4d4267661870d3ba331cddc57c9"
},
{
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",
@ -163,13 +164,13 @@
},
{
"ImportPath": "github.com/prometheus/client_golang/prometheus",
"Comment": "0.7.0-129-g3fb8ace",
"Rev": "3fb8ace93bc4ccddea55af62320c2fd109252880"
"Comment": "v0.8.0",
"Rev": "c5b7fccd204277076155f10851dad72b76a49317"
},
{
"ImportPath": "github.com/prometheus/client_golang/prometheus/promhttp",
"Comment": "0.7.0-129-g3fb8ace",
"Rev": "3fb8ace93bc4ccddea55af62320c2fd109252880"
"Comment": "v0.8.0",
"Rev": "c5b7fccd204277076155f10851dad72b76a49317"
},
{
"ImportPath": "github.com/prometheus/client_model/go",
@ -247,48 +248,48 @@
},
{
"ImportPath": "google.golang.org/grpc",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/codes",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/credentials",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/grpclog",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/internal",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/metadata",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/naming",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/peer",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "google.golang.org/grpc/transport",
"Comment": "v1.0.1-GA-39-g52f6504",
"Rev": "52f6504dc290bd928a8139ba94e3ab32ed9a6273"
"Comment": "v1.0.3",
"Rev": "b7f1379d3cbbbeb2ca3405852012e237aa05459e"
},
{
"ImportPath": "gopkg.in/gorp.v1",

View File

@ -391,7 +391,7 @@ func TestOCSP(t *testing.T) {
test.AssertEquals(t, parsed.SerialNumber.Cmp(parsedCert.SerialNumber), 0)
// Test that signatures are checked.
ocspResp, err = ca.GenerateOCSP(ctx, core.OCSPSigningRequest{
_, err = ca.GenerateOCSP(ctx, core.OCSPSigningRequest{
CertDER: append(cert.DER, byte(0)),
Status: string(core.OCSPStatusGood),
})

View File

@ -1,16 +1,15 @@
// Code generated by protoc-gen-go.
// source: ca.proto
// source: ca/proto/ca.proto
// DO NOT EDIT!
/*
Package proto is a generated protocol buffer package.
It is generated from these files:
ca.proto
ca/proto/ca.proto
It has these top-level messages:
IssueCertificateRequest
Certificate
GenerateOCSPRequest
OCSPResponse
*/
@ -19,6 +18,7 @@ package proto
import proto1 "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import core "github.com/letsencrypt/boulder/core/proto"
import (
context "golang.org/x/net/context"
@ -61,63 +61,6 @@ func (m *IssueCertificateRequest) GetRegistrationID() int64 {
return 0
}
type Certificate struct {
RegistrationID *int64 `protobuf:"varint,1,opt,name=registrationID" json:"registrationID,omitempty"`
Serial *string `protobuf:"bytes,2,opt,name=serial" json:"serial,omitempty"`
Digest *string `protobuf:"bytes,3,opt,name=digest" json:"digest,omitempty"`
Der []byte `protobuf:"bytes,4,opt,name=der" json:"der,omitempty"`
Issued *int64 `protobuf:"varint,5,opt,name=issued" json:"issued,omitempty"`
Expires *int64 `protobuf:"varint,6,opt,name=expires" json:"expires,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Certificate) Reset() { *m = Certificate{} }
func (m *Certificate) String() string { return proto1.CompactTextString(m) }
func (*Certificate) ProtoMessage() {}
func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Certificate) GetRegistrationID() int64 {
if m != nil && m.RegistrationID != nil {
return *m.RegistrationID
}
return 0
}
func (m *Certificate) GetSerial() string {
if m != nil && m.Serial != nil {
return *m.Serial
}
return ""
}
func (m *Certificate) GetDigest() string {
if m != nil && m.Digest != nil {
return *m.Digest
}
return ""
}
func (m *Certificate) GetDer() []byte {
if m != nil {
return m.Der
}
return nil
}
func (m *Certificate) GetIssued() int64 {
if m != nil && m.Issued != nil {
return *m.Issued
}
return 0
}
func (m *Certificate) GetExpires() int64 {
if m != nil && m.Expires != nil {
return *m.Expires
}
return 0
}
type GenerateOCSPRequest struct {
CertDER []byte `protobuf:"bytes,1,opt,name=certDER" json:"certDER,omitempty"`
Status *string `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"`
@ -129,7 +72,7 @@ type GenerateOCSPRequest struct {
func (m *GenerateOCSPRequest) Reset() { *m = GenerateOCSPRequest{} }
func (m *GenerateOCSPRequest) String() string { return proto1.CompactTextString(m) }
func (*GenerateOCSPRequest) ProtoMessage() {}
func (*GenerateOCSPRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (*GenerateOCSPRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *GenerateOCSPRequest) GetCertDER() []byte {
if m != nil {
@ -167,7 +110,7 @@ type OCSPResponse struct {
func (m *OCSPResponse) Reset() { *m = OCSPResponse{} }
func (m *OCSPResponse) String() string { return proto1.CompactTextString(m) }
func (*OCSPResponse) ProtoMessage() {}
func (*OCSPResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (*OCSPResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *OCSPResponse) GetResponse() []byte {
if m != nil {
@ -178,7 +121,6 @@ func (m *OCSPResponse) GetResponse() []byte {
func init() {
proto1.RegisterType((*IssueCertificateRequest)(nil), "ca.IssueCertificateRequest")
proto1.RegisterType((*Certificate)(nil), "ca.Certificate")
proto1.RegisterType((*GenerateOCSPRequest)(nil), "ca.GenerateOCSPRequest")
proto1.RegisterType((*OCSPResponse)(nil), "ca.OCSPResponse")
}
@ -194,7 +136,7 @@ const _ = grpc.SupportPackageIsVersion3
// Client API for CertificateAuthority service
type CertificateAuthorityClient interface {
IssueCertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*Certificate, error)
IssueCertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*core.Certificate, error)
GenerateOCSP(ctx context.Context, in *GenerateOCSPRequest, opts ...grpc.CallOption) (*OCSPResponse, error)
}
@ -206,8 +148,8 @@ func NewCertificateAuthorityClient(cc *grpc.ClientConn) CertificateAuthorityClie
return &certificateAuthorityClient{cc}
}
func (c *certificateAuthorityClient) IssueCertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*Certificate, error) {
out := new(Certificate)
func (c *certificateAuthorityClient) IssueCertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*core.Certificate, error) {
out := new(core.Certificate)
err := grpc.Invoke(ctx, "/ca.CertificateAuthority/IssueCertificate", in, out, c.cc, opts...)
if err != nil {
return nil, err
@ -227,7 +169,7 @@ func (c *certificateAuthorityClient) GenerateOCSP(ctx context.Context, in *Gener
// Server API for CertificateAuthority service
type CertificateAuthorityServer interface {
IssueCertificate(context.Context, *IssueCertificateRequest) (*Certificate, error)
IssueCertificate(context.Context, *IssueCertificateRequest) (*core.Certificate, error)
GenerateOCSP(context.Context, *GenerateOCSPRequest) (*OCSPResponse, error)
}
@ -288,27 +230,25 @@ var _CertificateAuthority_serviceDesc = grpc.ServiceDesc{
Metadata: fileDescriptor0,
}
func init() { proto1.RegisterFile("ca.proto", fileDescriptor0) }
func init() { proto1.RegisterFile("ca/proto/ca.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 302 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x91, 0x4f, 0x4f, 0xc2, 0x40,
0x10, 0xc5, 0x29, 0x95, 0x7f, 0x03, 0x01, 0x5c, 0x8d, 0x34, 0x78, 0x21, 0x3d, 0x71, 0xe2, 0xe0,
0xd5, 0xc4, 0x84, 0x3f, 0xc6, 0x70, 0xd2, 0xe0, 0x49, 0x6f, 0x9b, 0xed, 0x88, 0x1b, 0x4d, 0xb7,
0xce, 0x4c, 0x8d, 0x7e, 0x12, 0xbf, 0xae, 0xd9, 0x05, 0x63, 0x63, 0xf0, 0xd6, 0xe9, 0xcc, 0x9b,
0xdf, 0x7b, 0xb3, 0xd0, 0x36, 0x7a, 0x56, 0x90, 0x13, 0xa7, 0xea, 0x46, 0xa7, 0x57, 0x30, 0x5a,
0x33, 0x97, 0xb8, 0x44, 0x12, 0xfb, 0x64, 0x8d, 0x16, 0xdc, 0xe0, 0x5b, 0x89, 0x2c, 0xaa, 0x0b,
0xb1, 0x61, 0x4a, 0xa2, 0x49, 0x34, 0xed, 0xa9, 0x33, 0xe8, 0x13, 0x6e, 0x2d, 0x0b, 0x69, 0xb1,
0x2e, 0x5f, 0xaf, 0x92, 0xfa, 0x24, 0x9a, 0xc6, 0x29, 0x43, 0xb7, 0x22, 0x3d, 0x30, 0xe6, 0xe5,
0xb1, 0xea, 0x43, 0x93, 0x91, 0xac, 0x7e, 0x0d, 0xb2, 0x8e, 0xaf, 0x33, 0xbb, 0x45, 0x96, 0x24,
0x0e, 0x75, 0x17, 0xe2, 0x0c, 0x29, 0x39, 0x0a, 0xac, 0x3e, 0x34, 0xad, 0xf7, 0x94, 0x25, 0x8d,
0x20, 0x1e, 0x40, 0x0b, 0x3f, 0x0a, 0x4b, 0xc8, 0x49, 0x33, 0x40, 0x1f, 0xe0, 0xe4, 0x06, 0x73,
0x24, 0x2d, 0x78, 0xbb, 0xbc, 0xbf, 0xfb, 0x31, 0x3c, 0x80, 0x96, 0x41, 0x92, 0xd5, 0xf5, 0x66,
0x6f, 0xda, 0x53, 0x45, 0x4b, 0xc9, 0xbf, 0x54, 0x42, 0xcd, 0x2e, 0x0f, 0xd4, 0x86, 0x3a, 0x86,
0x0e, 0xe1, 0xbb, 0x7b, 0xc1, 0x6c, 0x2e, 0x81, 0x1d, 0xa7, 0x13, 0xe8, 0xed, 0x56, 0x72, 0xe1,
0x72, 0x46, 0x35, 0x84, 0x36, 0xed, 0xbf, 0x77, 0x4b, 0x2f, 0xbe, 0x22, 0x38, 0xad, 0x44, 0x9e,
0x97, 0xf2, 0xec, 0xc8, 0xca, 0xa7, 0x5a, 0xc0, 0xf0, 0xef, 0x29, 0xd5, 0xf9, 0xcc, 0xe8, 0xd9,
0x3f, 0x07, 0x1e, 0x0f, 0x7c, 0xb3, 0xf2, 0x3f, 0xad, 0xa9, 0x4b, 0xe8, 0x55, 0x93, 0xa9, 0x91,
0x1f, 0x39, 0x90, 0x75, 0x3c, 0xf4, 0x8d, 0xaa, 0xd3, 0xb4, 0xb6, 0x68, 0x3d, 0x36, 0xc2, 0xc3,
0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x25, 0xda, 0x9b, 0x25, 0xe3, 0x01, 0x00, 0x00,
// 267 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x90, 0x4d, 0x4b, 0xc3, 0x40,
0x10, 0x86, 0x9b, 0xc6, 0x5a, 0x3b, 0x86, 0x9a, 0xac, 0x1f, 0x0d, 0xf1, 0x12, 0x72, 0xca, 0x29,
0x05, 0xaf, 0x82, 0x50, 0x1b, 0x91, 0x9e, 0x94, 0x7a, 0xd2, 0xdb, 0xb2, 0x8e, 0x1a, 0x84, 0x6c,
0x9d, 0x99, 0x08, 0xfe, 0x14, 0xff, 0xad, 0x64, 0xd3, 0x42, 0x10, 0xbd, 0xcd, 0xf0, 0xf2, 0x3e,
0xcc, 0x33, 0x10, 0x19, 0x3d, 0xdf, 0x90, 0x15, 0x3b, 0x37, 0xba, 0x70, 0x83, 0x1a, 0x1a, 0x9d,
0x9c, 0x1a, 0x4b, 0xb8, 0x0b, 0x2c, 0x61, 0x17, 0x65, 0x57, 0x30, 0x5b, 0x31, 0x37, 0xb8, 0x44,
0x92, 0xea, 0xa5, 0x32, 0x5a, 0x70, 0x8d, 0x1f, 0x0d, 0xb2, 0xa8, 0x43, 0xf0, 0x0d, 0x53, 0xec,
0xa5, 0x5e, 0x1e, 0xa8, 0x33, 0x98, 0x12, 0xbe, 0x56, 0x2c, 0xa4, 0xa5, 0xb2, 0xf5, 0xaa, 0x8c,
0x87, 0xa9, 0x97, 0xfb, 0xd9, 0x23, 0x1c, 0xdf, 0x62, 0x8d, 0xa4, 0x05, 0xef, 0x96, 0x0f, 0xf7,
0xbb, 0xee, 0x11, 0x8c, 0x0d, 0x92, 0x94, 0x37, 0xeb, 0x6d, 0x7f, 0x0a, 0xfb, 0x2c, 0x5a, 0x1a,
0x76, 0xbd, 0x49, 0xbb, 0x13, 0x6a, 0xb6, 0x75, 0xec, 0xa7, 0x5e, 0x3e, 0x52, 0x11, 0x4c, 0x08,
0x3f, 0xed, 0x3b, 0x3e, 0x2f, 0x24, 0xde, 0x73, 0xe8, 0x14, 0x82, 0x0e, 0xc9, 0x1b, 0x5b, 0x33,
0xaa, 0x10, 0x0e, 0x68, 0x3b, 0x77, 0xd0, 0x8b, 0x6f, 0x0f, 0x4e, 0x7a, 0x87, 0x2f, 0x1a, 0x79,
0xb3, 0x54, 0xc9, 0x97, 0x2a, 0x21, 0xfc, 0x6d, 0xa5, 0xce, 0x0b, 0xa3, 0x8b, 0x7f, 0x5c, 0x93,
0xa8, 0x70, 0x3f, 0xe9, 0x25, 0xd9, 0x40, 0x5d, 0x42, 0xd0, 0x77, 0x53, 0xb3, 0x96, 0xf0, 0x87,
0x6d, 0x12, 0xb6, 0x41, 0xff, 0xd6, 0x6c, 0x70, 0x3d, 0x7e, 0x1a, 0xb9, 0x0f, 0xff, 0x04, 0x00,
0x00, 0xff, 0xff, 0x08, 0x1f, 0xbb, 0xea, 0x90, 0x01, 0x00, 0x00,
}

View File

@ -3,8 +3,10 @@ syntax = "proto2";
package ca;
option go_package = "proto";
import "core/proto/core.proto";
service CertificateAuthority {
rpc IssueCertificate(IssueCertificateRequest) returns (Certificate) {}
rpc IssueCertificate(IssueCertificateRequest) returns (core.Certificate) {}
rpc GenerateOCSP(GenerateOCSPRequest) returns (OCSPResponse) {}
}
@ -13,15 +15,6 @@ message IssueCertificateRequest {
optional int64 registrationID = 2;
}
message Certificate {
optional int64 registrationID = 1;
optional string serial = 2;
optional string digest = 3;
optional bytes der = 4;
optional int64 issued = 5; // Unix timestamp (nanoseconds)
optional int64 expires = 6; // Unix timestamp (nanoseconds)
}
message GenerateOCSPRequest {
optional bytes certDER = 1;
optional string status = 2;

View File

@ -1,3 +1,3 @@
package proto
//go:generate sh -c "protoc --go_out=plugins=grpc:. ca.proto"
//go:generate sh -c "cd ../.. && protoc --go_out=plugins=grpc,Mcore/proto/core.proto=github.com/letsencrypt/boulder/core/proto:. ca/proto/ca.proto"

View File

@ -145,7 +145,7 @@ func (cdr *CAADistributedResolver) queryCAA(ctx context.Context, url string, ic
if respObj.Comment != "" {
return nil, fmt.Errorf("Query failed with %s: %s", dns.RcodeToString[respObj.Status], respObj.Comment)
}
return nil, fmt.Errorf("Query failed wtih %s", dns.RcodeToString[respObj.Status])
return nil, fmt.Errorf("Query failed with %s", dns.RcodeToString[respObj.Status])
}
return parseAnswer(respObj.Answer)

View File

@ -24,8 +24,8 @@ var log = blog.UseMock()
func TestParseAnswer(t *testing.T) {
as := []core.GPDNSAnswer{
{"a", 257, 10, "0 issue \"ca.com\""},
{"b", 1, 10, "1.1.1.1"},
{Name: "a", Type: 257, TTL: 10, Data: "0 issue \"ca.com\""},
{Name: "b", Type: 1, TTL: 10, Data: "1.1.1.1"},
}
r, err := parseAnswer(as)

View File

@ -16,11 +16,14 @@ import (
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
bgrpc "github.com/letsencrypt/boulder/grpc"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics"
rapb "github.com/letsencrypt/boulder/ra/proto"
"github.com/letsencrypt/boulder/revocation"
"github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/sa"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
const clientName = "AdminRevoker"
@ -48,6 +51,9 @@ type config struct {
// The revoker isn't a long running service, so doesn't get a full
// ServiceConfig, just an AMQPConfig.
AMQP *cmd.AMQPConfig
RAService *cmd.GRPCClientConfig
SAService *cmd.GRPCClientConfig
}
Statsd cmd.StatsdConfig
@ -55,13 +61,21 @@ type config struct {
Syslog cmd.SyslogConfig
}
func setupContext(c config) (rpc.RegistrationAuthorityClient, blog.Logger, *gorp.DbMap, rpc.StorageAuthorityClient, metrics.Scope) {
func setupContext(c config) (core.RegistrationAuthority, blog.Logger, *gorp.DbMap, core.StorageAuthority, metrics.Scope) {
stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
scope := metrics.NewStatsdScope(stats, "AdminRevoker")
amqpConf := c.Revoker.AMQP
rac, err := rpc.NewRegistrationAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create CA client")
var rac core.RegistrationAuthority
if c.Revoker.RAService != nil {
conn, err := bgrpc.ClientSetup(c.Revoker.RAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to RA")
rac = bgrpc.NewRegistrationAuthorityClient(rapb.NewRegistrationAuthorityClient(conn))
} else {
var err error
rac, err = rpc.NewRegistrationAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create RA AMQP client")
}
dbURL, err := c.Revoker.DBConfig.URL()
cmd.FailOnError(err, "Couldn't load DB URL")
@ -69,13 +83,20 @@ func setupContext(c config) (rpc.RegistrationAuthorityClient, blog.Logger, *gorp
cmd.FailOnError(err, "Couldn't setup database connection")
go sa.ReportDbConnCount(dbMap, scope)
sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Failed to create SA client")
var sac core.StorageAuthority
if c.Revoker.SAService != nil {
conn, err := bgrpc.ClientSetup(c.Revoker.SAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Failed to create SA client")
}
return *rac, logger, dbMap, *sac, scope
return rac, logger, dbMap, sac, scope
}
func revokeBySerial(ctx context.Context, serial string, reasonCode revocation.Reason, rac rpc.RegistrationAuthorityClient, logger blog.Logger, tx *gorp.Transaction) (err error) {
func revokeBySerial(ctx context.Context, serial string, reasonCode revocation.Reason, rac core.RegistrationAuthority, logger blog.Logger, tx *gorp.Transaction) (err error) {
if reasonCode < 0 || reasonCode == 7 || reasonCode > 10 {
panic(fmt.Sprintf("Invalid reason code: %d", reasonCode))
}
@ -102,7 +123,7 @@ func revokeBySerial(ctx context.Context, serial string, reasonCode revocation.Re
return
}
func revokeByReg(ctx context.Context, regID int64, reasonCode revocation.Reason, rac rpc.RegistrationAuthorityClient, logger blog.Logger, tx *gorp.Transaction) (err error) {
func revokeByReg(ctx context.Context, regID int64, reasonCode revocation.Reason, rac core.RegistrationAuthority, logger blog.Logger, tx *gorp.Transaction) (err error) {
var certs []core.Certificate
_, err = tx.Select(&certs, "SELECT serial FROM certificates WHERE registrationID = :regID", map[string]interface{}{"regID": regID})
if err != nil {
@ -158,14 +179,14 @@ func main() {
reasonCode, err := strconv.Atoi(args[1])
cmd.FailOnError(err, "Reason code argument must be an integer")
cac, logger, dbMap, _, _ := setupContext(c)
rac, logger, dbMap, _, _ := setupContext(c)
tx, err := dbMap.Begin()
if err != nil {
cmd.FailOnError(sa.Rollback(tx, err), "Couldn't begin transaction")
}
err = revokeBySerial(ctx, serial, revocation.Reason(reasonCode), cac, logger, tx)
err = revokeBySerial(ctx, serial, revocation.Reason(reasonCode), rac, logger, tx)
if err != nil {
cmd.FailOnError(sa.Rollback(tx, err), "Couldn't revoke certificate")
}
@ -180,7 +201,7 @@ func main() {
reasonCode, err := strconv.Atoi(args[1])
cmd.FailOnError(err, "Reason code argument must be an integer")
cac, logger, dbMap, sac, _ := setupContext(c)
rac, logger, dbMap, sac, _ := setupContext(c)
defer logger.AuditPanic()
tx, err := dbMap.Begin()
@ -193,7 +214,7 @@ func main() {
cmd.FailOnError(err, "Couldn't fetch registration")
}
err = revokeByReg(ctx, regID, revocation.Reason(reasonCode), cac, logger, tx)
err = revokeByReg(ctx, regID, revocation.Reason(reasonCode), rac, logger, tx)
if err != nil {
cmd.FailOnError(sa.Rollback(tx, err), "Couldn't revoke certificate")
}

View File

@ -24,6 +24,7 @@ import (
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/policy"
"github.com/letsencrypt/boulder/rpc"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
const clientName = "CA"
@ -169,8 +170,14 @@ func main() {
cai.PA = pa
amqpConf := c.CA.AMQP
cai.SA, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Failed to create SA client")
if c.CA.SAService != nil {
conn, err := bgrpc.ClientSetup(c.CA.SAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
cai.SA = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
cai.SA, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Failed to create SA client")
}
if amqpConf.Publisher != nil {
cai.Publisher, err = rpc.NewPublisherClient(clientName, amqpConf, scope)

View File

@ -14,6 +14,7 @@ import (
"github.com/letsencrypt/boulder/publisher"
pubPB "github.com/letsencrypt/boulder/publisher/proto"
"github.com/letsencrypt/boulder/rpc"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
const clientName = "Publisher"
@ -23,6 +24,7 @@ type config struct {
cmd.ServiceConfig
SubmissionTimeout cmd.ConfigDuration
MaxConcurrentRPCServerRequests int64
SAService *cmd.GRPCClientConfig
}
Statsd cmd.StatsdConfig
@ -72,8 +74,15 @@ func main() {
}
amqpConf := c.Publisher.AMQP
sa, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create SA client")
var sac core.StorageAuthority
if c.Publisher.SAService != nil {
conn, err := bgrpc.ClientSetup(c.Publisher.SAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create SA client")
}
pubi := publisher.New(
bundle,
@ -81,17 +90,17 @@ func main() {
c.Publisher.SubmissionTimeout.Duration,
logger,
scope,
sa)
sac)
var grpcSrv *grpc.Server
if c.Publisher.GRPC != nil {
s, l, err := bgrpc.NewServer(c.Publisher.GRPC, scope)
cmd.FailOnError(err, "Failed to setup gRPC server")
cmd.FailOnError(err, "Unable to setup Publisher gRPC server")
gw := bgrpc.NewPublisherServerWrapper(pubi)
pubPB.RegisterPublisherServer(s, gw)
go func() {
err = s.Serve(l)
cmd.FailOnError(err, "gRPC service failed")
cmd.FailOnError(err, "Publisher gRPC service failed")
}()
grpcSrv = s
}

View File

@ -3,10 +3,12 @@ package main
import (
"flag"
"fmt"
"net"
"os"
"time"
"github.com/jmhodges/clock"
"google.golang.org/grpc"
"github.com/letsencrypt/boulder/bdns"
caPB "github.com/letsencrypt/boulder/ca/proto"
@ -19,7 +21,9 @@ import (
"github.com/letsencrypt/boulder/policy"
pubPB "github.com/letsencrypt/boulder/publisher/proto"
"github.com/letsencrypt/boulder/ra"
rapb "github.com/letsencrypt/boulder/ra/proto"
"github.com/letsencrypt/boulder/rpc"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
const clientName = "RA"
@ -43,6 +47,7 @@ type config struct {
// will be turned into 1.
DNSTries int
SAService *cmd.GRPCClientConfig
VAService *cmd.GRPCClientConfig
CAService *cmd.GRPCClientConfig
PublisherService *cmd.GRPCClientConfig
@ -131,7 +136,7 @@ func main() {
if c.RA.CAService != nil {
conn, err := bgrpc.ClientSetup(c.RA.CAService, scope)
cmd.FailOnError(err, "Unable to create CA client")
cac = bgrpc.NewCertificateAuthorityClient(caPB.NewCertificateAuthorityClient(conn), c.RA.CAService.Timeout.Duration)
cac = bgrpc.NewCertificateAuthorityClient(caPB.NewCertificateAuthorityClient(conn))
} else {
cac, err = rpc.NewCertificateAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create CA client")
@ -141,11 +146,18 @@ func main() {
if c.RA.PublisherService != nil {
conn, err := bgrpc.ClientSetup(c.RA.PublisherService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to Publisher")
pubc = bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn), c.RA.PublisherService.Timeout.Duration)
pubc = bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn))
}
sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create SA client")
var sac core.StorageAuthority
if c.RA.SAService != nil {
conn, err := bgrpc.ClientSetup(c.RA.SAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Unable to create SA client")
}
// TODO(patf): remove once RA.authorizationLifetimeDays is deployed
authorizationLifetime := 300 * 24 * time.Hour
@ -206,10 +218,28 @@ func main() {
err = rai.UpdateIssuedCountForever()
cmd.FailOnError(err, "Updating total issuance count")
var grpcSrv *grpc.Server
if c.RA.GRPC != nil {
var listener net.Listener
grpcSrv, listener, err = bgrpc.NewServer(c.RA.GRPC, scope)
cmd.FailOnError(err, "Unable to setup RA gRPC server")
gw := bgrpc.NewRegistrationAuthorityServer(rai)
rapb.RegisterRegistrationAuthorityServer(grpcSrv, gw)
go func() {
err = grpcSrv.Serve(listener)
cmd.FailOnError(err, "RA gRPC service failed")
}()
}
ras, err := rpc.NewAmqpRPCServer(amqpConf, c.RA.MaxConcurrentRPCServerRequests, scope, logger)
cmd.FailOnError(err, "Unable to create RA RPC server")
go cmd.CatchSignals(logger, ras.Stop)
go cmd.CatchSignals(logger, func() {
ras.Stop()
if grpcSrv != nil {
grpcSrv.GracefulStop()
}
})
err = rpc.NewRegistrationAuthorityServer(ras, rai, logger)
cmd.FailOnError(err, "Unable to setup RA RPC server")

View File

@ -2,15 +2,19 @@ package main
import (
"flag"
"net"
"os"
"github.com/jmhodges/clock"
"google.golang.org/grpc"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/features"
bgrpc "github.com/letsencrypt/boulder/grpc"
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/sa"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
const clientName = "SA"
@ -63,11 +67,29 @@ func main() {
sai, err := sa.NewSQLStorageAuthority(dbMap, clock.Default(), logger)
cmd.FailOnError(err, "Failed to create SA impl")
var grpcSrv *grpc.Server
if c.SA.GRPC != nil {
var listener net.Listener
grpcSrv, listener, err = bgrpc.NewServer(c.SA.GRPC, scope)
cmd.FailOnError(err, "Unable to setup SA gRPC server")
gw := bgrpc.NewStorageAuthorityServer(sai)
sapb.RegisterStorageAuthorityServer(grpcSrv, gw)
go func() {
err = grpcSrv.Serve(listener)
cmd.FailOnError(err, "SA gRPC service failed")
}()
}
amqpConf := saConf.AMQP
sas, err := rpc.NewAmqpRPCServer(amqpConf, c.SA.MaxConcurrentRPCServerRequests, scope, logger)
cmd.FailOnError(err, "Unable to create SA RPC server")
go cmd.CatchSignals(logger, sas.Stop)
go cmd.CatchSignals(logger, func() {
sas.Stop()
if grpcSrv != nil {
grpcSrv.GracefulStop()
}
})
err = rpc.NewStorageAuthorityServer(sas, sai)
cmd.FailOnError(err, "Unable to setup SA RPC server")

View File

@ -10,11 +10,15 @@ import (
"github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/features"
"github.com/letsencrypt/boulder/goodkey"
bgrpc "github.com/letsencrypt/boulder/grpc"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics"
rapb "github.com/letsencrypt/boulder/ra/proto"
"github.com/letsencrypt/boulder/rpc"
sapb "github.com/letsencrypt/boulder/sa/proto"
"github.com/letsencrypt/boulder/wfe"
)
@ -38,10 +42,12 @@ type config struct {
SubscriberAgreementURL string
CheckMalformedCSR bool
AcceptRevocationReason bool
AllowAuthzDeactivation bool
RAService *cmd.GRPCClientConfig
SAService *cmd.GRPCClientConfig
Features map[string]bool
}
@ -57,13 +63,29 @@ type config struct {
}
}
func setupWFE(c config, logger blog.Logger, stats metrics.Scope) (*rpc.RegistrationAuthorityClient, *rpc.StorageAuthorityClient) {
func setupWFE(c config, logger blog.Logger, stats metrics.Scope) (core.RegistrationAuthority, core.StorageAuthority) {
amqpConf := c.WFE.AMQP
rac, err := rpc.NewRegistrationAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create RA client")
var rac core.RegistrationAuthority
if c.WFE.RAService != nil {
conn, err := bgrpc.ClientSetup(c.WFE.RAService, stats)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to RA")
rac = bgrpc.NewRegistrationAuthorityClient(rapb.NewRegistrationAuthorityClient(conn))
} else {
var err error
rac, err = rpc.NewRegistrationAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create RA AMQP client")
}
sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create SA client")
var sac core.StorageAuthority
if c.WFE.SAService != nil {
conn, err := bgrpc.ClientSetup(c.WFE.SAService, stats)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
var err error
sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create SA client")
}
return rac, sac
}
@ -102,7 +124,6 @@ func main() {
}
wfe.AllowOrigins = c.WFE.AllowOrigins
wfe.CheckMalformedCSR = c.WFE.CheckMalformedCSR
wfe.AcceptRevocationReason = c.WFE.AcceptRevocationReason
wfe.AllowAuthzDeactivation = c.WFE.AllowAuthzDeactivation
@ -118,8 +139,7 @@ func main() {
// Set up paths
wfe.BaseURL = c.Common.BaseURL
h, err := wfe.Handler()
cmd.FailOnError(err, "Problem setting up HTTP handlers")
h := wfe.Handler()
httpMonitor := metrics.NewHTTPMonitor(scope, h)

View File

@ -8,6 +8,7 @@ import (
"log/syslog"
"os"
"reflect"
"regexp"
"runtime"
"sync"
"sync/atomic"
@ -33,6 +34,26 @@ const (
expectedValidityPeriod = time.Hour * 24 * 90
)
// For defense-in-depth in addition to using the PA & its hostnamePolicy to
// check domain names we also perform a check against the regex's from the
// forbiddenDomains array
var forbiddenDomainPatterns = []*regexp.Regexp{
regexp.MustCompile(`^\s*$`),
regexp.MustCompile(`\.mil$`),
regexp.MustCompile(`\.local$`),
regexp.MustCompile(`^localhost$`),
regexp.MustCompile(`\.localhost$`),
}
func isForbiddenDomain(name string) (bool, string) {
for _, r := range forbiddenDomainPatterns {
if matches := r.FindAllStringSubmatch(name, -1); len(matches) > 0 {
return true, r.String()
}
}
return false, ""
}
var batchSize = 1000
type report struct {
@ -214,6 +235,16 @@ func (c *certChecker) checkCert(cert core.Certificate) (problems []string) {
id := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name}
if err = c.pa.WillingToIssue(id); err != nil {
problems = append(problems, fmt.Sprintf("Policy Authority isn't willing to issue for '%s': %s", name, err))
} else {
// For defense-in-depth, even if the PA was willing to issue for a name
// we double check it against a list of forbidden domains. This way even
// if the hostnamePolicyFile malfunctions we will flag the forbidden
// domain matches
if forbidden, pattern := isForbiddenDomain(name); forbidden {
problems = append(problems, fmt.Sprintf(
"Policy Authority was willing to issue but domain '%s' matches "+
"forbiddenDomains entry %q", name, pattern))
}
}
}
// Check the cert has the correct key usage extensions

View File

@ -102,7 +102,7 @@ func TestCheckCert(t *testing.T) {
},
NotBefore: issued,
NotAfter: goodExpiry.AddDate(0, 0, 1), // Period too long
DNSNames: []string{"example-a.com"},
DNSNames: []string{"example-a.com", "foodnotbombs.mil"},
SerialNumber: serial,
BasicConstraintsValid: false,
}
@ -131,6 +131,8 @@ func TestCheckCert(t *testing.T) {
"Stored issuance date is outside of 6 hour window of certificate NotBefore": 1,
"Certificate has incorrect key usage extensions": 1,
"Certificate has common name >64 characters long (65)": 1,
"Policy Authority was willing to issue but domain 'foodnotbombs.mil' " +
"matches forbiddenDomains entry \"\\\\.mil$\"": 1,
}
for _, p := range problems {
_, ok := problemsMap[p]
@ -142,7 +144,7 @@ func TestCheckCert(t *testing.T) {
for k := range problemsMap {
t.Errorf("Expected problem but didn't find it: '%s'.", k)
}
test.AssertEquals(t, len(problems), 8)
test.AssertEquals(t, len(problems), 9)
// Same settings as above, but the stored serial number in the DB is invalid.
cert.Serial = "not valid"
@ -157,6 +159,7 @@ func TestCheckCert(t *testing.T) {
// Fix the problems
rawCert.Subject.CommonName = "example-a.com"
rawCert.DNSNames = []string{"example-a.com"}
rawCert.NotAfter = goodExpiry
rawCert.BasicConstraintsValid = true
rawCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
@ -294,3 +297,47 @@ func TestSaveReport(t *testing.T) {
err := r.dump()
test.AssertNotError(t, err, "Failed to dump results")
}
func TestIsForbiddenDomain(t *testing.T) {
// Note: These testcases are not an exhaustive representation of domains
// Boulder won't issue for, but are instead testing the defense-in-depth
// `isForbiddenDomain` function called *after* the PA has vetted the name
// against the complex hostname policy file.
testcases := []struct {
Name string
Expected bool
}{
/* Expected to be forbidden test cases */
// Whitespace only
{Name: "", Expected: true},
{Name: " ", Expected: true},
// Anything .mil
{Name: "foodnotbombs.mil", Expected: true},
{Name: "www.foodnotbombs.mil", Expected: true},
{Name: ".mil", Expected: true},
// Anything .local
{Name: "yokel.local", Expected: true},
{Name: "off.on.remote.local", Expected: true},
{Name: ".local", Expected: true},
// Localhost is verboten
{Name: "localhost", Expected: true},
// Anything .localhost
{Name: ".localhost", Expected: true},
{Name: "local.localhost", Expected: true},
{Name: "extremely.local.localhost", Expected: true},
/* Expected to be allowed test cases */
{Name: "ok.computer.com", Expected: false},
{Name: "ok.millionaires", Expected: false},
{Name: "ok.milly", Expected: false},
{Name: "ok", Expected: false},
{Name: "nearby.locals", Expected: false},
{Name: "yocalhost", Expected: false},
{Name: "jokes.yocalhost", Expected: false},
}
for _, tc := range testcases {
result, _ := isForbiddenDomain(tc.Name)
test.AssertEquals(t, result, tc.Expected)
}
}

View File

@ -146,6 +146,8 @@ type CAConfig struct {
// triggers issuance of certificates with Must Staple.
EnableMustStaple bool
SAService *GRPCClientConfig
Features map[string]bool
}
@ -236,6 +238,8 @@ type OCSPUpdaterConfig struct {
SignFailureBackoffMax ConfigDuration
Publisher *GRPCClientConfig
SAService *GRPCClientConfig
CAService *GRPCClientConfig
}
// GoogleSafeBrowsingConfig is the JSON config struct for the VA's use of the

View File

@ -62,10 +62,10 @@ func writeContacts(contactsList []contact, outfile string) error {
if outfile != "" {
return ioutil.WriteFile(outfile, data, 0644)
} else {
fmt.Printf("%s", data)
return nil
}
fmt.Printf("%s", data)
return nil
}
const usageIntro = `

View File

@ -83,13 +83,13 @@ func TestFindContacts(t *testing.T) {
func exampleContacts() []contact {
return []contact{
contact{
{
ID: 1,
},
contact{
{
ID: 2,
},
contact{
{
ID: 3,
},
}

View File

@ -23,11 +23,13 @@ import (
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
bgrpc "github.com/letsencrypt/boulder/grpc"
blog "github.com/letsencrypt/boulder/log"
bmail "github.com/letsencrypt/boulder/mail"
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/sa"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
const defaultNagCheckInterval = 24 * time.Hour
@ -326,6 +328,8 @@ type config struct {
NagCheckInterval string
// Path to a text/template email template
EmailTemplate string
SAService *cmd.GRPCClientConfig
}
Statsd cmd.StatsdConfig
@ -371,9 +375,15 @@ func main() {
cmd.FailOnError(err, "Could not connect to database")
go sa.ReportDbConnCount(dbMap, scope)
amqpConf := c.Mailer.AMQP
sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
cmd.FailOnError(err, "Failed to create SA client")
var sac core.StorageAuthority
if c.Mailer.SAService != nil {
conn, err := bgrpc.ClientSetup(c.Mailer.SAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
sac, err = rpc.NewStorageAuthorityClient(clientName, c.Mailer.AMQP, scope)
cmd.FailOnError(err, "Failed to create SA client")
}
// Load email template
emailTmpl, err := ioutil.ReadFile(c.Mailer.EmailTemplate)

View File

@ -19,6 +19,8 @@ import (
"github.com/letsencrypt/boulder/sa"
)
const clientName = "ExpiredAuthzPurger"
type eapConfig struct {
ExpiredAuthzPurger struct {
cmd.DBConfig
@ -113,7 +115,7 @@ func main() {
// Set up logging
stats, auditlogger := cmd.StatsAndLogging(config.ExpiredAuthzPurger.Statsd, config.ExpiredAuthzPurger.Syslog)
scope := metrics.NewStatsdScope(stats, "AuthzPurger")
auditlogger.Info(cmd.Version())
auditlogger.Info(cmd.VersionString(clientName))
defer auditlogger.AuditPanic()

View File

@ -304,27 +304,27 @@ type mockEmailResolver struct{}
func (bs mockEmailResolver) SelectOne(output interface{}, _ string, args ...interface{}) error {
// The "db" is just a list in memory
db := []contactJSON{
contactJSON{
{
ID: 1,
Contact: []byte(`["mailto:example@example.com"]`),
},
contactJSON{
{
ID: 2,
Contact: []byte(`["mailto:test-example-updated@example.com"]`),
},
contactJSON{
{
ID: 3,
Contact: []byte(`["mailto:test-test-test@example.com"]`),
},
contactJSON{
{
ID: 4,
Contact: []byte(`["mailto:example-example-example@example.com"]`),
},
contactJSON{
{
ID: 5,
Contact: []byte(`["mailto:youve.got.mail@example.com"]`),
},
contactJSON{
{
ID: 6,
Contact: []byte(`["mailto:mail@example.com"]`),
},
@ -367,18 +367,18 @@ func TestResolveEmails(t *testing.T) {
// more test cases here you must also add the corresponding DB result in the
// mock.
regs := []regID{
regID{
{
ID: 1,
},
regID{
{
ID: 2,
},
regID{
{
ID: 3,
},
// This registration ID deliberately doesn't exist in the mock data to make
// sure this case is handled gracefully
regID{
{
ID: 999,
},
}

View File

@ -16,6 +16,7 @@ import (
"golang.org/x/net/context"
"github.com/letsencrypt/boulder/akamai"
capb "github.com/letsencrypt/boulder/ca/proto"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/features"
@ -25,6 +26,7 @@ import (
pubPB "github.com/letsencrypt/boulder/publisher/proto"
"github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/sa"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
/*
@ -586,14 +588,32 @@ func setupClients(c cmd.OCSPUpdaterConfig, stats metrics.Scope) (
core.StorageAuthority,
) {
amqpConf := c.AMQP
cac, err := rpc.NewCertificateAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create CA client")
var cac core.CertificateAuthority
if c.CAService != nil {
conn, err := bgrpc.ClientSetup(c.CAService, stats)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to CA")
cac = bgrpc.NewCertificateAuthorityClient(capb.NewCertificateAuthorityClient(conn))
} else {
var err error
cac, err = rpc.NewCertificateAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create CA client")
}
conn, err := bgrpc.ClientSetup(c.Publisher, stats)
cmd.FailOnError(err, "Failed to load credentials and create connection to service")
pubc := bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn), c.Publisher.Timeout.Duration)
sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create SA client")
pubc := bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn))
var sac core.StorageAuthority
if c.SAService != nil {
conn, err := bgrpc.ClientSetup(c.SAService, stats)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, stats)
cmd.FailOnError(err, "Unable to create SA client")
}
return cac, pubc, sac
}

View File

@ -91,6 +91,7 @@ func setup(t *testing.T) (*OCSPUpdater, core.StorageAuthority, *gorp.DbMap, cloc
"",
blog.NewMock(),
)
test.AssertNotError(t, err, "Failed to create newUpdater")
return updater, sa, dbMap, fc, cleanUp
}

View File

@ -16,9 +16,11 @@ import (
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
bgrpc "github.com/letsencrypt/boulder/grpc"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/rpc"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
var usageString = `
@ -35,9 +37,10 @@ command descriptions:
`
type config struct {
AMQP cmd.AMQPConfig
Statsd cmd.StatsdConfig
Syslog cmd.SyslogConfig
AMQP cmd.AMQPConfig
Statsd cmd.StatsdConfig
SAService *cmd.GRPCClientConfig
Syslog cmd.SyslogConfig
}
type certificateStorage interface {
@ -110,7 +113,7 @@ func parseLogLine(sa certificateStorage, logger blog.Logger, line string) (found
return true, true
}
func setup(configFile string) (metrics.Scope, blog.Logger, *rpc.StorageAuthorityClient) {
func setup(configFile string) (metrics.Scope, blog.Logger, core.StorageAuthority) {
configJSON, err := ioutil.ReadFile(configFile)
cmd.FailOnError(err, "Failed to read config file")
var conf config
@ -118,9 +121,17 @@ func setup(configFile string) (metrics.Scope, blog.Logger, *rpc.StorageAuthority
cmd.FailOnError(err, "Failed to parse config file")
stats, logger := cmd.StatsAndLogging(conf.Statsd, conf.Syslog)
scope := metrics.NewStatsdScope(stats, "OrphanFinder")
sa, err := rpc.NewStorageAuthorityClient("orphan-finder", &conf.AMQP, scope)
cmd.FailOnError(err, "Failed to create SA client")
return scope, logger, sa
var sac core.StorageAuthority
if conf.SAService != nil {
conn, err := bgrpc.ClientSetup(conf.SAService, scope)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
} else {
sac, err = rpc.NewStorageAuthorityClient("orphan-finder", &conf.AMQP, scope)
cmd.FailOnError(err, "Failed to create SA client")
}
return scope, logger, sac
}
func main() {

View File

@ -51,17 +51,12 @@ import (
func init() {
for _, v := range os.Args {
if v == "--version" || v == "-version" {
fmt.Println(Version())
fmt.Println(VersionString(os.Args[0]))
os.Exit(0)
}
}
}
// Version returns a string representing the version of boulder running.
func Version() string {
return fmt.Sprintf("0.1.0 [%s]", core.GetBuildID())
}
// mysqlLogger proxies blog.AuditLogger to provide a Print(...) method.
type mysqlLogger struct {
blog.Logger

View File

@ -2,8 +2,12 @@ package cmd
import (
"encoding/json"
"fmt"
"runtime"
"testing"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/test"
)
@ -51,3 +55,128 @@ func TestPAConfigUnmarshal(t *testing.T) {
test.AssertNotError(t, err, "Failed to unmarshal PAConfig")
test.AssertError(t, pc4.CheckChallenges(), "Disallow empty challenges map")
}
func TestMysqlLogger(t *testing.T) {
log := blog.UseMock()
mLog := mysqlLogger{log}
testCases := []struct {
args []interface{}
expected string
}{
{
[]interface{}{nil},
`ERR: [AUDIT] [mysql] <nil>`,
},
{
[]interface{}{""},
`ERR: [AUDIT] [mysql] `,
},
{
[]interface{}{"Sup ", 12345, " Sup sup"},
`ERR: [AUDIT] [mysql] Sup 12345 Sup sup`,
},
}
for _, tc := range testCases {
// mysqlLogger proxies blog.AuditLogger to provide a Print() method
mLog.Print(tc.args...)
logged := log.GetAll()
// Calling Print should produce the expected output
test.AssertEquals(t, len(logged), 1)
test.AssertEquals(t, logged[0], tc.expected)
log.Clear()
}
}
func TestCfsslLogger(t *testing.T) {
log := blog.UseMock()
cLog := cfsslLogger{log}
testCases := []struct {
msg, expected string
}{
{
"",
"ERR: [AUDIT] ",
},
{
"Test",
"ERR: [AUDIT] Test",
},
}
for _, tc := range testCases {
// cfsslLogger proxies blog.AuditLogger to provide Crit() and Emerg()
// methods that are expected by CFSSL's logger
cLog.Crit(tc.msg)
cLog.Emerg(tc.msg)
logged := log.GetAll()
// Calling Crit and Emerg should produce two AuditErr outputs matching the
// testCase expected output
test.AssertEquals(t, len(logged), 2)
test.AssertEquals(t, logged[0], tc.expected)
test.AssertEquals(t, logged[1], tc.expected)
log.Clear()
}
}
func TestVersionString(t *testing.T) {
core.BuildID = "TestBuildID"
core.BuildTime = "RightNow!"
core.BuildHost = "Localhost"
versionStr := VersionString("test")
expected := fmt.Sprintf("Versions: test=(TestBuildID RightNow!) Golang=(%s) BuildHost=(Localhost)", runtime.Version())
test.AssertEquals(t, versionStr, expected)
}
func TestLoadCert(t *testing.T) {
testCases := []struct {
path string
expectedErr string
}{
{
"",
"Issuer certificate was not provided in config.",
},
{
"../does/not/exist",
"open ../does/not/exist: no such file or directory",
},
{
"../test/test-ca.key",
"Invalid certificate value returned",
},
}
for _, tc := range testCases {
_, err := LoadCert(tc.path)
test.AssertError(t, err, fmt.Sprintf("LoadCert(%q) did not error", tc.path))
test.AssertEquals(t, err.Error(), tc.expectedErr)
}
bytes, err := LoadCert("../test/test-ca.pem")
test.AssertNotError(t, err, "LoadCert(../test/test-ca.pem) errored")
test.AssertNotEquals(t, len(bytes), 0)
}
func TestReadConfigFile(t *testing.T) {
err := ReadConfigFile("", nil)
test.AssertError(t, err, "ReadConfigFile('') did not error")
type config struct {
NotifyMailer struct {
DBConfig
PasswordConfig
SMTPConfig
}
Statsd StatsdConfig
Syslog SyslogConfig
}
var c config
err = ReadConfigFile("../test/config/notify-mailer.json", &c)
test.AssertNotError(t, err, "ReadConfigFile(../test/config/notify-mailer.json) errored")
test.AssertEquals(t, c.NotifyMailer.SMTPConfig.Server, "localhost")
test.AssertEquals(t, c.Syslog.StdoutLevel, 6)
}

View File

@ -466,7 +466,7 @@ type CertificateStatus struct {
// For performance reasons[0] we duplicate the `Expires` field of the
// `Certificates` object/table in `CertificateStatus` to avoid a costly `JOIN`
// later on just to retreive this `Time` value. This helps both the OCSP
// later on just to retrieve this `Time` value. This helps both the OCSP
// updater and the expiration-mailer stay performant.
//
// Similarly, we add an explicit `IsExpired` boolean to `CertificateStatus`

View File

@ -12,6 +12,10 @@ It has these top-level messages:
Challenge
ValidationRecord
ProblemDetails
Certificate
Registration
Authorization
Empty
*/
package proto
@ -193,34 +197,255 @@ func (m *ProblemDetails) GetHttpStatus() int32 {
return 0
}
type Certificate struct {
RegistrationID *int64 `protobuf:"varint,1,opt,name=registrationID" json:"registrationID,omitempty"`
Serial *string `protobuf:"bytes,2,opt,name=serial" json:"serial,omitempty"`
Digest *string `protobuf:"bytes,3,opt,name=digest" json:"digest,omitempty"`
Der []byte `protobuf:"bytes,4,opt,name=der" json:"der,omitempty"`
Issued *int64 `protobuf:"varint,5,opt,name=issued" json:"issued,omitempty"`
Expires *int64 `protobuf:"varint,6,opt,name=expires" json:"expires,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Certificate) Reset() { *m = Certificate{} }
func (m *Certificate) String() string { return proto1.CompactTextString(m) }
func (*Certificate) ProtoMessage() {}
func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *Certificate) GetRegistrationID() int64 {
if m != nil && m.RegistrationID != nil {
return *m.RegistrationID
}
return 0
}
func (m *Certificate) GetSerial() string {
if m != nil && m.Serial != nil {
return *m.Serial
}
return ""
}
func (m *Certificate) GetDigest() string {
if m != nil && m.Digest != nil {
return *m.Digest
}
return ""
}
func (m *Certificate) GetDer() []byte {
if m != nil {
return m.Der
}
return nil
}
func (m *Certificate) GetIssued() int64 {
if m != nil && m.Issued != nil {
return *m.Issued
}
return 0
}
func (m *Certificate) GetExpires() int64 {
if m != nil && m.Expires != nil {
return *m.Expires
}
return 0
}
type Registration struct {
Id *int64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"`
Contact []string `protobuf:"bytes,3,rep,name=contact" json:"contact,omitempty"`
ContactsPresent *bool `protobuf:"varint,4,opt,name=contactsPresent" json:"contactsPresent,omitempty"`
Agreement *string `protobuf:"bytes,5,opt,name=agreement" json:"agreement,omitempty"`
InitialIP []byte `protobuf:"bytes,6,opt,name=initialIP" json:"initialIP,omitempty"`
CreatedAt *int64 `protobuf:"varint,7,opt,name=createdAt" json:"createdAt,omitempty"`
Status *string `protobuf:"bytes,8,opt,name=status" json:"status,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Registration) Reset() { *m = Registration{} }
func (m *Registration) String() string { return proto1.CompactTextString(m) }
func (*Registration) ProtoMessage() {}
func (*Registration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *Registration) GetId() int64 {
if m != nil && m.Id != nil {
return *m.Id
}
return 0
}
func (m *Registration) GetKey() []byte {
if m != nil {
return m.Key
}
return nil
}
func (m *Registration) GetContact() []string {
if m != nil {
return m.Contact
}
return nil
}
func (m *Registration) GetContactsPresent() bool {
if m != nil && m.ContactsPresent != nil {
return *m.ContactsPresent
}
return false
}
func (m *Registration) GetAgreement() string {
if m != nil && m.Agreement != nil {
return *m.Agreement
}
return ""
}
func (m *Registration) GetInitialIP() []byte {
if m != nil {
return m.InitialIP
}
return nil
}
func (m *Registration) GetCreatedAt() int64 {
if m != nil && m.CreatedAt != nil {
return *m.CreatedAt
}
return 0
}
func (m *Registration) GetStatus() string {
if m != nil && m.Status != nil {
return *m.Status
}
return ""
}
type Authorization struct {
Id *string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Identifier *string `protobuf:"bytes,2,opt,name=identifier" json:"identifier,omitempty"`
RegistrationID *int64 `protobuf:"varint,3,opt,name=registrationID" json:"registrationID,omitempty"`
Status *string `protobuf:"bytes,4,opt,name=status" json:"status,omitempty"`
Expires *int64 `protobuf:"varint,5,opt,name=expires" json:"expires,omitempty"`
Challenges []*Challenge `protobuf:"bytes,6,rep,name=challenges" json:"challenges,omitempty"`
Combinations []byte `protobuf:"bytes,7,opt,name=combinations" json:"combinations,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Authorization) Reset() { *m = Authorization{} }
func (m *Authorization) String() string { return proto1.CompactTextString(m) }
func (*Authorization) ProtoMessage() {}
func (*Authorization) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *Authorization) GetId() string {
if m != nil && m.Id != nil {
return *m.Id
}
return ""
}
func (m *Authorization) GetIdentifier() string {
if m != nil && m.Identifier != nil {
return *m.Identifier
}
return ""
}
func (m *Authorization) GetRegistrationID() int64 {
if m != nil && m.RegistrationID != nil {
return *m.RegistrationID
}
return 0
}
func (m *Authorization) GetStatus() string {
if m != nil && m.Status != nil {
return *m.Status
}
return ""
}
func (m *Authorization) GetExpires() int64 {
if m != nil && m.Expires != nil {
return *m.Expires
}
return 0
}
func (m *Authorization) GetChallenges() []*Challenge {
if m != nil {
return m.Challenges
}
return nil
}
func (m *Authorization) GetCombinations() []byte {
if m != nil {
return m.Combinations
}
return nil
}
type Empty struct {
XXX_unrecognized []byte `json:"-"`
}
func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto1.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func init() {
proto1.RegisterType((*Challenge)(nil), "core.Challenge")
proto1.RegisterType((*ValidationRecord)(nil), "core.ValidationRecord")
proto1.RegisterType((*ProblemDetails)(nil), "core.ProblemDetails")
proto1.RegisterType((*Certificate)(nil), "core.Certificate")
proto1.RegisterType((*Registration)(nil), "core.Registration")
proto1.RegisterType((*Authorization)(nil), "core.Authorization")
proto1.RegisterType((*Empty)(nil), "core.Empty")
}
func init() { proto1.RegisterFile("core/proto/core.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 312 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x91, 0xcb, 0x6e, 0xf2, 0x30,
0x10, 0x85, 0x65, 0x42, 0xe0, 0xcf, 0x84, 0x1f, 0x81, 0x7b, 0x91, 0xbb, 0xb3, 0xe8, 0x26, 0x2b,
0x50, 0x79, 0x83, 0x5e, 0x36, 0xdd, 0x55, 0xf4, 0xb2, 0xe8, 0xce, 0xc5, 0xa3, 0xc6, 0xc2, 0xc4,
0x91, 0x3d, 0x20, 0xd1, 0x75, 0xdf, 0xac, 0x2f, 0x56, 0xc5, 0x09, 0x95, 0xaa, 0xee, 0x66, 0xce,
0xf1, 0x48, 0xe7, 0x7c, 0x86, 0xb3, 0xb5, 0xf3, 0xb8, 0xa8, 0xbd, 0x23, 0xb7, 0x68, 0xc6, 0x79,
0x1c, 0x79, 0xbf, 0x99, 0x67, 0x5f, 0x0c, 0xb2, 0xdb, 0x52, 0x59, 0x8b, 0xd5, 0x3b, 0x72, 0x80,
0x9e, 0xd1, 0x82, 0x49, 0x56, 0x24, 0x7c, 0x04, 0x7d, 0x3a, 0xd4, 0x28, 0x7a, 0x92, 0x15, 0x19,
0x1f, 0xc3, 0x20, 0x90, 0xa2, 0x5d, 0x10, 0x83, 0xb8, 0xe7, 0x90, 0xec, 0xbc, 0x11, 0x59, 0x5c,
0xfe, 0x43, 0x4a, 0x6e, 0x83, 0x95, 0x48, 0xe2, 0x2a, 0x60, 0xb2, 0xc1, 0xc3, 0xf5, 0x8e, 0x4a,
0xe7, 0xcd, 0x87, 0x22, 0xe3, 0x2a, 0x91, 0x46, 0xe7, 0x0a, 0xa6, 0x7b, 0x65, 0x8d, 0x8e, 0x9a,
0xc7, 0xb5, 0xf3, 0x3a, 0x08, 0x90, 0x49, 0x91, 0x2f, 0xcf, 0xe7, 0x31, 0xdb, 0xcb, 0x8f, 0xbd,
0x8a, 0x36, 0xbf, 0x84, 0x14, 0xbd, 0x77, 0x5e, 0x0c, 0x25, 0x2b, 0xf2, 0xe5, 0x69, 0xfb, 0xec,
0xc1, 0xbb, 0x37, 0x8b, 0xdb, 0x3b, 0x24, 0x65, 0x6c, 0x98, 0x7d, 0x32, 0x98, 0xfc, 0xb9, 0x9c,
0xc0, 0xbf, 0xd2, 0x05, 0xaa, 0xd4, 0x16, 0x63, 0xa5, 0xac, 0xa9, 0x54, 0x3b, 0x4f, 0x5d, 0xa5,
0x0b, 0x98, 0x2a, 0xad, 0x3d, 0x86, 0x80, 0x61, 0x85, 0xc1, 0xd9, 0x3d, 0x6a, 0x91, 0xc8, 0xa4,
0x18, 0xf1, 0x13, 0xc8, 0x3b, 0xeb, 0x39, 0xa0, 0x16, 0x7d, 0xc9, 0x3a, 0xb1, 0xed, 0x44, 0x06,
0x83, 0x48, 0x65, 0x72, 0xe4, 0x60, 0x5b, 0x28, 0xb3, 0x7b, 0x18, 0xff, 0x0e, 0xd6, 0xdc, 0xd4,
0xad, 0xf2, 0xd4, 0xb0, 0x64, 0x47, 0x96, 0x3a, 0xfa, 0x5d, 0x10, 0x0e, 0x50, 0x12, 0xd5, 0x8f,
0x2d, 0xdf, 0x86, 0x61, 0x7a, 0x33, 0x7c, 0x4d, 0xe3, 0x37, 0x7d, 0x07, 0x00, 0x00, 0xff, 0xff,
0x1c, 0xa6, 0xad, 0x9d, 0xbe, 0x01, 0x00, 0x00,
// 520 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x93, 0xcf, 0x72, 0xd3, 0x30,
0x10, 0xc6, 0xc7, 0x55, 0xdc, 0xd4, 0x6b, 0x37, 0x6d, 0x4c, 0x29, 0xe2, 0xe6, 0x71, 0x2f, 0x39,
0xb5, 0x43, 0xdf, 0xa0, 0xb4, 0x1c, 0x72, 0xcb, 0x84, 0x3f, 0x07, 0x6e, 0xaa, 0xb5, 0x24, 0x9a,
0x38, 0x96, 0x47, 0xda, 0x74, 0x08, 0x67, 0x9e, 0x82, 0x2b, 0x8f, 0xc2, 0x8b, 0x31, 0x5a, 0x3b,
0x34, 0xa1, 0x37, 0x69, 0x57, 0xd2, 0xee, 0xfe, 0xbe, 0x4f, 0xf0, 0xba, 0xb2, 0x0e, 0x6f, 0x5a,
0x67, 0xc9, 0xde, 0x84, 0xe5, 0x35, 0x2f, 0xf3, 0x41, 0x58, 0x97, 0x7f, 0x22, 0x48, 0xee, 0x97,
0xaa, 0xae, 0xb1, 0x59, 0x60, 0x0e, 0x70, 0x64, 0xb4, 0x8c, 0x8a, 0x68, 0x22, 0xf2, 0x0c, 0x06,
0xb4, 0x6d, 0x51, 0x1e, 0x15, 0xd1, 0x24, 0xc9, 0x47, 0x70, 0xec, 0x49, 0xd1, 0xc6, 0xcb, 0x63,
0xde, 0xa7, 0x20, 0x36, 0xce, 0xc8, 0x84, 0x37, 0xa7, 0x10, 0x93, 0x5d, 0x61, 0x23, 0x05, 0x6f,
0x25, 0x9c, 0xaf, 0x70, 0x7b, 0xb7, 0xa1, 0xa5, 0x75, 0xe6, 0x87, 0x22, 0x63, 0x1b, 0x19, 0x73,
0xe6, 0x1d, 0x8c, 0x9f, 0x54, 0x6d, 0x34, 0xc7, 0x1c, 0x56, 0xd6, 0x69, 0x2f, 0xa1, 0x10, 0x93,
0xf4, 0xf6, 0xf2, 0x9a, 0x7b, 0xfb, 0xf2, 0x2f, 0x3d, 0xe7, 0x74, 0x7e, 0x05, 0x31, 0x3a, 0x67,
0x9d, 0x1c, 0x16, 0xd1, 0x24, 0xbd, 0xbd, 0xe8, 0x8e, 0xcd, 0x9c, 0x7d, 0xac, 0x71, 0xfd, 0x80,
0xa4, 0x4c, 0xed, 0xcb, 0x9f, 0x11, 0x9c, 0xbf, 0xb8, 0x79, 0x0e, 0x27, 0x4b, 0xeb, 0xa9, 0x51,
0x6b, 0xe4, 0x91, 0x92, 0x30, 0x52, 0x6b, 0x1d, 0xf5, 0x23, 0xbd, 0x85, 0xb1, 0xd2, 0xda, 0xa1,
0xf7, 0xe8, 0xe7, 0xe8, 0x6d, 0xfd, 0x84, 0x5a, 0x8a, 0x42, 0x4c, 0xb2, 0xfc, 0x15, 0xa4, 0x7d,
0xea, 0xb3, 0x47, 0x2d, 0x07, 0x45, 0xd4, 0x07, 0xbb, 0x99, 0xc8, 0xa0, 0x97, 0x71, 0x21, 0x76,
0x1c, 0xea, 0x0e, 0x4a, 0x39, 0x85, 0xd1, 0x61, 0x63, 0xe1, 0x4e, 0xdb, 0x45, 0x3e, 0x05, 0x96,
0xd1, 0x8e, 0xa5, 0xe6, 0x7c, 0xdf, 0x48, 0x0e, 0xb0, 0x24, 0x6a, 0x3f, 0x76, 0x7c, 0x03, 0xc3,
0xb8, 0xf4, 0x90, 0xde, 0xa3, 0x23, 0xf3, 0xcd, 0x54, 0x8a, 0x30, 0xbf, 0x84, 0x91, 0xc3, 0x85,
0xf1, 0xe4, 0x78, 0xc2, 0xe9, 0x43, 0x2f, 0x52, 0x90, 0x05, 0x9d, 0x51, 0xf5, 0xb3, 0x4c, 0xda,
0x2c, 0xd0, 0x53, 0x2f, 0x45, 0x0a, 0x42, 0xa3, 0xeb, 0x07, 0x18, 0xc1, 0xb1, 0xf1, 0x7e, 0x83,
0x9a, 0xd5, 0x10, 0xf9, 0x19, 0x0c, 0xf1, 0x7b, 0x6b, 0x1c, 0x76, 0xa2, 0x8a, 0xf2, 0x57, 0x04,
0xd9, 0x7c, 0xaf, 0xcc, 0x81, 0x1f, 0x52, 0x10, 0x2b, 0xdc, 0x72, 0x9d, 0x2c, 0x5c, 0xad, 0x6c,
0x43, 0xaa, 0x22, 0x26, 0x96, 0xe4, 0x6f, 0xe0, 0xac, 0x0f, 0xf8, 0x99, 0x43, 0x8f, 0x0d, 0x71,
0xd1, 0x93, 0x7c, 0x0c, 0x89, 0x5a, 0x38, 0xc4, 0x75, 0x08, 0x75, 0x2e, 0x18, 0x43, 0x62, 0x1a,
0x43, 0x46, 0xd5, 0xd3, 0x19, 0x57, 0xce, 0x42, 0xa8, 0x72, 0xa8, 0x08, 0xf5, 0x1d, 0xb1, 0xd2,
0x62, 0xcf, 0x71, 0x27, 0x0c, 0xf7, 0x77, 0x04, 0xa7, 0x07, 0x9e, 0xda, 0xeb, 0x8e, 0x19, 0x1a,
0x8d, 0x4d, 0x00, 0x86, 0xae, 0x87, 0xf1, 0x12, 0x9a, 0xf8, 0xef, 0xe5, 0x01, 0x9f, 0xdb, 0xe3,
0xd0, 0x81, 0xb9, 0x02, 0xa8, 0x76, 0x7f, 0x22, 0xb0, 0x09, 0xfe, 0x3c, 0xeb, 0x8c, 0xf7, 0xfc,
0x57, 0x2e, 0x20, 0xab, 0xec, 0xfa, 0xd1, 0x34, 0xfc, 0xb8, 0xe7, 0xae, 0xb3, 0x72, 0x08, 0xf1,
0x87, 0x75, 0x4b, 0xdb, 0xf7, 0xc3, 0xaf, 0x31, 0xff, 0xb3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff,
0xbb, 0xf8, 0xbc, 0xd0, 0x7f, 0x03, 0x00, 0x00,
}

View File

@ -1,7 +1,6 @@
syntax = "proto2";
package core;
option go_package = "proto";
message Challenge {
@ -30,3 +29,35 @@ message ProblemDetails {
optional string detail = 2;
optional int32 httpStatus = 3;
}
message Certificate {
optional int64 registrationID = 1;
optional string serial = 2;
optional string digest = 3;
optional bytes der = 4;
optional int64 issued = 5; // Unix timestamp (nanoseconds)
optional int64 expires = 6; // Unix timestamp (nanoseconds)
}
message Registration {
optional int64 id = 1;
optional bytes key = 2;
repeated string contact = 3;
optional bool contactsPresent = 4;
optional string agreement = 5;
optional bytes initialIP = 6;
optional int64 createdAt = 7; // Unix timestamp (nanoseconds)
optional string status = 8;
}
message Authorization {
optional string id = 1;
optional string identifier = 2;
optional int64 registrationID = 3;
optional string status = 4;
optional int64 expires = 5; // Unix timestamp (nanoseconds)
repeated core.Challenge challenges = 6;
optional bytes combinations = 7;
}
message Empty {}

View File

@ -1,16 +0,0 @@
package core
import "strings"
// ReverseName takes a domain name and returns a label-wise reversed version of
// it. Example:
// ReverseName("www.example.com") == "com.example.www"
// This is useful for storing domain names in a DB such than subdomains of the
// same parent domain are near each other.
func ReverseName(domain string) string {
labels := strings.Split(domain, ".")
for i, j := 0, len(labels)-1; i < j; i, j = i+1, j-1 {
labels[i], labels[j] = labels[j], labels[i]
}
return strings.Join(labels, ".")
}

View File

@ -84,7 +84,7 @@ func TestKeyDigest(t *testing.T) {
test.Assert(t, err == nil && digest == JWK1Digest, "Failed to digest bare key")
// Test with unknown key type
digest, err = KeyDigest(struct{}{})
_, err = KeyDigest(struct{}{})
test.Assert(t, err != nil, "Should have rejected unknown key type")
}

View File

@ -4,13 +4,13 @@ While Boulder attempts to implement the ACME specification as strictly as possib
This document details these differences, since ACME is not yet finalized it will be updated as numbered drafts are published.
Current draft: [`draft-ietf-acme-acme-03`](https://tools.ietf.org/html/draft-ietf-acme-acme-03).
Current draft: [`draft-ietf-acme-acme-04`](https://tools.ietf.org/html/draft-ietf-acme-acme-04).
## [Section 5.5.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-5.5)
## [Section 5.6.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-5.6)
Boulder does not provide a `Retry-After` header when a user hits a rate-limit, nor does it provide `Link` headers to further documentation on rate-limiting.
## [Section 5.6.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-5.6)
## [Section 5.7.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-5.7)
Boulder doesn't return errors under the `urn:ietf:params:acme:error:` namespace but instead uses the `urn:acme:error:` namespace from [draft-ietf-acme-01 Section 5.4](https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-5.4).
@ -18,47 +18,50 @@ Boulder uses `invalidEmail` in place of the error `invalidContact` defined in [d
Boulder does not implement the `caa` and `dnssec` errors.
## [Section 6.1.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.1)
## [Section 6.1.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.1)
Boulder does not implement the `new-application` resource. Instead of `new-application` Boulder implements the `new-cert` resource that is defined in [draft-ietf-acme-02 Section 6.5](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5).
Boulder does not implement the `new-application` resource. Instead of `new-application` Boulder implements the `new-cert` resource that is defined in [draft-ietf-acme-02 Section 6.5](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5). Boulder also doesn't implement the `new-nonce` endpoint.
## [Section 6.1.1.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.1.1)
## [Section 6.1.1.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.1.1)
Boulder does not implement the `meta` field returned by the `directory` endpoint.
## [Section 6.1.2.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.1.2)
## [Section 6.1.2.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.1.2)
Boulder does not implement the `status`, `applications`, or `certificates` fields
in the registration object (nor the endpoints the latter two link to).
Boulder does not implement the `terms-of-service-agreed` or `applications` fields in the registration object (nor the endpoints the latter links to).
## [Section 6.1.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.1.3)
## [Section 6.1.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.1.3)
Boulder does not implement applications, instead it implements the `new-cert` flow from [draft-ietf-acme-02 Section 6.5](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5). Instead of application requirements Boulder currently uses authorizations that are created using the `new-authz` flow from [draft-ietf-acme-02 Section 6.4](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.4).
## [Section 6.1.4.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.1.4)
## [Section 6.1.4.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.1.4)
Boulder does not implement the `scope` field in authorization objects.
## [Section 6.2.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.2)
## [Section 6.2.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.2)
Boulder does not allow `tel` URIs in the registrations `contact` list.
Boulder doesn't implement the `new-nonce` endpoint, instead it responds to `HEAD` requests with a valid `Replay-Nonce` header per [draft-ietf-acme-03 Section 5.4](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-5.4).
## [Section 6.2.1.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.2.1)
## [Section 6.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.3)
Boulder implements draft-03 style key roll-over with a few divergences. Since Boulder doesn't currently use the registration URL to identify users we do not check for that field in the JWS protected headers but do check for it in the inner payload. Boulder also requires the outer JWS payload contains the `"resource": "key-change"` field.
Boulder only allows `mailto` URIs in the registrations `contact` list.
## [Section 6.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3)
## [Section 6.3.2.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.3.2)
Boulder does not implement applications, instead it implements the `new-cert` flow from [draft-ietf-acme-02 Section 6.5](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5). Instead of application requirements Boulder currently uses authorizations that are created using the `new-authz` flow from [draft-ietf-acme-02 Section 6.4](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.4).
Boulder implements draft-04 style key roll-over with a few divergences. Since Boulder doesn't currently use the registration URL to identify users we do not check for that field in the JWS protected headers but do check for it in the inner payload. Boulder also requires the outer JWS payload contains the `"resource": "key-change"` field.
## [Section 7.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3)
## [Section 6.4.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-6.4)
Boulder does not implement applications, instead it implements the `new-cert` flow from [draft-ietf-acme-02 Section 6.5](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5). Instead of application requirements Boulder currently uses authorizations that are created using the `new-authz` flow from [draft-ietf-acme-02 Section 6.4](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.4). Certificates are not proactively issued, a user must request issuance via the `new-cert` endpoint instead of assuming a certificate will be created once all required authorizations are validated.
## [Section 7.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-7.3)
Boulder implements `tls-sni-01` from [draft-ietf-acme-01 Section 7.3](https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3) instead of the `tls-sni-02` validation method.
## [Section 7.5.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.5)
## [Section 7.5.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-7.5)
Boulder does not implement the `oob-01` validation method.
## [Section 8.5.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-8.5)
## [Section 8.5.](https://tools.ietf.org/html/draft-ietf-acme-acme-04#section-8.5)
Boulder uses the `urn:acme:` namespace from [draft-ietf-acme-01 Section 5.4](https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-5.4) for errors instead of `urn:ietf:params:acme:`.

View File

@ -81,7 +81,7 @@ func Enabled(n FeatureFlag) bool {
defer fMu.RUnlock()
v, present := features[n]
if !present {
panic(fmt.Sprintf("feature '%s' doesn't exist", n))
panic(fmt.Sprintf("feature '%s' doesn't exist", n.String()))
}
return v
}

View File

@ -4,36 +4,81 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/core"
)
// gRPC error codes used by Boulder. While the gRPC codes
// end at 16 we start at 100 to provide a little leeway
// in case they ever decide to add more
const (
// DNSQueryTimeout is used when DNS queries timeout
DNSQueryTimeout codes.Code = 100
// DNSError is used when DNS queries fail for some reason
DNSError codes.Code = 101
MalformedRequestError = iota + 100
NotSupportedError
UnauthorizedError
NotFoundError
LengthRequiredError
SignatureValidationError
RateLimitedError
BadNonceError
NoSuchRegistrationError
InternalServerError
)
// CodeToProblem takes a gRPC error code and translates it to
// a Boulder ProblemType
func CodeToProblem(c codes.Code) probs.ProblemType {
switch c {
case DNSQueryTimeout, DNSError:
return probs.ConnectionProblem
func errorToCode(err error) codes.Code {
switch err.(type) {
case core.MalformedRequestError:
return MalformedRequestError
case core.NotSupportedError:
return NotSupportedError
case core.UnauthorizedError:
return UnauthorizedError
case core.NotFoundError:
return NotFoundError
case core.LengthRequiredError:
return LengthRequiredError
case core.SignatureValidationError:
return SignatureValidationError
case core.RateLimitedError:
return RateLimitedError
case core.BadNonceError:
return BadNonceError
case core.NoSuchRegistrationError:
return NoSuchRegistrationError
case core.InternalServerError:
return InternalServerError
default:
return probs.ServerInternalProblem
return codes.Unknown
}
}
// ErrorToProb converts a error returned by a gRPC call to a
// probs.ProblemDetails
func ErrorToProb(err error) *probs.ProblemDetails {
return &probs.ProblemDetails{
Type: CodeToProblem(grpc.Code(err)),
Detail: grpc.ErrorDesc(err),
func wrapError(err error) error {
return grpc.Errorf(errorToCode(err), err.Error())
}
func unwrapError(err error) error {
code := grpc.Code(err)
errBody := grpc.ErrorDesc(err)
switch code {
case InternalServerError:
return core.InternalServerError(errBody)
case NotSupportedError:
return core.NotSupportedError(errBody)
case MalformedRequestError:
return core.MalformedRequestError(errBody)
case UnauthorizedError:
return core.UnauthorizedError(errBody)
case NotFoundError:
return core.NotFoundError(errBody)
case SignatureValidationError:
return core.SignatureValidationError(errBody)
case NoSuchRegistrationError:
return core.NoSuchRegistrationError(errBody)
case RateLimitedError:
return core.RateLimitedError(errBody)
case LengthRequiredError:
return core.LengthRequiredError(errBody)
case BadNonceError:
return core.BadNonceError(errBody)
default:
return err
}
}

View File

@ -3,18 +3,33 @@ package grpc
import (
"testing"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/test"
)
func TestErrorToProb(t *testing.T) {
prob := ErrorToProb(CodedError(codes.Aborted, "it's an error!"))
test.AssertEquals(t, prob.Detail, "it's an error!")
test.AssertEquals(t, prob.Type, probs.ServerInternalProblem)
prob = ErrorToProb(CodedError(DNSQueryTimeout, ""))
test.AssertEquals(t, prob.Type, probs.ConnectionProblem)
prob = ErrorToProb(CodedError(DNSError, ""))
test.AssertEquals(t, prob.Type, probs.ConnectionProblem)
func TestErrors(t *testing.T) {
testcases := []struct {
err error
expectedCode codes.Code
}{
{core.MalformedRequestError("test 1"), MalformedRequestError},
{core.NotSupportedError("test 2"), NotSupportedError},
{core.UnauthorizedError("test 3"), UnauthorizedError},
{core.NotFoundError("test 4"), NotFoundError},
{core.LengthRequiredError("test 5"), LengthRequiredError},
{core.SignatureValidationError("test 6"), SignatureValidationError},
{core.RateLimitedError("test 7"), RateLimitedError},
{core.BadNonceError("test 8"), BadNonceError},
{core.NoSuchRegistrationError("test 9"), NoSuchRegistrationError},
{core.InternalServerError("test 10"), InternalServerError},
}
for _, tc := range testcases {
wrappedErr := wrapError(tc.err)
test.AssertEquals(t, grpc.Code(wrappedErr), tc.expectedCode)
test.AssertEquals(t, tc.err, unwrapError(wrappedErr))
}
}

View File

@ -38,7 +38,7 @@ func ClientSetup(c *cmd.GRPCClientConfig, stats metrics.Scope) (*grpc.ClientConn
if err != nil {
return nil, err
}
ci := clientInterceptor{stats.NewScope("gRPCClient"), clock.Default()}
ci := clientInterceptor{stats.NewScope("gRPCClient"), clock.Default(), c.Timeout.Duration}
creds := bcreds.NewClientCredentials(rootCAs, []tls.Certificate{clientCert})
return grpc.Dial(
"", // Since our staticResolver provides addresses we don't need to pass an address here

View File

@ -11,6 +11,24 @@ import (
"google.golang.org/grpc/credentials"
)
var (
ClientHandshakeNopErr = errors.New(
"boulder/grpc/creds: Client-side handshakes are not implemented with " +
"serverTransportCredentials")
ServerHandshakeNopErr = errors.New(
"boulder/grpc/creds: Server-side handshakes are not implemented with " +
"clientTransportCredentials")
OverrideServerNameNopErr = errors.New(
"boulder/grpc/creds: OverrideServerName() is not implemented")
NilServerConfigErr = errors.New(
"boulder/grpc/creds: `serverConfig` must not be nil")
EmptyPeerCertsErr = errors.New(
"boulder/grpc/creds: validateClient given state with empty PeerCertificates")
SANNotAcceptedErr = errors.New(
"boulder/grpc/creds: peer's client certificate SAN entries did not match " +
"any entries on accepted SAN list.")
)
// clientTransportCredentials is a grpc/credentials.TransportCredentials which supports
// connecting to, and verifying multiple DNS names
type clientTransportCredentials struct {
@ -55,22 +73,6 @@ func (tc *clientTransportCredentials) ClientHandshake(ctx context.Context, addr
}
}
var (
ClientHandshakeNopErr = errors.New(
"boulder/grpc/creds: Client-side handshakes are not implemented with " +
"serverTransportCredentials")
ServerHandshakeNopErr = errors.New(
"boulder/grpc/creds: Server-side handshakes are not implemented with " +
"clientTransportCredentials")
NilServerConfigErr = errors.New(
"boulder/grpc/creds: `serverConfig` must not be nil")
EmptyPeerCertsErr = errors.New(
"boulder/grpc/creds: validateClient given state with empty PeerCertificates")
SANNotAcceptedErr = errors.New(
"boulder/grpc/creds: peer's client certificate SAN entries did not match " +
"any entries on accepted SAN list.")
)
// ServerHandshake is not implemented for a `clientTransportCredentials`, use
// a `serverTransportCredentials` if you require `ServerHandshake`.
func (tc *clientTransportCredentials) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
@ -95,6 +97,16 @@ func (tc *clientTransportCredentials) RequireTransportSecurity() bool {
return true
}
// Clone returns a copy of the clientTransportCredentials
func (tc *clientTransportCredentials) Clone() credentials.TransportCredentials {
return NewClientCredentials(tc.roots, tc.clients)
}
// OverrideServerName is not implemented and here only to satisfy the interface
func (tc *clientTransportCredentials) OverrideServerName(serverNameOverride string) error {
return OverrideServerNameNopErr
}
// serverTransportCredentials is a grpc/credentials.TransportCredentials which supports
// filtering acceptable peer connections by a list of accepted client certificate SANs
type serverTransportCredentials struct {
@ -129,7 +141,7 @@ func (tc *serverTransportCredentials) validateClient(peerState tls.ConnectionSta
* once we have deployed & updated all gRPC configurations to have an accepted
* SAN list configured
*/
if tc.acceptedSANs == nil {
if len(tc.acceptedSANs) == 0 {
return nil
}
@ -188,7 +200,7 @@ func (tc *serverTransportCredentials) ServerHandshake(rawConn net.Conn) (net.Con
return nil, nil, err
}
return conn, credentials.TLSInfo{conn.ConnectionState()}, nil
return conn, credentials.TLSInfo{State: conn.ConnectionState()}, nil
}
// ClientHandshake is not implemented for a `serverTransportCredentials`, use
@ -214,3 +226,14 @@ func (tc *serverTransportCredentials) GetRequestMetadata(ctx context.Context, ur
func (tc *serverTransportCredentials) RequireTransportSecurity() bool {
return true
}
// Clone returns a copy of the serverTransportCredentials
func (tc *serverTransportCredentials) Clone() credentials.TransportCredentials {
clone, _ := NewServerCredentials(tc.serverConfig, tc.acceptedSANs)
return clone
}
// OverrideServerName is not implemented and here only to satisfy the interface
func (tc *serverTransportCredentials) OverrideServerName(serverNameOverride string) error {
return OverrideServerNameNopErr
}

View File

@ -1,6 +1,7 @@
package creds
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
@ -12,15 +13,13 @@ import (
"testing"
"time"
"golang.org/x/net/context"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/test"
)
func TestServerTransportCredentials(t *testing.T) {
acceptedSANs := map[string]struct{}{
"boulder-client": struct{}{},
"boulder-client": {},
}
goodCert, err := core.LoadCert("../../test/grpc-creds/boulder-client/cert.pem")
test.AssertNotError(t, err, "core.LoadCert('../../grpc-creds/boulder-client/cert.pem') failed")
@ -32,11 +31,18 @@ func TestServerTransportCredentials(t *testing.T) {
_, err = NewServerCredentials(nil, acceptedSANs)
test.AssertEquals(t, err, NilServerConfigErr)
// A creds with a nil acceptedSANs list should consider any peer valid
bcreds := &serverTransportCredentials{servTLSConfig, nil}
// A creds with a empty acceptedSANs list should consider any peer valid
wrappedCreds, err := NewServerCredentials(servTLSConfig, nil)
test.AssertNotError(t, err, "NewServerCredentials failed with nil acceptedSANs")
bcreds := wrappedCreds.(*serverTransportCredentials)
emptyState := tls.ConnectionState{}
err = bcreds.validateClient(emptyState)
test.AssertNotError(t, err, "validateClient() errored for emptyState")
wrappedCreds, err = NewServerCredentials(servTLSConfig, map[string]struct{}{})
test.AssertNotError(t, err, "NewServerCredentials failed with empty acceptedSANs")
bcreds = wrappedCreds.(*serverTransportCredentials)
err = bcreds.validateClient(emptyState)
test.AssertNotError(t, err, "validateClient() errored for emptyState")
// A creds given an empty TLS ConnectionState to verify should return an error
bcreds = &serverTransportCredentials{servTLSConfig, acceptedSANs}
@ -63,7 +69,7 @@ func TestServerTransportCredentials(t *testing.T) {
// that has a leaf certificate containing an IP address SAN present in the
// accepted list.
acceptedIPSans := map[string]struct{}{
"127.0.0.1": struct{}{},
"127.0.0.1": {},
}
bcreds = &serverTransportCredentials{servTLSConfig, acceptedIPSans}
err = bcreds.validateClient(rightState)

View File

@ -3,6 +3,7 @@ package grpc
import (
"errors"
"strings"
"time"
"github.com/letsencrypt/boulder/metrics"
@ -47,18 +48,28 @@ func (si *serverInterceptor) intercept(ctx context.Context, req interface{}, inf
}
type clientInterceptor struct {
stats metrics.Scope
clk clock.Clock
stats metrics.Scope
clk clock.Clock
timeout time.Duration
}
// intercept fulfils the grpc.UnaryClientInterceptor interface, it should be noted that while this API
// is currently experimental the metrics it reports should be kept as stable as can be, *within reason*.
func (ci *clientInterceptor) intercept(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
func (ci *clientInterceptor) intercept(
ctx context.Context,
method string,
req,
reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption) error {
localCtx, cancel := context.WithTimeout(ctx, ci.timeout)
defer cancel()
s := ci.clk.Now()
methodScope := ci.stats.NewScope(cleanMethod(method, false))
methodScope.Inc("Calls", 1)
methodScope.GaugeDelta("InProgress", 1)
err := invoker(ctx, method, req, reply, cc, opts...)
err := invoker(localCtx, method, req, reply, cc, opts...)
methodScope.TimingDuration("Latency", ci.clk.Since(s))
methodScope.GaugeDelta("InProgress", -1)
if err != nil {

View File

@ -64,7 +64,7 @@ func TestClientInterceptor(t *testing.T) {
defer ctrl.Finish()
statter := metrics.NewMockStatter(ctrl)
stats := metrics.NewStatsdScope(statter, "fake", "gRPCClient")
ci := clientInterceptor{stats, fc}
ci := clientInterceptor{stats, fc, time.Second}
statter.EXPECT().Inc("fake.gRPCClient.service_test.Calls", int64(1), float32(1.0)).Return(nil)
statter.EXPECT().GaugeDelta("fake.gRPCClient.service_test.InProgress", int64(1), float32(1.0)).Return(nil)

View File

@ -6,7 +6,9 @@
package grpc
import (
"encoding/json"
"net"
"time"
"google.golang.org/grpc/codes"
"gopkg.in/square/go-jose.v1"
@ -14,6 +16,7 @@ import (
"github.com/letsencrypt/boulder/core"
corepb "github.com/letsencrypt/boulder/core/proto"
"github.com/letsencrypt/boulder/probs"
sapb "github.com/letsencrypt/boulder/sa/proto"
vapb "github.com/letsencrypt/boulder/va/proto"
)
@ -85,7 +88,7 @@ func pbToProblemDetails(in *corepb.ProblemDetails) (*probs.ProblemDetails, error
return prob, nil
}
func vaChallengeToPB(challenge core.Challenge) (*corepb.Challenge, error) {
func challengeToPB(challenge core.Challenge) (*corepb.Challenge, error) {
st := string(challenge.Status)
return &corepb.Challenge{
Id: &challenge.ID,
@ -96,7 +99,7 @@ func vaChallengeToPB(challenge core.Challenge) (*corepb.Challenge, error) {
}, nil
}
func pbToVAChallenge(in *corepb.Challenge) (challenge core.Challenge, err error) {
func pbToChallenge(in *corepb.Challenge) (challenge core.Challenge, err error) {
if in == nil {
return core.Challenge{}, ErrMissingParameters
}
@ -206,7 +209,7 @@ func performValidationReqToArgs(in *vapb.PerformValidationRequest) (domain strin
return
}
domain = *in.Domain
challenge, err = pbToVAChallenge(in.Challenge)
challenge, err = pbToChallenge(in.Challenge)
if err != nil {
return
}
@ -219,7 +222,7 @@ func performValidationReqToArgs(in *vapb.PerformValidationRequest) (domain strin
}
func argsToPerformValidationRequest(domain string, challenge core.Challenge, authz core.Authorization) (*vapb.PerformValidationRequest, error) {
pbChall, err := vaChallengeToPB(challenge)
pbChall, err := challengeToPB(challenge)
if err != nil {
return nil, err
}
@ -234,3 +237,191 @@ func argsToPerformValidationRequest(domain string, challenge core.Challenge, aut
}, nil
}
func registrationToPB(reg core.Registration) (*corepb.Registration, error) {
keyBytes, err := reg.Key.MarshalJSON()
if err != nil {
return nil, err
}
ipBytes, err := reg.InitialIP.MarshalText()
if err != nil {
return nil, err
}
createdAt := reg.CreatedAt.UnixNano()
status := string(reg.Status)
var contacts []string
// Since the default value of corepb.Registration.Contact is a slice
// we need a indicator as to if the value is actually important on
// the other side (pb -> reg).
contactsPresent := reg.Contact != nil
if reg.Contact != nil {
contacts = *reg.Contact
}
return &corepb.Registration{
Id: &reg.ID,
Key: keyBytes,
Contact: contacts,
ContactsPresent: &contactsPresent,
Agreement: &reg.Agreement,
InitialIP: ipBytes,
CreatedAt: &createdAt,
Status: &status,
}, nil
}
func pbToRegistration(pb *corepb.Registration) (core.Registration, error) {
var key jose.JsonWebKey
err := key.UnmarshalJSON(pb.Key)
if err != nil {
return core.Registration{}, err
}
var initialIP net.IP
err = initialIP.UnmarshalText(pb.InitialIP)
if err != nil {
return core.Registration{}, err
}
var contacts *[]string
if *pb.ContactsPresent {
if len(pb.Contact) != 0 {
contacts = &pb.Contact
} else {
// When gRPC creates an empty slice it is actually a nil slice. Since
// certain things boulder uses, like encoding/json, differentiate between
// these we need to de-nil these slices. Without this we are unable to
// properly do registration updates as contacts would always be removed
// as we use the difference between a nil and empty slice in ra.mergeUpdate.
empty := []string{}
contacts = &empty
}
}
return core.Registration{
ID: *pb.Id,
Key: &key,
Contact: contacts,
Agreement: *pb.Agreement,
InitialIP: initialIP,
CreatedAt: time.Unix(0, *pb.CreatedAt),
Status: core.AcmeStatus(*pb.Status),
}, nil
}
func authzToPB(authz core.Authorization) (*corepb.Authorization, error) {
challs := make([]*corepb.Challenge, len(authz.Challenges))
for i, c := range authz.Challenges {
pbChall, err := challengeToPB(c)
if err != nil {
return nil, err
}
challs[i] = pbChall
}
comboBytes, err := json.Marshal(authz.Combinations)
if err != nil {
return nil, err
}
status := string(authz.Status)
var expires int64
if authz.Expires != nil {
expires = authz.Expires.UnixNano()
}
return &corepb.Authorization{
Id: &authz.ID,
Identifier: &authz.Identifier.Value,
RegistrationID: &authz.RegistrationID,
Status: &status,
Expires: &expires,
Challenges: challs,
Combinations: comboBytes,
}, nil
}
func pbToAuthz(pb *corepb.Authorization) (core.Authorization, error) {
challs := make([]core.Challenge, len(pb.Challenges))
for i, c := range pb.Challenges {
chall, err := pbToChallenge(c)
if err != nil {
return core.Authorization{}, err
}
challs[i] = chall
}
var combos [][]int
err := json.Unmarshal(pb.Combinations, &combos)
if err != nil {
return core.Authorization{}, err
}
expires := time.Unix(0, *pb.Expires)
return core.Authorization{
ID: *pb.Id,
Identifier: core.AcmeIdentifier{Type: core.IdentifierDNS, Value: *pb.Identifier},
RegistrationID: *pb.RegistrationID,
Status: core.AcmeStatus(*pb.Status),
Expires: &expires,
Challenges: challs,
Combinations: combos,
}, nil
}
func registrationValid(reg *corepb.Registration) bool {
return !(reg.Id == nil || reg.Key == nil || reg.Agreement == nil || reg.InitialIP == nil || reg.CreatedAt == nil || reg.Status == nil || reg.ContactsPresent == nil)
}
func authorizationValid(authz *corepb.Authorization) bool {
return !(authz.Id == nil || authz.Identifier == nil || authz.RegistrationID == nil || authz.Status == nil || authz.Expires == nil)
}
func certificateValid(cert *corepb.Certificate) bool {
return !(cert.RegistrationID == nil || cert.Serial == nil || cert.Digest == nil || cert.Der == nil || cert.Issued == nil || cert.Expires == nil)
}
func sctToPB(sct core.SignedCertificateTimestamp) *sapb.SignedCertificateTimestamp {
id := int64(sct.ID)
version := int64(sct.SCTVersion)
timestamp := int64(sct.Timestamp)
return &sapb.SignedCertificateTimestamp{
Id: &id,
SctVersion: &version,
LogID: &sct.LogID,
Timestamp: &timestamp,
Extensions: sct.Extensions,
Signature: sct.Signature,
CertificateSerial: &sct.CertificateSerial,
}
}
func pbToSCT(pb *sapb.SignedCertificateTimestamp) core.SignedCertificateTimestamp {
return core.SignedCertificateTimestamp{
ID: int(*pb.Id),
SCTVersion: uint8(*pb.SctVersion),
LogID: *pb.LogID,
Timestamp: uint64(*pb.Timestamp),
Extensions: pb.Extensions,
Signature: pb.Signature,
CertificateSerial: *pb.CertificateSerial,
}
}
func sctValid(sct *sapb.SignedCertificateTimestamp) bool {
return !(sct.Id == nil || sct.SctVersion == nil || sct.LogID == nil || sct.Timestamp == nil || sct.Signature == nil || sct.CertificateSerial == nil)
}
func certToPB(cert core.Certificate) *corepb.Certificate {
issued, expires := cert.Issued.UnixNano(), cert.Expires.UnixNano()
return &corepb.Certificate{
RegistrationID: &cert.RegistrationID,
Serial: &cert.Serial,
Digest: &cert.Digest,
Der: cert.DER,
Issued: &issued,
Expires: &expires,
}
}
func pbToCert(pb *corepb.Certificate) core.Certificate {
return core.Certificate{
RegistrationID: *pb.RegistrationID,
Serial: *pb.Serial,
Digest: *pb.Digest,
DER: pb.Der,
Issued: time.Unix(0, *pb.Issued),
Expires: time.Unix(0, *pb.Expires),
}
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"net"
"testing"
"time"
"gopkg.in/square/go-jose.v1"
@ -93,7 +94,7 @@ func TestProblemDetails(t *testing.T) {
test.AssertEquals(t, err, ErrMissingParameters)
}
func TestVAChallenge(t *testing.T) {
func TestChallenge(t *testing.T) {
var jwk jose.JsonWebKey
err := json.Unmarshal([]byte(JWK1JSON), &jwk)
test.AssertNotError(t, err, "Failed to unmarshal test key")
@ -105,19 +106,19 @@ func TestVAChallenge(t *testing.T) {
ProvidedKeyAuthorization: "keyauth",
}
pb, err := vaChallengeToPB(chall)
test.AssertNotError(t, err, "vaChallengeToPB failed")
pb, err := challengeToPB(chall)
test.AssertNotError(t, err, "challengeToPB failed")
test.Assert(t, pb != nil, "Returned corepb.Challenge is nil")
recon, err := pbToVAChallenge(pb)
test.AssertNotError(t, err, "pbToVAChallenge failed")
recon, err := pbToChallenge(pb)
test.AssertNotError(t, err, "pbToChallenge failed")
test.AssertDeepEquals(t, recon, chall)
_, err = pbToVAChallenge(nil)
test.AssertError(t, err, "pbToVAChallenge did not fail")
_, err = pbToChallenge(nil)
test.AssertError(t, err, "pbToChallenge did not fail")
test.AssertEquals(t, err, ErrMissingParameters)
_, err = pbToVAChallenge(&corepb.Challenge{})
test.AssertError(t, err, "pbToVAChallenge did not fail")
_, err = pbToChallenge(&corepb.Challenge{})
test.AssertError(t, err, "pbToChallenge did not fail")
test.AssertEquals(t, err, ErrMissingParameters)
}
@ -196,3 +197,116 @@ func TestPerformValidationReq(t *testing.T) {
test.AssertDeepEquals(t, reconChall, chall)
test.AssertDeepEquals(t, reconAuthz, authz)
}
func TestRegistration(t *testing.T) {
contacts := []string{"email"}
var key jose.JsonWebKey
err := json.Unmarshal([]byte(`
{
"e": "AQAB",
"kty": "RSA",
"n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ"
}
`), &key)
test.AssertNotError(t, err, "Could not unmarshal testing key")
inReg := core.Registration{
ID: 1,
Key: &key,
Contact: &contacts,
Agreement: "yup",
InitialIP: net.ParseIP("1.1.1.1"),
CreatedAt: time.Now(),
Status: core.StatusValid,
}
pbReg, err := registrationToPB(inReg)
test.AssertNotError(t, err, "registrationToPB failed")
outReg, err := pbToRegistration(pbReg)
test.AssertNotError(t, err, "pbToRegistration failed")
test.AssertDeepEquals(t, inReg, outReg)
inReg.Contact = nil
pbReg, err = registrationToPB(inReg)
test.AssertNotError(t, err, "registrationToPB failed")
pbReg.Contact = []string{}
outReg, err = pbToRegistration(pbReg)
test.AssertNotError(t, err, "pbToRegistration failed")
test.AssertDeepEquals(t, inReg, outReg)
var empty []string
inReg.Contact = &empty
pbReg, err = registrationToPB(inReg)
test.AssertNotError(t, err, "registrationToPB failed")
outReg, err = pbToRegistration(pbReg)
test.AssertNotError(t, err, "pbToRegistration failed")
test.Assert(t, *outReg.Contact != nil, "Empty slice was converted to a nil slice")
}
func TestAuthz(t *testing.T) {
exp := time.Now().AddDate(0, 0, 1)
identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "example.com"}
combos := make([][]int, 1)
combos[0] = []int{0, 1}
challA := core.Challenge{
ID: 10,
Type: core.ChallengeTypeDNS01,
Status: core.StatusPending,
Token: "asd",
ProvidedKeyAuthorization: "keyauth",
}
challB := core.Challenge{
ID: 11,
Type: core.ChallengeTypeDNS01,
Status: core.StatusPending,
Token: "asd2",
ProvidedKeyAuthorization: "keyauth4",
}
inAuthz := core.Authorization{
ID: "1",
Identifier: identifier,
RegistrationID: 5,
Status: core.StatusPending,
Expires: &exp,
Challenges: []core.Challenge{challA, challB},
Combinations: combos,
}
pbAuthz, err := authzToPB(inAuthz)
test.AssertNotError(t, err, "authzToPB failed")
outAuthz, err := pbToAuthz(pbAuthz)
test.AssertNotError(t, err, "pbToAuthz failed")
test.AssertDeepEquals(t, inAuthz, outAuthz)
}
func TestSCT(t *testing.T) {
sct := core.SignedCertificateTimestamp{
ID: 10,
SCTVersion: 1,
LogID: "logid",
Timestamp: 100,
Extensions: []byte{255},
Signature: []byte{1},
CertificateSerial: "serial",
}
sctPB := sctToPB(sct)
outSCT := pbToSCT(sctPB)
test.AssertDeepEquals(t, sct, outSCT)
}
func TestCert(t *testing.T) {
now := time.Now()
cert := core.Certificate{
RegistrationID: 1,
Serial: "serial",
Digest: "digest",
DER: []byte{255},
Issued: now,
Expires: now.Add(time.Hour),
}
certPB := certToPB(cert)
outCert := pbToCert(certPB)
test.AssertDeepEquals(t, cert, outCert)
}

File diff suppressed because it is too large Load Diff

View File

@ -458,7 +458,7 @@ func GPDNSHandler(w http.ResponseWriter, r *http.Request) {
resp := core.GPDNSResponse{
Status: dns.RcodeSuccess,
Answer: []core.GPDNSAnswer{
{r.URL.Query().Get("name"), 257, 10, "0 issue \"ca.com\""},
{Name: r.URL.Query().Get("name"), Type: 257, TTL: 10, Data: "0 issue \"ca.com\""},
},
}
data, err := json.Marshal(resp)
@ -478,7 +478,7 @@ func GPDNSHandler(w http.ResponseWriter, r *http.Request) {
resp := core.GPDNSResponse{
Status: dns.RcodeSuccess,
Answer: []core.GPDNSAnswer{
{r.URL.Query().Get("name"), 257, 10, strconv.Itoa(mrand.Int())},
{Name: r.URL.Query().Get("name"), Type: 257, TTL: 10, Data: strconv.Itoa(mrand.Int())},
},
}
data, err := json.Marshal(resp)

View File

@ -137,6 +137,7 @@ var (
errIPAddress = probs.Malformed("Issuance for IP addresses not supported")
errTooManyLabels = probs.Malformed("DNS name has too many labels")
errEmptyName = probs.Malformed("DNS name was empty")
errNameEndsInDot = probs.Malformed("DNS name ends in a period")
errTooFewLabels = probs.Malformed("DNS name does not have enough labels")
errLabelTooShort = probs.Malformed("DNS label is too short")
errLabelTooLong = probs.Malformed("DNS label is too long")
@ -188,6 +189,10 @@ func (pa *AuthorityImpl) WillingToIssue(id core.AcmeIdentifier) error {
return errIPAddress
}
if strings.HasSuffix(domain, ".") {
return errNameEndsInDot
}
labels := strings.Split(domain, ".")
if len(labels) > maxLabels {
return errTooManyLabels

View File

@ -60,12 +60,16 @@ func TestWillingToIssue(t *testing.T) {
{`zombo*com`, errInvalidDNSCharacter},
{`*.com`, errInvalidDNSCharacter},
{`*.zombo.com`, errInvalidDNSCharacter},
{`.`, errLabelTooShort},
{`..`, errLabelTooShort},
{`a..`, errLabelTooShort},
{`..a`, errLabelTooShort},
{`.a.`, errLabelTooShort},
{`.....`, errLabelTooShort},
{`a..a`, errLabelTooShort},
{`.a..a`, errLabelTooShort},
{`..foo.com`, errLabelTooShort},
{`.`, errNameEndsInDot},
{`..`, errNameEndsInDot},
{`a..`, errNameEndsInDot},
{`.....`, errNameEndsInDot},
{`.a.`, errNameEndsInDot},
{`www.zombo.com.`, errNameEndsInDot},
{`www.zombo_com.com`, errInvalidDNSCharacter},
{`\uFEFF`, errInvalidDNSCharacter}, // Byte order mark
{`\uFEFFwww.zombo.com`, errInvalidDNSCharacter},

View File

@ -1,4 +1,4 @@
package prefixed_db
package prefixdb
import "database/sql/driver"

View File

@ -1,4 +1,4 @@
package prefixed_db
package prefixdb
import (
"database/sql"

3
ra/proto/generate.go Normal file
View File

@ -0,0 +1,3 @@
package proto
//go:generate sh -c "cd ../.. && protoc --go_out=plugins=grpc,Mcore/proto/core.proto=github.com/letsencrypt/boulder/core/proto:. ra/proto/ra.proto"

599
ra/proto/ra.pb.go Normal file
View File

@ -0,0 +1,599 @@
// Code generated by protoc-gen-go.
// source: ra/proto/ra.proto
// DO NOT EDIT!
/*
Package proto is a generated protocol buffer package.
It is generated from these files:
ra/proto/ra.proto
It has these top-level messages:
NewAuthorizationRequest
NewCertificateRequest
UpdateRegistrationRequest
UpdateAuthorizationRequest
RevokeCertificateWithRegRequest
AdministrativelyRevokeCertificateRequest
*/
package proto
import proto1 "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import core "github.com/letsencrypt/boulder/core/proto"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto1.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto1.ProtoPackageIsVersion2 // please upgrade the proto package
type NewAuthorizationRequest struct {
Authz *core.Authorization `protobuf:"bytes,1,opt,name=authz" json:"authz,omitempty"`
RegID *int64 `protobuf:"varint,2,opt,name=regID" json:"regID,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *NewAuthorizationRequest) Reset() { *m = NewAuthorizationRequest{} }
func (m *NewAuthorizationRequest) String() string { return proto1.CompactTextString(m) }
func (*NewAuthorizationRequest) ProtoMessage() {}
func (*NewAuthorizationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *NewAuthorizationRequest) GetAuthz() *core.Authorization {
if m != nil {
return m.Authz
}
return nil
}
func (m *NewAuthorizationRequest) GetRegID() int64 {
if m != nil && m.RegID != nil {
return *m.RegID
}
return 0
}
type NewCertificateRequest struct {
Csr []byte `protobuf:"bytes,1,opt,name=csr" json:"csr,omitempty"`
RegID *int64 `protobuf:"varint,2,opt,name=regID" json:"regID,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *NewCertificateRequest) Reset() { *m = NewCertificateRequest{} }
func (m *NewCertificateRequest) String() string { return proto1.CompactTextString(m) }
func (*NewCertificateRequest) ProtoMessage() {}
func (*NewCertificateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *NewCertificateRequest) GetCsr() []byte {
if m != nil {
return m.Csr
}
return nil
}
func (m *NewCertificateRequest) GetRegID() int64 {
if m != nil && m.RegID != nil {
return *m.RegID
}
return 0
}
type UpdateRegistrationRequest struct {
Base *core.Registration `protobuf:"bytes,1,opt,name=base" json:"base,omitempty"`
Update *core.Registration `protobuf:"bytes,2,opt,name=update" json:"update,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *UpdateRegistrationRequest) Reset() { *m = UpdateRegistrationRequest{} }
func (m *UpdateRegistrationRequest) String() string { return proto1.CompactTextString(m) }
func (*UpdateRegistrationRequest) ProtoMessage() {}
func (*UpdateRegistrationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *UpdateRegistrationRequest) GetBase() *core.Registration {
if m != nil {
return m.Base
}
return nil
}
func (m *UpdateRegistrationRequest) GetUpdate() *core.Registration {
if m != nil {
return m.Update
}
return nil
}
type UpdateAuthorizationRequest struct {
Authz *core.Authorization `protobuf:"bytes,1,opt,name=authz" json:"authz,omitempty"`
ChallengeIndex *int64 `protobuf:"varint,2,opt,name=challengeIndex" json:"challengeIndex,omitempty"`
Response *core.Challenge `protobuf:"bytes,3,opt,name=response" json:"response,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *UpdateAuthorizationRequest) Reset() { *m = UpdateAuthorizationRequest{} }
func (m *UpdateAuthorizationRequest) String() string { return proto1.CompactTextString(m) }
func (*UpdateAuthorizationRequest) ProtoMessage() {}
func (*UpdateAuthorizationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *UpdateAuthorizationRequest) GetAuthz() *core.Authorization {
if m != nil {
return m.Authz
}
return nil
}
func (m *UpdateAuthorizationRequest) GetChallengeIndex() int64 {
if m != nil && m.ChallengeIndex != nil {
return *m.ChallengeIndex
}
return 0
}
func (m *UpdateAuthorizationRequest) GetResponse() *core.Challenge {
if m != nil {
return m.Response
}
return nil
}
type RevokeCertificateWithRegRequest struct {
Cert []byte `protobuf:"bytes,1,opt,name=cert" json:"cert,omitempty"`
Code *int64 `protobuf:"varint,2,opt,name=code" json:"code,omitempty"`
RegID *int64 `protobuf:"varint,3,opt,name=regID" json:"regID,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *RevokeCertificateWithRegRequest) Reset() { *m = RevokeCertificateWithRegRequest{} }
func (m *RevokeCertificateWithRegRequest) String() string { return proto1.CompactTextString(m) }
func (*RevokeCertificateWithRegRequest) ProtoMessage() {}
func (*RevokeCertificateWithRegRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *RevokeCertificateWithRegRequest) GetCert() []byte {
if m != nil {
return m.Cert
}
return nil
}
func (m *RevokeCertificateWithRegRequest) GetCode() int64 {
if m != nil && m.Code != nil {
return *m.Code
}
return 0
}
func (m *RevokeCertificateWithRegRequest) GetRegID() int64 {
if m != nil && m.RegID != nil {
return *m.RegID
}
return 0
}
type AdministrativelyRevokeCertificateRequest struct {
Cert []byte `protobuf:"bytes,1,opt,name=cert" json:"cert,omitempty"`
Code *int64 `protobuf:"varint,2,opt,name=code" json:"code,omitempty"`
AdminName *string `protobuf:"bytes,3,opt,name=adminName" json:"adminName,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *AdministrativelyRevokeCertificateRequest) Reset() {
*m = AdministrativelyRevokeCertificateRequest{}
}
func (m *AdministrativelyRevokeCertificateRequest) String() string { return proto1.CompactTextString(m) }
func (*AdministrativelyRevokeCertificateRequest) ProtoMessage() {}
func (*AdministrativelyRevokeCertificateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor0, []int{5}
}
func (m *AdministrativelyRevokeCertificateRequest) GetCert() []byte {
if m != nil {
return m.Cert
}
return nil
}
func (m *AdministrativelyRevokeCertificateRequest) GetCode() int64 {
if m != nil && m.Code != nil {
return *m.Code
}
return 0
}
func (m *AdministrativelyRevokeCertificateRequest) GetAdminName() string {
if m != nil && m.AdminName != nil {
return *m.AdminName
}
return ""
}
func init() {
proto1.RegisterType((*NewAuthorizationRequest)(nil), "ra.NewAuthorizationRequest")
proto1.RegisterType((*NewCertificateRequest)(nil), "ra.NewCertificateRequest")
proto1.RegisterType((*UpdateRegistrationRequest)(nil), "ra.UpdateRegistrationRequest")
proto1.RegisterType((*UpdateAuthorizationRequest)(nil), "ra.UpdateAuthorizationRequest")
proto1.RegisterType((*RevokeCertificateWithRegRequest)(nil), "ra.RevokeCertificateWithRegRequest")
proto1.RegisterType((*AdministrativelyRevokeCertificateRequest)(nil), "ra.AdministrativelyRevokeCertificateRequest")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion3
// Client API for RegistrationAuthority service
type RegistrationAuthorityClient interface {
NewRegistration(ctx context.Context, in *core.Registration, opts ...grpc.CallOption) (*core.Registration, error)
NewAuthorization(ctx context.Context, in *NewAuthorizationRequest, opts ...grpc.CallOption) (*core.Authorization, error)
NewCertificate(ctx context.Context, in *NewCertificateRequest, opts ...grpc.CallOption) (*core.Certificate, error)
UpdateRegistration(ctx context.Context, in *UpdateRegistrationRequest, opts ...grpc.CallOption) (*core.Registration, error)
UpdateAuthorization(ctx context.Context, in *UpdateAuthorizationRequest, opts ...grpc.CallOption) (*core.Authorization, error)
RevokeCertificateWithReg(ctx context.Context, in *RevokeCertificateWithRegRequest, opts ...grpc.CallOption) (*core.Empty, error)
DeactivateRegistration(ctx context.Context, in *core.Registration, opts ...grpc.CallOption) (*core.Empty, error)
DeactivateAuthorization(ctx context.Context, in *core.Authorization, opts ...grpc.CallOption) (*core.Empty, error)
AdministrativelyRevokeCertificate(ctx context.Context, in *AdministrativelyRevokeCertificateRequest, opts ...grpc.CallOption) (*core.Empty, error)
}
type registrationAuthorityClient struct {
cc *grpc.ClientConn
}
func NewRegistrationAuthorityClient(cc *grpc.ClientConn) RegistrationAuthorityClient {
return &registrationAuthorityClient{cc}
}
func (c *registrationAuthorityClient) NewRegistration(ctx context.Context, in *core.Registration, opts ...grpc.CallOption) (*core.Registration, error) {
out := new(core.Registration)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/NewRegistration", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) NewAuthorization(ctx context.Context, in *NewAuthorizationRequest, opts ...grpc.CallOption) (*core.Authorization, error) {
out := new(core.Authorization)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/NewAuthorization", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) NewCertificate(ctx context.Context, in *NewCertificateRequest, opts ...grpc.CallOption) (*core.Certificate, error) {
out := new(core.Certificate)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/NewCertificate", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) UpdateRegistration(ctx context.Context, in *UpdateRegistrationRequest, opts ...grpc.CallOption) (*core.Registration, error) {
out := new(core.Registration)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/UpdateRegistration", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) UpdateAuthorization(ctx context.Context, in *UpdateAuthorizationRequest, opts ...grpc.CallOption) (*core.Authorization, error) {
out := new(core.Authorization)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/UpdateAuthorization", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) RevokeCertificateWithReg(ctx context.Context, in *RevokeCertificateWithRegRequest, opts ...grpc.CallOption) (*core.Empty, error) {
out := new(core.Empty)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/RevokeCertificateWithReg", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) DeactivateRegistration(ctx context.Context, in *core.Registration, opts ...grpc.CallOption) (*core.Empty, error) {
out := new(core.Empty)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/DeactivateRegistration", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) DeactivateAuthorization(ctx context.Context, in *core.Authorization, opts ...grpc.CallOption) (*core.Empty, error) {
out := new(core.Empty)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/DeactivateAuthorization", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *registrationAuthorityClient) AdministrativelyRevokeCertificate(ctx context.Context, in *AdministrativelyRevokeCertificateRequest, opts ...grpc.CallOption) (*core.Empty, error) {
out := new(core.Empty)
err := grpc.Invoke(ctx, "/ra.RegistrationAuthority/AdministrativelyRevokeCertificate", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for RegistrationAuthority service
type RegistrationAuthorityServer interface {
NewRegistration(context.Context, *core.Registration) (*core.Registration, error)
NewAuthorization(context.Context, *NewAuthorizationRequest) (*core.Authorization, error)
NewCertificate(context.Context, *NewCertificateRequest) (*core.Certificate, error)
UpdateRegistration(context.Context, *UpdateRegistrationRequest) (*core.Registration, error)
UpdateAuthorization(context.Context, *UpdateAuthorizationRequest) (*core.Authorization, error)
RevokeCertificateWithReg(context.Context, *RevokeCertificateWithRegRequest) (*core.Empty, error)
DeactivateRegistration(context.Context, *core.Registration) (*core.Empty, error)
DeactivateAuthorization(context.Context, *core.Authorization) (*core.Empty, error)
AdministrativelyRevokeCertificate(context.Context, *AdministrativelyRevokeCertificateRequest) (*core.Empty, error)
}
func RegisterRegistrationAuthorityServer(s *grpc.Server, srv RegistrationAuthorityServer) {
s.RegisterService(&_RegistrationAuthority_serviceDesc, srv)
}
func _RegistrationAuthority_NewRegistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(core.Registration)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).NewRegistration(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/NewRegistration",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).NewRegistration(ctx, req.(*core.Registration))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_NewAuthorization_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NewAuthorizationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).NewAuthorization(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/NewAuthorization",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).NewAuthorization(ctx, req.(*NewAuthorizationRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_NewCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NewCertificateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).NewCertificate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/NewCertificate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).NewCertificate(ctx, req.(*NewCertificateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_UpdateRegistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateRegistrationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).UpdateRegistration(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/UpdateRegistration",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).UpdateRegistration(ctx, req.(*UpdateRegistrationRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_UpdateAuthorization_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateAuthorizationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).UpdateAuthorization(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/UpdateAuthorization",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).UpdateAuthorization(ctx, req.(*UpdateAuthorizationRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_RevokeCertificateWithReg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RevokeCertificateWithRegRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).RevokeCertificateWithReg(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/RevokeCertificateWithReg",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).RevokeCertificateWithReg(ctx, req.(*RevokeCertificateWithRegRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_DeactivateRegistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(core.Registration)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).DeactivateRegistration(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/DeactivateRegistration",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).DeactivateRegistration(ctx, req.(*core.Registration))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_DeactivateAuthorization_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(core.Authorization)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).DeactivateAuthorization(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/DeactivateAuthorization",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).DeactivateAuthorization(ctx, req.(*core.Authorization))
}
return interceptor(ctx, in, info, handler)
}
func _RegistrationAuthority_AdministrativelyRevokeCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdministrativelyRevokeCertificateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RegistrationAuthorityServer).AdministrativelyRevokeCertificate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ra.RegistrationAuthority/AdministrativelyRevokeCertificate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RegistrationAuthorityServer).AdministrativelyRevokeCertificate(ctx, req.(*AdministrativelyRevokeCertificateRequest))
}
return interceptor(ctx, in, info, handler)
}
var _RegistrationAuthority_serviceDesc = grpc.ServiceDesc{
ServiceName: "ra.RegistrationAuthority",
HandlerType: (*RegistrationAuthorityServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "NewRegistration",
Handler: _RegistrationAuthority_NewRegistration_Handler,
},
{
MethodName: "NewAuthorization",
Handler: _RegistrationAuthority_NewAuthorization_Handler,
},
{
MethodName: "NewCertificate",
Handler: _RegistrationAuthority_NewCertificate_Handler,
},
{
MethodName: "UpdateRegistration",
Handler: _RegistrationAuthority_UpdateRegistration_Handler,
},
{
MethodName: "UpdateAuthorization",
Handler: _RegistrationAuthority_UpdateAuthorization_Handler,
},
{
MethodName: "RevokeCertificateWithReg",
Handler: _RegistrationAuthority_RevokeCertificateWithReg_Handler,
},
{
MethodName: "DeactivateRegistration",
Handler: _RegistrationAuthority_DeactivateRegistration_Handler,
},
{
MethodName: "DeactivateAuthorization",
Handler: _RegistrationAuthority_DeactivateAuthorization_Handler,
},
{
MethodName: "AdministrativelyRevokeCertificate",
Handler: _RegistrationAuthority_AdministrativelyRevokeCertificate_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: fileDescriptor0,
}
func init() { proto1.RegisterFile("ra/proto/ra.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 465 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
0x14, 0x4c, 0x9a, 0x06, 0xe8, 0x4b, 0x69, 0xc9, 0xab, 0xd2, 0xa6, 0x46, 0x40, 0xba, 0x5c, 0x72,
0x40, 0xa9, 0x54, 0x8e, 0x15, 0x12, 0xa5, 0x05, 0x29, 0x52, 0xe4, 0x43, 0x24, 0x84, 0xe0, 0xc4,
0xe2, 0x3c, 0xe2, 0x15, 0x89, 0xd7, 0xac, 0xd7, 0x09, 0x29, 0xdf, 0xc3, 0x7f, 0x22, 0xaf, 0x37,
0x24, 0x76, 0x6c, 0x35, 0xf4, 0xb6, 0xd6, 0xbe, 0x99, 0x9d, 0x99, 0x37, 0x32, 0x34, 0x15, 0x3f,
0x0f, 0x95, 0xd4, 0xf2, 0x5c, 0xf1, 0x9e, 0x39, 0xe0, 0x8e, 0xe2, 0x4e, 0xcb, 0x93, 0x8a, 0xec,
0x45, 0x72, 0x4c, 0xaf, 0xd8, 0x00, 0x4e, 0x5c, 0x9a, 0x5f, 0xc5, 0xda, 0x97, 0x4a, 0xdc, 0x72,
0x2d, 0x64, 0x30, 0xa4, 0x9f, 0x31, 0x45, 0x1a, 0x19, 0xd4, 0x79, 0xac, 0xfd, 0xdb, 0x76, 0xb5,
0x53, 0xed, 0x36, 0x2e, 0x8e, 0x7a, 0x06, 0x96, 0x19, 0xc5, 0xc7, 0x50, 0x57, 0x34, 0xee, 0xdf,
0xb4, 0x77, 0x3a, 0xd5, 0x6e, 0x8d, 0xbd, 0x86, 0x96, 0x4b, 0xf3, 0x6b, 0x52, 0x5a, 0x7c, 0x17,
0x1e, 0xd7, 0xb4, 0xe4, 0x6a, 0x40, 0xcd, 0x8b, 0x94, 0x61, 0xda, 0xcf, 0x83, 0x38, 0x9c, 0x7e,
0x0c, 0x47, 0x66, 0x78, 0x2c, 0x22, 0xad, 0x32, 0x22, 0x3a, 0xb0, 0xfb, 0x8d, 0x47, 0x64, 0x35,
0x60, 0xaa, 0x61, 0x7d, 0x10, 0x19, 0x3c, 0x88, 0x0d, 0xdc, 0xd0, 0x15, 0xce, 0xb0, 0xdf, 0xe0,
0xa4, 0x4f, 0xdc, 0xdb, 0xe8, 0x31, 0x1c, 0x78, 0x3e, 0x9f, 0x4c, 0x28, 0x18, 0x53, 0x3f, 0x18,
0xd1, 0xaf, 0x54, 0x3c, 0x9e, 0xc1, 0x23, 0x45, 0x51, 0x28, 0x83, 0x88, 0xda, 0x35, 0x03, 0x3f,
0x4c, 0xe1, 0xd7, 0xcb, 0x69, 0x36, 0x80, 0x17, 0x43, 0x9a, 0xc9, 0x1f, 0xb4, 0x96, 0xcb, 0x27,
0xa1, 0xfd, 0x21, 0x8d, 0x97, 0x0a, 0xf6, 0x61, 0xd7, 0x23, 0xa5, 0x6d, 0x3e, 0xc9, 0x97, 0x1c,
0x91, 0x7d, 0xe1, 0x5f, 0x5a, 0x35, 0x93, 0xd6, 0x67, 0xe8, 0x5e, 0x8d, 0xa6, 0x22, 0xb0, 0xe6,
0x66, 0x34, 0x59, 0x6c, 0xb0, 0x6f, 0x43, 0xdb, 0x84, 0x3d, 0x9e, 0xf0, 0xb8, 0x7c, 0x9a, 0x2a,
0xdf, 0xbb, 0xf8, 0x53, 0x87, 0xd6, 0x7a, 0x6c, 0x36, 0x01, 0xbd, 0xc0, 0x4b, 0x38, 0x74, 0x69,
0x9e, 0x89, 0xbd, 0x20, 0x66, 0xa7, 0x28, 0xfa, 0x0a, 0x7e, 0x80, 0x27, 0xf9, 0x8a, 0xe1, 0xd3,
0x9e, 0xe2, 0xbd, 0x92, 0xe2, 0x39, 0x45, 0x0b, 0x60, 0x15, 0x7c, 0x0b, 0x07, 0xd9, 0x72, 0xe1,
0xa9, 0x65, 0xd9, 0xb4, 0xee, 0x34, 0xed, 0x16, 0x56, 0x37, 0xac, 0x82, 0x7d, 0xc0, 0xcd, 0xa6,
0xe1, 0xb3, 0x84, 0xa5, 0xb4, 0x81, 0x25, 0xa6, 0x06, 0x70, 0x54, 0xd0, 0x28, 0x7c, 0xbe, 0xe2,
0xfa, 0x1f, 0x6b, 0x2e, 0xb4, 0xcb, 0x2a, 0x82, 0x2f, 0x13, 0xca, 0x3b, 0x0a, 0xe4, 0x34, 0x52,
0xde, 0xf7, 0xd3, 0x50, 0x2f, 0x58, 0x05, 0x2f, 0xe1, 0xf8, 0x86, 0xb8, 0xa7, 0xc5, 0x2c, 0x6f,
0xb6, 0x68, 0x6d, 0x39, 0xf0, 0x1b, 0x38, 0x59, 0x81, 0xb3, 0xf6, 0x8a, 0xe4, 0xe7, 0xe1, 0x5f,
0xe1, 0xec, 0xce, 0x82, 0xe2, 0xab, 0xc4, 0xd4, 0xb6, 0x3d, 0xce, 0xbd, 0xf0, 0xee, 0xe1, 0x97,
0xba, 0xf9, 0x79, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x14, 0xc6, 0x23, 0xeb, 0x04, 0x00,
0x00,
}

51
ra/proto/ra.proto Normal file
View File

@ -0,0 +1,51 @@
syntax = "proto2";
package ra;
option go_package = "proto";
import "core/proto/core.proto";
service RegistrationAuthority {
rpc NewRegistration(core.Registration) returns (core.Registration) {}
rpc NewAuthorization(NewAuthorizationRequest) returns (core.Authorization) {}
rpc NewCertificate(NewCertificateRequest) returns (core.Certificate) {}
rpc UpdateRegistration(UpdateRegistrationRequest) returns (core.Registration) {}
rpc UpdateAuthorization(UpdateAuthorizationRequest) returns (core.Authorization) {}
rpc RevokeCertificateWithReg(RevokeCertificateWithRegRequest) returns (core.Empty) {}
rpc DeactivateRegistration(core.Registration) returns (core.Empty) {}
rpc DeactivateAuthorization(core.Authorization) returns (core.Empty) {}
rpc AdministrativelyRevokeCertificate(AdministrativelyRevokeCertificateRequest) returns (core.Empty) {}
}
message NewAuthorizationRequest {
optional core.Authorization authz = 1;
optional int64 regID = 2;
}
message NewCertificateRequest {
optional bytes csr = 1;
optional int64 regID = 2;
}
message UpdateRegistrationRequest {
optional core.Registration base = 1;
optional core.Registration update = 2;
}
message UpdateAuthorizationRequest {
optional core.Authorization authz = 1;
optional int64 challengeIndex = 2;
optional core.Challenge response = 3;
}
message RevokeCertificateWithRegRequest {
optional bytes cert = 1;
optional int64 code = 2;
optional int64 regID = 3;
}
message AdministrativelyRevokeCertificateRequest {
optional bytes cert = 1;
optional int64 code = 2;
optional string adminName = 3;
}

View File

@ -1345,7 +1345,7 @@ func TestDeactivateAuthorization(t *testing.T) {
err = ra.DeactivateAuthorization(ctx, authz)
test.AssertNotError(t, err, "Could not deactivate authorization")
deact, err := sa.GetAuthorization(ctx, authz.ID)
test.AssertNotError(t, err, "Could not get deactivated authorization wtih ID "+authz.ID)
test.AssertNotError(t, err, "Could not get deactivated authorization with ID "+authz.ID)
test.AssertEquals(t, deact.Status, core.StatusDeactivated)
}

View File

@ -38,9 +38,9 @@ var ReasonToString = map[Reason]string{
// UserAllowedReasons contains the subset of Reasons which users are
// allowed to use
var UserAllowedReasons = map[Reason]struct{}{
Unspecified: struct{}{}, // unspecified
KeyCompromise: struct{}{}, // keyCompromise
AffiliationChanged: struct{}{}, // affiliationChanged
Superseded: struct{}{}, // superseded
CessationOfOperation: struct{}{}, // cessationOfOperation
Unspecified: {}, // unspecified
KeyCompromise: {}, // keyCompromise
AffiliationChanged: {}, // affiliationChanged
Superseded: {}, // superseded
CessationOfOperation: {}, // cessationOfOperation
}

View File

@ -437,7 +437,7 @@ func (rpc *AmqpRPCServer) Start(c *cmd.AMQPConfig) error {
rpc.mu.RUnlock()
rpc.log.Info(" [!] Got channel close, but no signal to shut down. Continuing.")
}
case err = <-rpc.connection.closeChannel():
case <-rpc.connection.closeChannel():
rpc.log.Info(fmt.Sprintf(" [!] Server channel closed: %s", rpc.serverQueue))
rpc.connection.reconnect(c, rpc.log)
}

View File

@ -2,8 +2,7 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `registrations` ADD COLUMN (`status` varchar(255) DEFAULT NULL);
UPDATE `registrations` SET `status` = 'valid';
ALTER TABLE `registrations` ADD COLUMN (`status` varchar(255) DEFAULT "valid" NOT NULL);
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

View File

@ -0,0 +1,17 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `challenges` DROP COLUMN `accountKey`;
ALTER TABLE `challenges` DROP COLUMN `tls`;
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back
ALTER TABLE `challenges` ADD COLUMN (
`accountKey` mediumBlob
);
ALTER TABLE `challenges` ADD COLUMN (
`tls` tinyint(1) DEFAULT NULL
);

View File

@ -17,7 +17,7 @@ import (
"github.com/letsencrypt/boulder/features"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/prefixed_db"
"github.com/letsencrypt/boulder/prefixdb"
)
// NewDbMap creates the root gorp mapping object. Create one of these for each
@ -88,7 +88,7 @@ func NewDbMapFromConfig(config *mysql.Config, maxOpenConns int) (*gorp.DbMap, er
return nil, err
}
driverName := fmt.Sprintf("mysql-%d", driverNum)
sql.Register(driverName, prefixed_db.New(prefix, mysql.MySQLDriver{}))
sql.Register(driverName, prefixdb.New(prefix, mysql.MySQLDriver{}))
db, err := sqlOpen(driverName, config.FormatDSN())
if err != nil {

3
sa/proto/generate.go Normal file
View File

@ -0,0 +1,3 @@
package proto
//go:generate sh -c "cd ../.. && protoc --go_out=plugins=grpc,Mcore/proto/core.proto=github.com/letsencrypt/boulder/core/proto:. sa/proto/sa.proto"

1629
sa/proto/sa.pb.go Normal file

File diff suppressed because it is too large Load Diff

156
sa/proto/sa.proto Normal file
View File

@ -0,0 +1,156 @@
syntax = "proto2";
package sa;
option go_package = "proto";
import "core/proto/core.proto";
service StorageAuthority {
// Getters
rpc GetRegistration(RegistrationID) returns (core.Registration) {}
rpc GetRegistrationByKey(JsonWebKey) returns (core.Registration) {}
rpc GetAuthorization(AuthorizationID) returns (core.Authorization) {}
rpc GetValidAuthorizations(GetValidAuthorizationsRequest) returns (ValidAuthorizations) {}
rpc GetCertificate(Serial) returns (core.Certificate) {}
rpc GetCertificateStatus(Serial) returns (CertificateStatus) {}
rpc CountCertificatesRange(Range) returns (Count) {}
rpc CountCertificatesByNames(CountCertificatesByNamesRequest) returns (CountByNames) {}
rpc CountRegistrationsByIP(CountRegistrationsByIPRequest) returns (Count) {}
rpc CountPendingAuthorizations(RegistrationID) returns (Count) {}
rpc GetSCTReceipt(GetSCTReceiptRequest) returns (SignedCertificateTimestamp) {}
rpc CountFQDNSets(CountFQDNSetsRequest) returns (Count) {}
rpc FQDNSetExists(FQDNSetExistsRequest) returns (Exists) {}
// Adders
rpc NewRegistration(core.Registration) returns (core.Registration) {}
rpc UpdateRegistration(core.Registration) returns (core.Empty) {}
rpc NewPendingAuthorization(core.Authorization) returns (core.Authorization) {}
rpc UpdatePendingAuthorization(core.Authorization) returns (core.Empty) {}
rpc FinalizeAuthorization(core.Authorization) returns (core.Empty) {}
rpc MarkCertificateRevoked(MarkCertificateRevokedRequest) returns (core.Empty) {}
rpc AddCertificate(AddCertificateRequest) returns (AddCertificateResponse) {}
rpc AddSCTReceipt(SignedCertificateTimestamp) returns (core.Empty) {}
rpc RevokeAuthorizationsByDomain(RevokeAuthorizationsByDomainRequest) returns (RevokeAuthorizationsByDomainResponse) {}
rpc DeactivateRegistration(RegistrationID) returns (core.Empty) {}
rpc DeactivateAuthorization(AuthorizationID) returns (core.Empty) {}
}
message RegistrationID {
optional int64 id = 1;
}
message JsonWebKey {
optional bytes jwk = 1;
}
message AuthorizationID {
optional string id = 1;
}
message GetValidAuthorizationsRequest {
optional int64 registrationID = 1;
repeated string domains = 2;
optional int64 now = 3; // Unix timestamp (nanoseconds)
}
message ValidAuthorizations {
message MapElement {
optional string domain = 1;
optional core.Authorization authz = 2;
}
repeated MapElement valid = 1;
}
message CertificateStatus {
optional string serial = 1;
optional bool subscriberApproved = 2;
optional string status = 3;
optional int64 ocspLastUpdated = 4;
optional int64 revokedDate = 5;
optional int64 revokedReason = 6;
optional int64 lastExpirationNagSent = 7;
optional bytes ocspResponse = 8;
optional int64 notAfter = 9;
optional bool isExpired = 10;
}
message Serial {
optional string serial = 1;
}
message Range {
optional int64 earliest = 1; // Unix timestamp (nanoseconds)
optional int64 latest = 2; // Unix timestamp (nanoseconds)
}
message Count {
optional int64 count = 1;
}
message CountCertificatesByNamesRequest {
optional Range range = 1;
repeated string names = 2;
}
message CountByNames {
message MapElement {
optional string name = 1;
optional int64 count = 2;
}
repeated MapElement countByNames = 1;
}
message CountRegistrationsByIPRequest {
optional bytes ip = 1;
optional Range range = 2;
}
message GetSCTReceiptRequest {
optional string serial = 1;
optional string logID = 2;
}
message CountFQDNSetsRequest {
optional int64 window = 1;
repeated string domains = 2;
}
message FQDNSetExistsRequest {
repeated string domains = 1;
}
message Exists {
optional bool exists = 1;
}
message MarkCertificateRevokedRequest {
optional string serial = 1;
optional int64 code = 2;
}
message AddCertificateRequest {
optional bytes der = 1;
optional int64 regID = 2;
}
message AddCertificateResponse {
optional string digest = 1;
}
message SignedCertificateTimestamp {
optional int64 id = 1;
optional int64 sctVersion = 2;
optional string logID = 3;
optional int64 timestamp = 4;
optional bytes extensions = 5;
optional bytes signature = 6;
optional string certificateSerial = 7;
}
message RevokeAuthorizationsByDomainRequest {
optional string domain = 1;
}
message RevokeAuthorizationsByDomainResponse {
optional int64 finalized = 1;
optional int64 pending = 2;
}

View File

@ -362,6 +362,14 @@ func (ssa *SQLStorageAuthority) CountCertificatesByNames(ctx context.Context, do
return ret, nil
}
func reverseName(domain string) string {
labels := strings.Split(domain, ".")
for i, j := 0, len(labels)-1; i < j; i, j = i+1, j-1 {
labels[i], labels[j] = labels[j], labels[i]
}
return strings.Join(labels, ".")
}
// countCertificatesByNames returns, for a single domain, the count of
// certificates issued in the given time range for that domain and its
// subdomains.
@ -382,7 +390,7 @@ func (ssa *SQLStorageAuthority) countCertificatesByName(domain string, earliest,
AND notBefore > :earliest AND notBefore <= :latest
LIMIT :limit;`,
map[string]interface{}{
"reversedDomain": core.ReverseName(domain),
"reversedDomain": reverseName(domain),
"earliest": earliest,
"latest": latest,
"limit": max + 1,
@ -653,7 +661,7 @@ func (ssa *SQLStorageAuthority) NewPendingAuthorization(ctx context.Context, aut
err = tx.Commit()
output = pendingAuthz.Authorization
output.Challenges = authz.Challenges
return output, nil
return output, err
}
// UpdatePendingAuthorization updates a Pending Authorization
@ -780,7 +788,7 @@ func (ssa *SQLStorageAuthority) RevokeAuthorizationsByDomain(ctx context.Context
}
// AddCertificate stores an issued certificate and returns the digest as
// a string, or an error if any occured.
// a string, or an error if any occurred.
func (ssa *SQLStorageAuthority) AddCertificate(ctx context.Context, certDER []byte, regID int64) (string, error) {
parsedCertificate, err := x509.ParseCertificate(certDER)
if err != nil {
@ -950,7 +958,7 @@ func addIssuedNames(tx execable, cert *x509.Certificate) error {
var values []interface{}
for _, name := range cert.DNSNames {
values = append(values,
core.ReverseName(name),
reverseName(name),
core.SerialToString(cert.SerialNumber),
cert.NotBefore)
qmarks = append(qmarks, "(?, ?, ?)")

View File

@ -860,3 +860,22 @@ func TestDeactivateAccount(t *testing.T) {
test.AssertNotError(t, err, "GetRegistration failed")
test.AssertEquals(t, dbReg.Status, core.StatusDeactivated)
}
func TestReverseName(t *testing.T) {
testCases := []struct {
inputDomain string
inputReversed string
}{
{"", ""},
{"...", "..."},
{"com", "com"},
{"example.com", "com.example"},
{"www.example.com", "com.example.www"},
{"world.wide.web.example.com", "com.example.web.wide.world"},
}
for _, tc := range testCases {
output := reverseName(tc.inputDomain)
test.AssertEquals(t, output, tc.inputReversed)
}
}

View File

@ -34,6 +34,7 @@ func TestAcmeIdentifier(t *testing.T) {
marshaled := marshaledI.(string)
err = scanner.Binder(&marshaled, &out)
test.AssertNotError(t, err, "failed to scanner.Binder")
test.AssertMarshaledEquals(t, ai, out)
}
@ -58,6 +59,7 @@ func TestJsonWebKey(t *testing.T) {
marshaled := marshaledI.(string)
err = scanner.Binder(&marshaled, &out)
test.AssertNotError(t, err, "failed to scanner.Binder")
test.AssertMarshaledEquals(t, jwk, out)
}
@ -79,6 +81,7 @@ func TestAcmeStatus(t *testing.T) {
marshaled := marshaledI.(string)
err = scanner.Binder(&marshaled, &out)
test.AssertNotError(t, err, "failed to scanner.Binder")
test.AssertMarshaledEquals(t, as, out)
}
@ -100,6 +103,7 @@ func TestOCSPStatus(t *testing.T) {
marshaled := marshaledI.(string)
err = scanner.Binder(&marshaled, &out)
test.AssertNotError(t, err, "failed to scanner.Binder")
test.AssertMarshaledEquals(t, os, out)
}
@ -119,5 +123,6 @@ func TestStringSlice(t *testing.T) {
marshaled := marshaledI.(string)
err = scanner.Binder(&marshaled, &out)
test.AssertNotError(t, err, "failed to scanner.Binder")
test.AssertMarshaledEquals(t, au, out)
}

View File

@ -2,17 +2,19 @@
"revoker": {
"dbConnectFile": "test/secrets/revoker_dburl",
"maxDBConns": 1,
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"RA": {
"server": "RA.server",
"rpcTimeout": "15s"
},
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
}
"raService": {
"serverAddresses": ["boulder:9094"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
}
},
@ -25,4 +27,4 @@
"stdoutlevel": 6,
"sysloglevel": 4
}
}
}

View File

@ -4,6 +4,13 @@
"rsaProfile": "rsaEE",
"ecdsaProfile": "ecdsaEE",
"debugAddr": "localhost:8001",
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"grpc": {
"address": "boulder:9093",
"clientIssuerPath": "test/grpc-creds/minica.pem",
@ -119,11 +126,7 @@
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"serviceQueue": "CA.server",
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
}
"serviceQueue": "CA.server"
},
"features": {
"IDNASupport": true

View File

@ -4,7 +4,8 @@
"maxDBConns": 10,
"features": {
"IDNASupport": true
}
},
"hostnamePolicyFile": "test/hostname-policy.json"
},
"pa": {

View File

@ -12,13 +12,12 @@
"nagCheckInterval": "24h",
"emailTemplate": "test/example-expiration-template",
"debugAddr": "localhost:8008",
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
}
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
}
},
@ -31,4 +30,4 @@
"stdoutlevel": 6,
"sysloglevel": 4
}
}
}

View File

@ -22,17 +22,19 @@
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "10s"
},
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
},
"CA": {
"server": "CA.server",
"rpcTimeout": "15s"
}
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"caService": {
"serverAddresses": ["boulder:9093"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
}
},

View File

@ -8,12 +8,11 @@
"prefix": "Boulder"
},
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
}
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
}
}

View File

@ -12,14 +12,17 @@
"boulder-client"
]
},
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"serviceQueue": "Publisher.server",
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
}
"serviceQueue": "Publisher.server"
}
},

View File

@ -16,38 +16,42 @@
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "90s"
"timeout": "15s"
},
"caService": {
"serverAddresses": ["boulder:9093"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "90s"
"timeout": "15s"
},
"publisherService": {
"serverAddresses": ["boulder:9091"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "10s"
"timeout": "15s"
},
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"grpc": {
"address": "boulder:9094",
"clientIssuerPath": "test/grpc-creds/minica.pem",
"serverCertificatePath": "test/grpc-creds/boulder-server/cert.pem",
"serverKeyPath": "test/grpc-creds/boulder-server/key.pem",
"clientNames": [
"boulder-client"
]
},
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,
"serviceQueue": "RA.server",
"VA": {
"server": "VA.server",
"rpcTimeout": "60s"
},
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
},
"CA": {
"server": "CA.server",
"rpcTimeout": "15s"
}
"serviceQueue": "RA.server"
},
"features": {
"IDNASupport": true,

View File

@ -4,6 +4,15 @@
"maxDBConns": 10,
"maxConcurrentRPCServerRequests": 16,
"debugAddr": "localhost:8003",
"grpc": {
"address": "boulder:9095",
"clientIssuerPath": "test/grpc-creds/minica.pem",
"serverCertificatePath": "test/grpc-creds/boulder-server/cert.pem",
"serverKeyPath": "test/grpc-creds/boulder-server/key.pem",
"clientNames": [
"boulder-client"
]
},
"amqp": {
"serverURLFile": "test/secrets/amqp_url",
"insecure": true,

View File

@ -10,21 +10,22 @@
"shutdownStopTimeout": "10s",
"shutdownKillTimeout": "1m",
"subscriberAgreementURL": "http://boulder:4000/terms/v1",
"checkMalformedCSR": true,
"acceptRevocationReason": true,
"allowAuthzDeactivation": true,
"debugAddr": "localhost:8000",
"amqp": {
"server": "amqp://guest:guest@localhost:5673",
"insecure": true,
"RA": {
"server": "RA.server",
"rpcTimeout": "15s"
},
"SA": {
"server": "SA.server",
"rpcTimeout": "15s"
}
"raService": {
"serverAddresses": ["boulder:9094"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"saService": {
"serverAddresses": ["boulder:9095"],
"serverIssuerPath": "test/grpc-creds/minica.pem",
"clientCertificatePath": "test/grpc-creds/boulder-client/cert.pem",
"clientKeyPath": "test/grpc-creds/boulder-client/key.pem",
"timeout": "15s"
},
"features": {
"AllowAccountDeactivation": true,

View File

@ -1,7 +1,8 @@
{
"certChecker": {
"dbConnectFile": "test/secrets/cert_checker_dburl",
"maxDBConns": 10
"maxDBConns": 10,
"hostnamePolicyFile": "test/hostname-policy.json"
},
"pa": {

View File

@ -1,4 +1,8 @@
{
"ExactBlacklist": [
"highrisk.le-test.hoffman-andrews.com",
"exactblacklist.letsencrypt.org"
],
"Blacklist": [
"in-addr.arpa",
"example",

View File

@ -23,7 +23,7 @@ func reqAndRecorder(t testing.TB, method, relativeUrl string, body io.Reader) (*
func TestHTTPClear(t *testing.T) {
srv := mailSrv{}
w, r := reqAndRecorder(t, "POST", "/clear", nil)
srv.allReceivedMail = []rcvdMail{rcvdMail{}}
srv.allReceivedMail = []rcvdMail{{}}
srv.httpClear(w, r)
if w.Code != 200 {
t.Errorf("expected 200, got %d", w.Code)
@ -33,7 +33,7 @@ func TestHTTPClear(t *testing.T) {
}
w, r = reqAndRecorder(t, "GET", "/clear", nil)
srv.allReceivedMail = []rcvdMail{rcvdMail{}}
srv.allReceivedMail = []rcvdMail{{}}
srv.httpClear(w, r)
if w.Code != 405 {
t.Errorf("expected 405, got %d", w.Code)
@ -46,11 +46,11 @@ func TestHTTPClear(t *testing.T) {
func TestHTTPCount(t *testing.T) {
srv := mailSrv{}
srv.allReceivedMail = []rcvdMail{
rcvdMail{From: "a", To: "b"},
rcvdMail{From: "a", To: "b"},
rcvdMail{From: "a", To: "c"},
rcvdMail{From: "c", To: "a"},
rcvdMail{From: "c", To: "b"},
{From: "a", To: "b"},
{From: "a", To: "b"},
{From: "a", To: "c"},
{From: "c", To: "a"},
{From: "c", To: "b"},
}
tests := []struct {

View File

@ -87,6 +87,7 @@ func NewValidationAuthorityImpl(
type verificationRequestEvent struct {
ID string `json:",omitempty"`
Requester int64 `json:",omitempty"`
Hostname string `json:",omitempty"`
ValidationRecords []core.ValidationRecord `json:",omitempty"`
Challenge core.Challenge `json:",omitempty"`
RequestTime time.Time `json:",omitempty"`
@ -529,6 +530,7 @@ func (va *ValidationAuthorityImpl) PerformValidation(ctx context.Context, domain
logEvent := verificationRequestEvent{
ID: authz.ID,
Requester: authz.RegistrationID,
Hostname: authz.Identifier.Value,
RequestTime: va.clk.Now(),
}
vStart := va.clk.Now()
@ -563,9 +565,9 @@ func (va *ValidationAuthorityImpl) PerformValidation(ctx context.Context, domain
// interface value. See, e.g.
// https://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here
return records, nil
} else {
return records, prob
}
return records, prob
}
// CAASet consists of filtered CAA records

View File

@ -897,12 +897,12 @@ func TestParseResults(t *testing.T) {
test.Assert(t, s == nil, "set is not nil")
test.Assert(t, err == nil, "error is not nil")
test.AssertNotError(t, err, "no error should be returned")
r = []caaResult{{nil, errors.New("")}, {[]*dns.CAA{&dns.CAA{Value: "test"}}, nil}}
r = []caaResult{{nil, errors.New("")}, {[]*dns.CAA{{Value: "test"}}, nil}}
s, err = parseResults(r)
test.Assert(t, s == nil, "set is not nil")
test.AssertEquals(t, err.Error(), "")
expected := dns.CAA{Value: "other-test"}
r = []caaResult{{[]*dns.CAA{&expected}, nil}, {[]*dns.CAA{&dns.CAA{Value: "test"}}, nil}}
r = []caaResult{{[]*dns.CAA{&expected}, nil}, {[]*dns.CAA{{Value: "test"}}, nil}}
s, err = parseResults(r)
test.AssertEquals(t, len(s.Unknown), 1)
test.Assert(t, s.Unknown[0] == &expected, "Incorrect record returned")

12
vendor/github.com/letsencrypt/pkcs11key/README.md generated vendored Normal file
View File

@ -0,0 +1,12 @@
PKCS11Key
========
The pkcs11key package implements a crypto.Signer interface for a PKCS#11 private key.
[![Build Status](https://travis-ci.org/letsencrypt/pkcs11key.svg)](https://travis-ci.org/letsencrypt/pkcs11key)
## License summary
Some of this code is Copyright (c) 2014 CloudFlare Inc., some is Copyright (c)
2015 Internet Security Research Group.
The code is licensed under the BSD 2-clause license. See the LICENSE file for more details.

View File

@ -133,7 +133,7 @@ func initialize(modulePath string) (ctx, error) {
newModule := pkcs11.New(modulePath)
if newModule == nil {
return nil, fmt.Errorf("unable to load PKCS#11 module")
return nil, fmt.Errorf("unable to load PKCS#11 module from %q", modulePath)
}
err := newModule.Initialize()

18
vendor/github.com/prometheus/client_golang/AUTHORS.md generated vendored Normal file
View File

@ -0,0 +1,18 @@
The Prometheus project was started by Matt T. Proud (emeritus) and
Julius Volz in 2012.
Maintainers of this repository:
* Björn Rabenstein <beorn@soundcloud.com>
The following individuals have contributed code to this repository
(listed in alphabetical order):
* Bernerd Schaefer <bj.schaefer@gmail.com>
* Björn Rabenstein <beorn@soundcloud.com>
* Daniel Bornkessel <daniel@soundcloud.com>
* Jeff Younker <jeff@drinktomi.com>
* Julius Volz <julius.volz@gmail.com>
* Matt T. Proud <matt.proud@gmail.com>
* Tobias Schmidt <ts@soundcloud.com>

View File

@ -30,6 +30,15 @@ type Counter interface {
Metric
Collector
// Set is used to set the Counter to an arbitrary value. It is only used
// if you have to transfer a value from an external counter into this
// Prometheus metric. Do not use it for regular handling of a
// Prometheus counter (as it can be used to break the contract of
// monotonically increasing values).
//
// Deprecated: Use NewConstMetric to create a counter for an external
// value. A Counter should never be set.
Set(float64)
// Inc increments the counter by 1.
Inc()
// Add adds the given value to the counter. It panics if the value is <

View File

@ -78,7 +78,7 @@ type Desc struct {
// Help string. Each Desc with the same fqName must have the same
// dimHash.
dimHash uint64
// err is an error that occurred during construction. It is reported on
// err is an error that occured during construction. It is reported on
// registration time.
err error
}

View File

@ -62,7 +62,7 @@ func giveBuf(buf *bytes.Buffer) {
//
// Deprecated: Please note the issues described in the doc comment of
// InstrumentHandler. You might want to consider using promhttp.Handler instead
// (which is not instrumented).
// (which is non instrumented).
func Handler() http.Handler {
return InstrumentHandler("prometheus", UninstrumentedHandler())
}
@ -245,52 +245,34 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo
},
instLabels,
)
if err := Register(reqCnt); err != nil {
if are, ok := err.(AlreadyRegisteredError); ok {
reqCnt = are.ExistingCollector.(*CounterVec)
} else {
panic(err)
}
}
opts.Name = "request_duration_microseconds"
opts.Help = "The HTTP request latencies in microseconds."
reqDur := NewSummary(opts)
if err := Register(reqDur); err != nil {
if are, ok := err.(AlreadyRegisteredError); ok {
reqDur = are.ExistingCollector.(Summary)
} else {
panic(err)
}
}
opts.Name = "request_size_bytes"
opts.Help = "The HTTP request sizes in bytes."
reqSz := NewSummary(opts)
if err := Register(reqSz); err != nil {
if are, ok := err.(AlreadyRegisteredError); ok {
reqSz = are.ExistingCollector.(Summary)
} else {
panic(err)
}
}
opts.Name = "response_size_bytes"
opts.Help = "The HTTP response sizes in bytes."
resSz := NewSummary(opts)
if err := Register(resSz); err != nil {
if are, ok := err.(AlreadyRegisteredError); ok {
resSz = are.ExistingCollector.(Summary)
} else {
panic(err)
}
}
regReqCnt := MustRegisterOrGet(reqCnt).(*CounterVec)
regReqDur := MustRegisterOrGet(reqDur).(Summary)
regReqSz := MustRegisterOrGet(reqSz).(Summary)
regResSz := MustRegisterOrGet(resSz).(Summary)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
now := time.Now()
delegate := &responseWriterDelegator{ResponseWriter: w}
out := computeApproximateRequestSize(r)
out := make(chan int)
urlLen := 0
if r.URL != nil {
urlLen = len(r.URL.String())
}
go computeApproximateRequestSize(r, out, urlLen)
_, cn := w.(http.CloseNotifier)
_, fl := w.(http.Flusher)
@ -308,44 +290,30 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo
method := sanitizeMethod(r.Method)
code := sanitizeCode(delegate.status)
reqCnt.WithLabelValues(method, code).Inc()
reqDur.Observe(elapsed)
resSz.Observe(float64(delegate.written))
reqSz.Observe(float64(<-out))
regReqCnt.WithLabelValues(method, code).Inc()
regReqDur.Observe(elapsed)
regResSz.Observe(float64(delegate.written))
regReqSz.Observe(float64(<-out))
})
}
func computeApproximateRequestSize(r *http.Request) <-chan int {
// Get URL length in current go routine for avoiding a race condition.
// HandlerFunc that runs in parallel may modify the URL.
s := 0
if r.URL != nil {
s += len(r.URL.String())
func computeApproximateRequestSize(r *http.Request, out chan int, s int) {
s += len(r.Method)
s += len(r.Proto)
for name, values := range r.Header {
s += len(name)
for _, value := range values {
s += len(value)
}
}
s += len(r.Host)
out := make(chan int, 1)
// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
go func() {
s += len(r.Method)
s += len(r.Proto)
for name, values := range r.Header {
s += len(name)
for _, value := range values {
s += len(value)
}
}
s += len(r.Host)
// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
if r.ContentLength != -1 {
s += int(r.ContentLength)
}
out <- s
close(out)
}()
return out
if r.ContentLength != -1 {
s += int(r.ContentLength)
}
out <- s
}
type responseWriterDelegator struct {

View File

@ -19,10 +19,10 @@ type processCollector struct {
pid int
collectFn func(chan<- Metric)
pidFn func() (int, error)
cpuTotal *Desc
openFDs, maxFDs *Desc
vsize, rss *Desc
startTime *Desc
cpuTotal Counter
openFDs, maxFDs Gauge
vsize, rss Gauge
startTime Gauge
}
// NewProcessCollector returns a collector which exports the current state of
@ -48,36 +48,36 @@ func NewProcessCollectorPIDFn(
pidFn: pidFn,
collectFn: func(chan<- Metric) {},
cpuTotal: NewDesc(
namespace+"_process_cpu_seconds_total",
"Total user and system CPU time spent in seconds.",
nil, nil,
),
openFDs: NewDesc(
namespace+"_process_open_fds",
"Number of open file descriptors.",
nil, nil,
),
maxFDs: NewDesc(
namespace+"_process_max_fds",
"Maximum number of open file descriptors.",
nil, nil,
),
vsize: NewDesc(
namespace+"_process_virtual_memory_bytes",
"Virtual memory size in bytes.",
nil, nil,
),
rss: NewDesc(
namespace+"_process_resident_memory_bytes",
"Resident memory size in bytes.",
nil, nil,
),
startTime: NewDesc(
namespace+"_process_start_time_seconds",
"Start time of the process since unix epoch in seconds.",
nil, nil,
),
cpuTotal: NewCounter(CounterOpts{
Namespace: namespace,
Name: "process_cpu_seconds_total",
Help: "Total user and system CPU time spent in seconds.",
}),
openFDs: NewGauge(GaugeOpts{
Namespace: namespace,
Name: "process_open_fds",
Help: "Number of open file descriptors.",
}),
maxFDs: NewGauge(GaugeOpts{
Namespace: namespace,
Name: "process_max_fds",
Help: "Maximum number of open file descriptors.",
}),
vsize: NewGauge(GaugeOpts{
Namespace: namespace,
Name: "process_virtual_memory_bytes",
Help: "Virtual memory size in bytes.",
}),
rss: NewGauge(GaugeOpts{
Namespace: namespace,
Name: "process_resident_memory_bytes",
Help: "Resident memory size in bytes.",
}),
startTime: NewGauge(GaugeOpts{
Namespace: namespace,
Name: "process_start_time_seconds",
Help: "Start time of the process since unix epoch in seconds.",
}),
}
// Set up process metric collection if supported by the runtime.
@ -90,12 +90,12 @@ func NewProcessCollectorPIDFn(
// Describe returns all descriptions of the collector.
func (c *processCollector) Describe(ch chan<- *Desc) {
ch <- c.cpuTotal
ch <- c.openFDs
ch <- c.maxFDs
ch <- c.vsize
ch <- c.rss
ch <- c.startTime
ch <- c.cpuTotal.Desc()
ch <- c.openFDs.Desc()
ch <- c.maxFDs.Desc()
ch <- c.vsize.Desc()
ch <- c.rss.Desc()
ch <- c.startTime.Desc()
}
// Collect returns the current state of all metrics of the collector.
@ -117,19 +117,26 @@ func (c *processCollector) processCollect(ch chan<- Metric) {
}
if stat, err := p.NewStat(); err == nil {
ch <- MustNewConstMetric(c.cpuTotal, CounterValue, stat.CPUTime())
ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(stat.VirtualMemory()))
ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory()))
c.cpuTotal.Set(stat.CPUTime())
ch <- c.cpuTotal
c.vsize.Set(float64(stat.VirtualMemory()))
ch <- c.vsize
c.rss.Set(float64(stat.ResidentMemory()))
ch <- c.rss
if startTime, err := stat.StartTime(); err == nil {
ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime)
c.startTime.Set(startTime)
ch <- c.startTime
}
}
if fds, err := p.FileDescriptorsLen(); err == nil {
ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds))
c.openFDs.Set(float64(fds))
ch <- c.openFDs
}
if limits, err := p.NewLimits(); err == nil {
ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles))
c.maxFDs.Set(float64(limits.OpenFiles))
ch <- c.maxFDs
}
}

View File

@ -152,6 +152,38 @@ func MustRegister(cs ...Collector) {
DefaultRegisterer.MustRegister(cs...)
}
// RegisterOrGet registers the provided Collector with the DefaultRegisterer and
// returns the Collector, unless an equal Collector was registered before, in
// which case that Collector is returned.
//
// Deprecated: RegisterOrGet is merely a convenience function for the
// implementation as described in the documentation for
// AlreadyRegisteredError. As the use case is relatively rare, this function
// will be removed in a future version of this package to clean up the
// namespace.
func RegisterOrGet(c Collector) (Collector, error) {
if err := Register(c); err != nil {
if are, ok := err.(AlreadyRegisteredError); ok {
return are.ExistingCollector, nil
}
return nil, err
}
return c, nil
}
// MustRegisterOrGet behaves like RegisterOrGet but panics instead of returning
// an error.
//
// Deprecated: This is deprecated for the same reason RegisterOrGet is. See
// there for details.
func MustRegisterOrGet(c Collector) Collector {
c, err := RegisterOrGet(c)
if err != nil {
panic(err)
}
return c
}
// Unregister removes the registration of the provided Collector from the
// DefaultRegisterer.
//
@ -169,6 +201,25 @@ func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) {
return gf()
}
// SetMetricFamilyInjectionHook replaces the DefaultGatherer with one that
// gathers from the previous DefaultGatherers but then merges the MetricFamily
// protobufs returned from the provided hook function with the MetricFamily
// protobufs returned from the original DefaultGatherer.
//
// Deprecated: This function manipulates the DefaultGatherer variable. Consider
// the implications, i.e. don't do this concurrently with any uses of the
// DefaultGatherer. In the rare cases where you need to inject MetricFamily
// protobufs directly, it is recommended to use a custom Registry and combine it
// with a custom Gatherer using the Gatherers type (see
// there). SetMetricFamilyInjectionHook only exists for compatibility reasons
// with previous versions of this package.
func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
DefaultGatherer = Gatherers{
DefaultGatherer,
GathererFunc(func() ([]*dto.MetricFamily, error) { return hook(), nil }),
}
}
// AlreadyRegisteredError is returned by the Register method if the Collector to
// be registered has already been registered before, or a different Collector
// that collects the same metrics has been registered before. Registration fails
@ -396,7 +447,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
// Drain metricChan in case of premature return.
defer func() {
for range metricChan {
for _ = range metricChan {
}
}()
@ -632,7 +683,7 @@ func (s metricSorter) Less(i, j int) bool {
return s[i].GetTimestampMs() < s[j].GetTimestampMs()
}
// normalizeMetricFamilies returns a MetricFamily slice with empty
// normalizeMetricFamilies returns a MetricFamily slice whith empty
// MetricFamilies pruned and the remaining MetricFamilies sorted by name within
// the slice, with the contained Metrics sorted within each MetricFamily.
func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {

View File

@ -8,11 +8,12 @@ go:
go_import_path: google.golang.org/grpc
before_install:
- go get -u golang.org/x/tools/cmd/goimports github.com/golang/lint/golint github.com/axw/gocov/gocov github.com/mattn/goveralls golang.org/x/tools/cmd/cover
- if [[ $TRAVIS_GO_VERSION != 1.5* ]]; then go get github.com/golang/lint/golint; fi
- go get -u golang.org/x/tools/cmd/goimports github.com/axw/gocov/gocov github.com/mattn/goveralls golang.org/x/tools/cmd/cover
script:
- '! gofmt -s -d -l . 2>&1 | read'
- '! goimports -l . | read'
- '! golint ./... | grep -vE "(_string|\.pb)\.go:"'
- 'if [[ $TRAVIS_GO_VERSION != 1.5* ]]; then ! golint ./... | grep -vE "(_string|\.pb)\.go:"; fi'
- '! go tool vet -all . 2>&1 | grep -vE "constant [0-9]+ not a string in call to Errorf" | grep -vF .pb.go:' # https://github.com/golang/protobuf/issues/214
- make test testrace

View File

@ -58,7 +58,7 @@ func setDefaults(bc *BackoffConfig) {
}
}
func (bc BackoffConfig) backoff(retries int) (t time.Duration) {
func (bc BackoffConfig) backoff(retries int) time.Duration {
if retries == 0 {
return bc.baseDelay
}

View File

@ -38,6 +38,7 @@ import (
"sync"
"golang.org/x/net/context"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/naming"
)
@ -52,6 +53,14 @@ type Address struct {
Metadata interface{}
}
// BalancerConfig specifies the configurations for Balancer.
type BalancerConfig struct {
// DialCreds is the transport credential the Balancer implementation can
// use to dial to a remote load balancer server. The Balancer implementations
// can ignore this if it does not need to talk to another party securely.
DialCreds credentials.TransportCredentials
}
// BalancerGetOptions configures a Get call.
// This is the EXPERIMENTAL API and may be changed or extended in the future.
type BalancerGetOptions struct {
@ -66,11 +75,11 @@ type Balancer interface {
// Start does the initialization work to bootstrap a Balancer. For example,
// this function may start the name resolution and watch the updates. It will
// be called when dialing.
Start(target string) error
Start(target string, config BalancerConfig) error
// Up informs the Balancer that gRPC has a connection to the server at
// addr. It returns down which is called once the connection to addr gets
// lost or closed.
// TODO: It is not clear how to construct and take advantage the meaningful error
// TODO: It is not clear how to construct and take advantage of the meaningful error
// parameter for down. Need realistic demands to guide.
Up(addr Address) (down func(error))
// Get gets the address of a server for the RPC corresponding to ctx.
@ -205,7 +214,12 @@ func (rr *roundRobin) watchAddrUpdates() error {
return nil
}
func (rr *roundRobin) Start(target string) error {
func (rr *roundRobin) Start(target string, config BalancerConfig) error {
rr.mu.Lock()
defer rr.mu.Unlock()
if rr.done {
return ErrClientConnClosing
}
if rr.r == nil {
// If there is no name resolver installed, it is not needed to
// do name resolution. In this case, target is added into rr.addrs

View File

@ -270,31 +270,47 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
if cc.dopts.bs == nil {
cc.dopts.bs = DefaultBackoffConfig
}
var (
ok bool
addrs []Address
)
if cc.dopts.balancer == nil {
// Connect to target directly if balancer is nil.
addrs = append(addrs, Address{Addr: target})
creds := cc.dopts.copts.TransportCredentials
if creds != nil && creds.Info().ServerName != "" {
cc.authority = creds.Info().ServerName
} else {
if err := cc.dopts.balancer.Start(target); err != nil {
return nil, err
}
ch := cc.dopts.balancer.Notify()
if ch == nil {
// There is no name resolver installed.
addrs = append(addrs, Address{Addr: target})
} else {
addrs, ok = <-ch
if !ok || len(addrs) == 0 {
return nil, errNoAddr
}
colonPos := strings.LastIndex(target, ":")
if colonPos == -1 {
colonPos = len(target)
}
cc.authority = target[:colonPos]
}
var ok bool
waitC := make(chan error, 1)
go func() {
var addrs []Address
if cc.dopts.balancer == nil {
// Connect to target directly if balancer is nil.
addrs = append(addrs, Address{Addr: target})
} else {
var credsClone credentials.TransportCredentials
if creds != nil {
credsClone = creds.Clone()
}
config := BalancerConfig{
DialCreds: credsClone,
}
if err := cc.dopts.balancer.Start(target, config); err != nil {
waitC <- err
return
}
ch := cc.dopts.balancer.Notify()
if ch == nil {
// There is no name resolver installed.
addrs = append(addrs, Address{Addr: target})
} else {
addrs, ok = <-ch
if !ok || len(addrs) == 0 {
waitC <- errNoAddr
return
}
}
}
for _, a := range addrs {
if err := cc.resetAddrConn(a, false, nil); err != nil {
waitC <- err
@ -322,11 +338,6 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
if ok {
go cc.lbWatcher()
}
colonPos := strings.LastIndex(target, ":")
if colonPos == -1 {
colonPos = len(target)
}
cc.authority = target[:colonPos]
return cc, nil
}
@ -673,14 +684,18 @@ func (ac *addrConn) resetTransport(closeTransport bool) error {
}
ctx, cancel := context.WithTimeout(ac.ctx, timeout)
connectTime := time.Now()
newTransport, err := transport.NewClientTransport(ctx, ac.addr.Addr, ac.dopts.copts)
sinfo := transport.TargetInfo{
Addr: ac.addr.Addr,
Metadata: ac.addr.Metadata,
}
newTransport, err := transport.NewClientTransport(ctx, sinfo, ac.dopts.copts)
if err != nil {
cancel()
if e, ok := err.(transport.ConnectionError); ok && !e.Temporary() {
return err
}
grpclog.Printf("grpc: addrConn.resetTransport failed to create client transport: %v; Reconnecting to %q", err, ac.addr)
grpclog.Printf("grpc: addrConn.resetTransport failed to create client transport: %v; Reconnecting to %v", err, ac.addr)
ac.mu.Lock()
if ac.state == Shutdown {
// ac.tearDown(...) has been invoked.

View File

@ -72,7 +72,7 @@ type PerRPCCredentials interface {
}
// ProtocolInfo provides information regarding the gRPC wire protocol version,
// security protocol, security protocol version in use, etc.
// security protocol, security protocol version in use, server name, etc.
type ProtocolInfo struct {
// ProtocolVersion is the gRPC wire protocol version.
ProtocolVersion string
@ -80,6 +80,8 @@ type ProtocolInfo struct {
SecurityProtocol string
// SecurityVersion is the security protocol version.
SecurityVersion string
// ServerName is the user-configured server name.
ServerName string
}
// AuthInfo defines the common interface for the auth information the users are interested in.
@ -107,6 +109,12 @@ type TransportCredentials interface {
ServerHandshake(net.Conn) (net.Conn, AuthInfo, error)
// Info provides the ProtocolInfo of this TransportCredentials.
Info() ProtocolInfo
// Clone makes a copy of this TransportCredentials.
Clone() TransportCredentials
// OverrideServerName overrides the server name used to verify the hostname on the returned certificates from the server.
// gRPC internals also use it to override the virtual hosting name if it is set.
// It must be called before dialing. Currently, this is only used by grpclb.
OverrideServerName(string) error
}
// TLSInfo contains the auth information for a TLS authenticated connection.
@ -130,19 +138,10 @@ func (c tlsCreds) Info() ProtocolInfo {
return ProtocolInfo{
SecurityProtocol: "tls",
SecurityVersion: "1.2",
ServerName: c.config.ServerName,
}
}
// GetRequestMetadata returns nil, nil since TLS credentials does not have
// metadata.
func (c *tlsCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return nil, nil
}
func (c *tlsCreds) RequireTransportSecurity() bool {
return true
}
func (c *tlsCreds) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) {
// use local cfg to avoid clobbering ServerName if using multiple endpoints
cfg := cloneTLSConfig(c.config)
@ -179,6 +178,15 @@ func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error)
return conn, TLSInfo{conn.ConnectionState()}, nil
}
func (c *tlsCreds) Clone() TransportCredentials {
return NewTLS(c.config)
}
func (c *tlsCreds) OverrideServerName(serverNameOverride string) error {
c.config.ServerName = serverNameOverride
return nil
}
// NewTLS uses c to construct a TransportCredentials based on TLS.
func NewTLS(c *tls.Config) TransportCredentials {
tc := &tlsCreds{cloneTLSConfig(c)}
@ -187,12 +195,16 @@ func NewTLS(c *tls.Config) TransportCredentials {
}
// NewClientTLSFromCert constructs a TLS from the input certificate for client.
func NewClientTLSFromCert(cp *x509.CertPool, serverName string) TransportCredentials {
return NewTLS(&tls.Config{ServerName: serverName, RootCAs: cp})
// serverNameOverride is for testing only. If set to a non empty string,
// it will override the virtual host name of authority (e.g. :authority header field) in requests.
func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
}
// NewClientTLSFromFile constructs a TLS from the input certificate file for client.
func NewClientTLSFromFile(certFile, serverName string) (TransportCredentials, error) {
// serverNameOverride is for testing only. If set to a non empty string,
// it will override the virtual host name of authority (e.g. :authority header field) in requests.
func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) {
b, err := ioutil.ReadFile(certFile)
if err != nil {
return nil, err
@ -201,7 +213,7 @@ func NewClientTLSFromFile(certFile, serverName string) (TransportCredentials, er
if !cp.AppendCertsFromPEM(b) {
return nil, fmt.Errorf("credentials: failed to append certificates")
}
return NewTLS(&tls.Config{ServerName: serverName, RootCAs: cp}), nil
return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
}
// NewServerTLSFromCert constructs a TLS from the input certificate for server.

View File

@ -117,10 +117,17 @@ func (md MD) Len() int {
// Copy returns a copy of md.
func (md MD) Copy() MD {
return Join(md)
}
// Join joins any number of MDs into a single MD.
// The order of values for each key is determined by the order in which
// the MDs containing those values are presented to Join.
func Join(mds ...MD) MD {
out := MD{}
for k, v := range md {
for _, i := range v {
out[k] = append(out[k], i)
for _, md := range mds {
for k, v := range md {
out[k] = append(out[k], v...)
}
}
return out

View File

@ -89,10 +89,12 @@ type service struct {
type Server struct {
opts options
mu sync.Mutex // guards following
lis map[net.Listener]bool
conns map[io.Closer]bool
drain bool
mu sync.Mutex // guards following
lis map[net.Listener]bool
conns map[io.Closer]bool
drain bool
ctx context.Context
cancel context.CancelFunc
// A CondVar to let GracefulStop() blocks until all the pending RPCs are finished
// and all the transport goes away.
cv *sync.Cond
@ -203,6 +205,7 @@ func NewServer(opt ...ServerOption) *Server {
m: make(map[string]*service),
}
s.cv = sync.NewCond(&s.mu)
s.ctx, s.cancel = context.WithCancel(context.Background())
if EnableTracing {
_, file, line, _ := runtime.Caller(1)
s.events = trace.NewEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line))
@ -324,7 +327,7 @@ func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credenti
// Serve accepts incoming connections on the listener lis, creating a new
// ServerTransport and service goroutine for each. The service goroutines
// read gRPC requests and then call the registered handlers to reply to them.
// Serve returns when lis.Accept fails. lis will be closed when
// Serve returns when lis.Accept fails with fatal errors. lis will be closed when
// this method returns.
func (s *Server) Serve(lis net.Listener) error {
s.mu.Lock()
@ -344,14 +347,38 @@ func (s *Server) Serve(lis net.Listener) error {
}
s.mu.Unlock()
}()
var tempDelay time.Duration // how long to sleep on accept failure
for {
rawConn, err := lis.Accept()
if err != nil {
if ne, ok := err.(interface {
Temporary() bool
}); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
s.mu.Lock()
s.printf("Accept error: %v; retrying in %v", err, tempDelay)
s.mu.Unlock()
select {
case <-time.After(tempDelay):
case <-s.ctx.Done():
}
continue
}
s.mu.Lock()
s.printf("done serving; Accept = %v", err)
s.mu.Unlock()
return err
}
tempDelay = 0
// Start a new goroutine to deal with rawConn
// so we don't stall this Accept loop goroutine.
go s.handleRawConn(rawConn)
@ -500,7 +527,7 @@ func (s *Server) removeConn(c io.Closer) {
defer s.mu.Unlock()
if s.conns != nil {
delete(s.conns, c)
s.cv.Signal()
s.cv.Broadcast()
}
}
@ -801,7 +828,7 @@ func (s *Server) Stop() {
st := s.conns
s.conns = nil
// interrupt GracefulStop if Stop and GracefulStop are called concurrently.
s.cv.Signal()
s.cv.Broadcast()
s.mu.Unlock()
for lis := range listeners {
@ -812,6 +839,7 @@ func (s *Server) Stop() {
}
s.mu.Lock()
s.cancel()
if s.events != nil {
s.events.Finish()
s.events = nil
@ -824,16 +852,19 @@ func (s *Server) Stop() {
func (s *Server) GracefulStop() {
s.mu.Lock()
defer s.mu.Unlock()
if s.drain == true || s.conns == nil {
if s.conns == nil {
return
}
s.drain = true
for lis := range s.lis {
lis.Close()
}
s.lis = nil
for c := range s.conns {
c.(transport.ServerTransport).Drain()
s.cancel()
if !s.drain {
for c := range s.conns {
c.(transport.ServerTransport).Drain()
}
s.drain = true
}
for len(s.conns) != 0 {
s.cv.Wait()
@ -865,33 +896,49 @@ func (s *Server) testingCloseConns() {
s.mu.Unlock()
}
// SendHeader sends header metadata. It may be called at most once from a unary
// RPC handler. The ctx is the RPC handler's Context or one derived from it.
func SendHeader(ctx context.Context, md metadata.MD) error {
// SetHeader sets the header metadata.
// When called multiple times, all the provided metadata will be merged.
// All the metadata will be sent out when one of the following happens:
// - grpc.SendHeader() is called;
// - The first response is sent out;
// - An RPC status is sent out (error or success).
func SetHeader(ctx context.Context, md metadata.MD) error {
if md.Len() == 0 {
return nil
}
stream, ok := transport.StreamFromContext(ctx)
if !ok {
return fmt.Errorf("grpc: failed to fetch the stream from the context %v", ctx)
return Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx)
}
return stream.SetHeader(md)
}
// SendHeader sends header metadata. It may be called at most once.
// The provided md and headers set by SetHeader() will be sent.
func SendHeader(ctx context.Context, md metadata.MD) error {
stream, ok := transport.StreamFromContext(ctx)
if !ok {
return Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx)
}
t := stream.ServerTransport()
if t == nil {
grpclog.Fatalf("grpc: SendHeader: %v has no ServerTransport to send header metadata.", stream)
}
return t.WriteHeader(stream, md)
if err := t.WriteHeader(stream, md); err != nil {
return toRPCErr(err)
}
return nil
}
// SetTrailer sets the trailer metadata that will be sent when an RPC returns.
// It may be called at most once from a unary RPC handler. The ctx is the RPC
// handler's Context or one derived from it.
// When called more than once, all the provided metadata will be merged.
func SetTrailer(ctx context.Context, md metadata.MD) error {
if md.Len() == 0 {
return nil
}
stream, ok := transport.StreamFromContext(ctx)
if !ok {
return fmt.Errorf("grpc: failed to fetch the stream from the context %v", ctx)
return Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx)
}
return stream.SetTrailer(md)
}

View File

@ -410,12 +410,19 @@ func (cs *clientStream) finish(err error) {
// ServerStream defines the interface a server stream has to satisfy.
type ServerStream interface {
// SendHeader sends the header metadata. It should not be called
// after SendProto. It fails if called multiple times or if
// called after SendProto.
// SetHeader sets the header metadata. It may be called multiple times.
// When call multiple times, all the provided metadata will be merged.
// All the metadata will be sent out when one of the following happens:
// - ServerStream.SendHeader() is called;
// - The first response is sent out;
// - An RPC status is sent out (error or success).
SetHeader(metadata.MD) error
// SendHeader sends the header metadata.
// The provided md and headers set by SetHeader() will be sent.
// It fails if called multiple times.
SendHeader(metadata.MD) error
// SetTrailer sets the trailer metadata which will be sent with the
// RPC status.
// SetTrailer sets the trailer metadata which will be sent with the RPC status.
// When called more than once, all the provided metadata will be merged.
SetTrailer(metadata.MD)
Stream
}
@ -441,6 +448,13 @@ func (ss *serverStream) Context() context.Context {
return ss.s.Context()
}
func (ss *serverStream) SetHeader(md metadata.MD) error {
if md.Len() == 0 {
return nil
}
return ss.s.SetHeader(md)
}
func (ss *serverStream) SendHeader(md metadata.MD) error {
return ss.t.WriteHeader(ss.s, md)
}

View File

@ -57,6 +57,7 @@ import (
type http2Client struct {
target string // server name/addr
userAgent string
md interface{}
conn net.Conn // underlying communication channel
authInfo credentials.AuthInfo // auth info about the connection
nextID uint32 // the next stream ID to be used
@ -107,7 +108,7 @@ type http2Client struct {
prevGoAwayID uint32
}
func dial(fn func(context.Context, string) (net.Conn, error), ctx context.Context, addr string) (net.Conn, error) {
func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error), addr string) (net.Conn, error) {
if fn != nil {
return fn(ctx, addr)
}
@ -145,9 +146,9 @@ func isTemporary(err error) bool {
// newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2
// and starts to receive messages on it. Non-nil error returns if construction
// fails.
func newHTTP2Client(ctx context.Context, addr string, opts ConnectOptions) (_ ClientTransport, err error) {
func newHTTP2Client(ctx context.Context, addr TargetInfo, opts ConnectOptions) (_ ClientTransport, err error) {
scheme := "http"
conn, err := dial(opts.Dialer, ctx, addr)
conn, err := dial(ctx, opts.Dialer, addr.Addr)
if err != nil {
return nil, connectionErrorf(true, err, "transport: %v", err)
}
@ -160,7 +161,7 @@ func newHTTP2Client(ctx context.Context, addr string, opts ConnectOptions) (_ Cl
var authInfo credentials.AuthInfo
if creds := opts.TransportCredentials; creds != nil {
scheme = "https"
conn, authInfo, err = creds.ClientHandshake(ctx, addr, conn)
conn, authInfo, err = creds.ClientHandshake(ctx, addr.Addr, conn)
if err != nil {
// Credentials handshake errors are typically considered permanent
// to avoid retrying on e.g. bad certificates.
@ -174,8 +175,9 @@ func newHTTP2Client(ctx context.Context, addr string, opts ConnectOptions) (_ Cl
}
var buf bytes.Buffer
t := &http2Client{
target: addr,
target: addr.Addr,
userAgent: ua,
md: addr.Metadata,
conn: conn,
authInfo: authInfo,
// The client initiated stream id is odd starting from 1.
@ -252,8 +254,10 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream {
s.windowHandler = func(n int) {
t.updateWindow(s, uint32(n))
}
// Make a stream be able to cancel the pending operations by itself.
s.ctx, s.cancel = context.WithCancel(ctx)
// The client side stream context should have exactly the same life cycle with the user provided context.
// That means, s.ctx should be read-only. And s.ctx is done iff ctx is done.
// So we use the original context here instead of creating a copy.
s.ctx = ctx
s.dec = &recvBufferReader{
ctx: s.ctx,
goAway: s.goAway,
@ -265,16 +269,6 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream {
// NewStream creates a stream and register it into the transport as "active"
// streams.
func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) {
// Record the timeout value on the context.
var timeout time.Duration
if dl, ok := ctx.Deadline(); ok {
timeout = dl.Sub(time.Now())
}
select {
case <-ctx.Done():
return nil, ContextErr(ctx.Err())
default:
}
pr := &peer.Peer{
Addr: t.conn.RemoteAddr(),
}
@ -381,9 +375,12 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
if callHdr.SendCompress != "" {
t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress})
}
if timeout > 0 {
if dl, ok := ctx.Deadline(); ok {
// Send out timeout regardless its value. The server can detect timeout context by itself.
timeout := dl.Sub(time.Now())
t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-timeout", Value: encodeTimeout(timeout)})
}
for k, v := range authData {
// Capital header names are illegal in HTTP/2.
k = strings.ToLower(k)
@ -405,6 +402,16 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
}
}
}
if md, ok := t.md.(*metadata.MD); ok {
for k, v := range *md {
if isReservedHeader(k) {
continue
}
for _, entry := range v {
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: entry})
}
}
}
first := true
// Sends the headers in a single batch even when they span multiple frames.
for !endHeaders {
@ -795,6 +802,9 @@ func (t *http2Client) handleSettings(f *http2.SettingsFrame) {
}
func (t *http2Client) handlePing(f *http2.PingFrame) {
if f.IsAck() { // Do nothing.
return
}
pingAck := &ping{ack: true}
copy(pingAck.data[:], f.Data[:])
t.controlBuf.put(pingAck)
@ -852,6 +862,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
state.processHeaderField(hf)
}
if state.err != nil {
s.mu.Lock()
if !s.headerDone {
close(s.headerChan)
s.headerDone = true
}
s.mu.Unlock()
s.write(recvMsg{err: state.err})
// Something wrong. Stops reading even when there is remaining.
return

View File

@ -405,6 +405,9 @@ func (t *http2Server) handleSettings(f *http2.SettingsFrame) {
}
func (t *http2Server) handlePing(f *http2.PingFrame) {
if f.IsAck() { // Do nothing.
return
}
pingAck := &ping{ack: true}
copy(pingAck.data[:], f.Data[:])
t.controlBuf.put(pingAck)
@ -462,6 +465,14 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error {
return ErrIllegalHeaderWrite
}
s.headerOk = true
if md.Len() > 0 {
if s.header.Len() > 0 {
s.header = metadata.Join(s.header, md)
} else {
s.header = md
}
}
md = s.header
s.mu.Unlock()
if _, err := wait(s.ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil {
return err
@ -493,7 +504,7 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error {
// TODO(zhaoq): Now it indicates the end of entire stream. Revisit if early
// OK is adopted.
func (t *http2Server) WriteStatus(s *Stream, statusCode codes.Code, statusDesc string) error {
var headersSent bool
var headersSent, hasHeader bool
s.mu.Lock()
if s.state == streamDone {
s.mu.Unlock()
@ -502,7 +513,16 @@ func (t *http2Server) WriteStatus(s *Stream, statusCode codes.Code, statusDesc s
if s.headerOk {
headersSent = true
}
if s.header.Len() > 0 {
hasHeader = true
}
s.mu.Unlock()
if !headersSent && hasHeader {
t.WriteHeader(s, nil)
headersSent = true
}
if _, err := wait(s.ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil {
return err
}
@ -548,29 +568,10 @@ func (t *http2Server) Write(s *Stream, data []byte, opts *Options) error {
}
if !s.headerOk {
writeHeaderFrame = true
s.headerOk = true
}
s.mu.Unlock()
if writeHeaderFrame {
if _, err := wait(s.ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil {
return err
}
t.hBuf.Reset()
t.hEnc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: "application/grpc"})
if s.sendCompress != "" {
t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-encoding", Value: s.sendCompress})
}
p := http2.HeadersFrameParam{
StreamID: s.id,
BlockFragment: t.hBuf.Bytes(),
EndHeaders: true,
}
if err := t.framer.writeHeaders(false, p); err != nil {
t.Close()
return connectionErrorf(true, err, "transport: %v", err)
}
t.writableChan <- 0
t.WriteHeader(s, nil)
}
r := bytes.NewBuffer(data)
for {

View File

@ -253,6 +253,9 @@ func div(d, r time.Duration) int64 {
// TODO(zhaoq): It is the simplistic and not bandwidth efficient. Improve it.
func encodeTimeout(t time.Duration) string {
if t <= 0 {
return "0n"
}
if d := div(t, time.Nanosecond); d <= maxTimeoutValue {
return strconv.FormatInt(d, 10) + "n"
}
@ -349,7 +352,7 @@ func decodeGrpcMessageUnchecked(msg string) string {
for i := 0; i < lenMsg; i++ {
c := msg[i]
if c == percentByte && i+2 < lenMsg {
parsed, err := strconv.ParseInt(msg[i+1:i+3], 16, 8)
parsed, err := strconv.ParseUint(msg[i+1:i+3], 16, 8)
if err != nil {
buf.WriteByte(c)
} else {

View File

@ -39,7 +39,6 @@ package transport
import (
"bytes"
"errors"
"fmt"
"io"
"net"
@ -169,7 +168,8 @@ type Stream struct {
// nil for client side Stream.
st ServerTransport
// ctx is the associated context of the stream.
ctx context.Context
ctx context.Context
// cancel is always nil for client side Stream.
cancel context.CancelFunc
// done is closed when the final status arrives.
done chan struct{}
@ -286,19 +286,30 @@ func (s *Stream) StatusDesc() string {
return s.statusDesc
}
// ErrIllegalTrailerSet indicates that the trailer has already been set or it
// is too late to do so.
var ErrIllegalTrailerSet = errors.New("transport: trailer has been set")
// SetTrailer sets the trailer metadata which will be sent with the RPC status
// by the server. This can only be called at most once. Server side only.
func (s *Stream) SetTrailer(md metadata.MD) error {
// SetHeader sets the header metadata. This can be called multiple times.
// Server side only.
func (s *Stream) SetHeader(md metadata.MD) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.trailer != nil {
return ErrIllegalTrailerSet
if s.headerOk || s.state == streamDone {
return ErrIllegalHeaderWrite
}
s.trailer = md.Copy()
if md.Len() == 0 {
return nil
}
s.header = metadata.Join(s.header, md)
return nil
}
// SetTrailer sets the trailer metadata which will be sent with the RPC status
// by the server. This can be called multiple times. Server side only.
func (s *Stream) SetTrailer(md metadata.MD) error {
if md.Len() == 0 {
return nil
}
s.mu.Lock()
defer s.mu.Unlock()
s.trailer = metadata.Join(s.trailer, md)
return nil
}
@ -350,7 +361,7 @@ func NewServerTransport(protocol string, conn net.Conn, maxStreams uint32, authI
return newHTTP2Server(conn, maxStreams, authInfo)
}
// ConnectOptions covers all relevant options for dialing a server.
// ConnectOptions covers all relevant options for communicating with the server.
type ConnectOptions struct {
// UserAgent is the application user agent.
UserAgent string
@ -362,9 +373,15 @@ type ConnectOptions struct {
TransportCredentials credentials.TransportCredentials
}
// TargetInfo contains the information of the target such as network address and metadata.
type TargetInfo struct {
Addr string
Metadata interface{}
}
// NewClientTransport establishes the transport with the required ConnectOptions
// and returns it to the caller.
func NewClientTransport(ctx context.Context, target string, opts ConnectOptions) (ClientTransport, error) {
func NewClientTransport(ctx context.Context, target TargetInfo, opts ConnectOptions) (ClientTransport, error) {
return newHTTP2Client(ctx, target, opts)
}

View File

@ -86,8 +86,6 @@ type WebFrontEndImpl struct {
// Maximum duration of a request
RequestTimeout time.Duration
// Feature gates
CheckMalformedCSR bool
AcceptRevocationReason bool
AllowAuthzDeactivation bool
}
@ -275,7 +273,7 @@ func (wfe *WebFrontEndImpl) relativeDirectory(request *http.Request, directory m
// Handler returns an http.Handler that uses various functions for
// various ACME-specified paths.
func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {
func (wfe *WebFrontEndImpl) Handler() http.Handler {
m := http.NewServeMux()
wfe.HandleFunc(m, directoryPath, wfe.Directory, "GET")
wfe.HandleFunc(m, newRegPath, wfe.NewRegistration, "POST")
@ -300,7 +298,7 @@ func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {
clk: clock.Default(),
wfe: wfeHandlerFunc(wfe.Index),
})
return m, nil
return m
}
// Method implementations
@ -872,15 +870,13 @@ func (wfe *WebFrontEndImpl) NewCertificate(ctx context.Context, logEvent *reques
// with a more useful error message.
if len(rawCSR.CSR) >= 10 && rawCSR.CSR[8] == 2 && rawCSR.CSR[9] == 0 {
logEvent.AddError("Pre-1.0.2 OpenSSL malformed CSR")
if wfe.CheckMalformedCSR {
wfe.sendError(
response,
logEvent,
probs.Malformed("CSR generated using a pre-1.0.2 OpenSSL with a client that doesn't properly specify the CSR version. See https://community.letsencrypt.org/t/openssl-bug-information/19591"),
nil,
)
return
}
wfe.sendError(
response,
logEvent,
probs.Malformed("CSR generated using a pre-1.0.2 OpenSSL with a client that doesn't properly specify the CSR version. See https://community.letsencrypt.org/t/openssl-bug-information/19591"),
nil,
)
return
}
certificateRequest := core.CertificateRequest{Bytes: rawCSR.CSR}

View File

@ -611,8 +611,7 @@ func TestDirectory(t *testing.T) {
defer features.Reset()
wfe, _ := setupWFE(t)
wfe.BaseURL = "http://localhost:4300"
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
responseWriter := httptest.NewRecorder()
@ -646,8 +645,7 @@ func TestRelativeDirectory(t *testing.T) {
_ = features.Set(map[string]bool{"AllowKeyRollover": true})
defer features.Reset()
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
dirTests := []struct {
host string
@ -692,8 +690,7 @@ func TestRelativeDirectory(t *testing.T) {
// - RA returns with a failure
func TestIssueCertificate(t *testing.T) {
wfe, fc := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
mockLog := wfe.log.(*blog.Mock)
// The mock CA we use always returns the same test certificate, with a Not
@ -842,8 +839,6 @@ func TestIssueCertificate(t *testing.T) {
test.AssertContains(t, reqlogs[0], `[AUDIT] `)
test.AssertContains(t, reqlogs[0], `"CommonName":"not-an-example.com",`)
// CSR generated using pre-1.0.1 OpenSSL with malformed version integer
wfe.CheckMalformedCSR = true
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(ctx, newRequestEvent(), responseWriter,
@ -991,6 +986,7 @@ func TestNewECDSARegistration(t *testing.T) {
responseWriter = httptest.NewRecorder()
// POST, Valid JSON, Key already in use
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["mailto:person@mail.com"],"agreement":"` + agreementURL + `"}`))
test.AssertNotError(t, err, "Failed to signer.Sign")
wfe.NewRegistration(ctx, newRequestEvent(), responseWriter, makePostRequest(result.FullSerialize()))
assertJSONEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Registration key is already in use","status":409}`)
@ -1004,8 +1000,6 @@ func TestNewECDSARegistration(t *testing.T) {
// a populated reg object will be returned.
func TestEmptyRegistration(t *testing.T) {
wfe, _ := setupWFE(t)
_, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
responseWriter := httptest.NewRecorder()
// Test Key 1 is mocked in the mock StorageAuthority used in setupWFE to
@ -1045,9 +1039,7 @@ func TestEmptyRegistration(t *testing.T) {
func TestNewRegistration(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
key, err := jose.LoadPrivateKey([]byte(test2KeyPrivatePEM))
test.AssertNotError(t, err, "Failed to load key")
rsaKey, ok := key.(*rsa.PrivateKey)
@ -1165,6 +1157,7 @@ func TestNewRegistration(t *testing.T) {
responseWriter = httptest.NewRecorder()
// POST, Valid JSON, Key already in use
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["mailto:person@mail.com"],"agreement":"` + agreementURL + `"}`))
test.AssertNotError(t, err, "Failed to signer.Sign")
wfe.NewRegistration(ctx, newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
@ -1417,8 +1410,7 @@ func TestRevokeCertificateWithAuthz(t *testing.T) {
func TestAuthorization(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
responseWriter := httptest.NewRecorder()
@ -1487,7 +1479,7 @@ func TestAuthorization(t *testing.T) {
assertJSONEquals(t, responseWriter.Body.String(), `{"identifier":{"type":"dns","value":"test.com"}}`)
var authz core.Authorization
err = json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
err := json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
test.AssertNotError(t, err, "Couldn't unmarshal returned authorization object")
// Expired authorizations should be inaccessible
@ -1524,8 +1516,7 @@ func TestRegistration(t *testing.T) {
_ = features.Set(map[string]bool{"AllowKeyRollover": true})
defer features.Reset()
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
responseWriter := httptest.NewRecorder()
// Test invalid method
@ -1658,8 +1649,7 @@ func TestIssuer(t *testing.T) {
func TestGetCertificate(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
wfe.CertCacheDuration = time.Second * 10
wfe.CertNoCacheExpirationWindow = time.Hour * 24 * 7
@ -1819,7 +1809,7 @@ func TestGetCertificateHEADHasCorrectBodyLength(t *testing.T) {
mockLog := wfe.log.(*blog.Mock)
mockLog.Clear()
mux, _ := wfe.Handler()
mux := wfe.Handler()
s := httptest.NewServer(mux)
// TODO(#1989): Close s
req, _ := http.NewRequest("HEAD", s.URL+"/acme/cert/0000000000000000000000000000000000b2", nil)
@ -1855,8 +1845,7 @@ func TestVerifyPOSTInvalidJWK(t *testing.T) {
func TestHeaderBoulderRequestId(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
responseWriter := httptest.NewRecorder()
mux.ServeHTTP(responseWriter, &http.Request{
@ -1870,8 +1859,7 @@ func TestHeaderBoulderRequestId(t *testing.T) {
func TestHeaderBoulderRequester(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mux := wfe.Handler()
responseWriter := httptest.NewRecorder()
// create a signed request
@ -1892,6 +1880,7 @@ func TestHeaderBoulderRequester(t *testing.T) {
// requests that do call sendError() also should have the requester header
signer.SetNonceSource(wfe.nonceService)
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"https://letsencrypt.org/im-bad"}`))
test.AssertNotError(t, err, "Failed to signer.Sign")
request = makePostRequestWithPath(regPath+"1", result.FullSerialize())
mux.ServeHTTP(responseWriter, request)
test.AssertEquals(t, responseWriter.Header().Get("Boulder-Requester"), "1")