Merge pull request #2394 from letsencrypt/master
Merge master to staging.
This commit is contained in:
commit
0f2af77660
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = `
|
||||
|
|
|
|||
|
|
@ -83,13 +83,13 @@ func TestFindContacts(t *testing.T) {
|
|||
|
||||
func exampleContacts() []contact {
|
||||
return []contact{
|
||||
contact{
|
||||
{
|
||||
ID: 1,
|
||||
},
|
||||
contact{
|
||||
{
|
||||
ID: 2,
|
||||
},
|
||||
contact{
|
||||
{
|
||||
ID: 3,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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, ".")
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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: ®.ID,
|
||||
Key: keyBytes,
|
||||
Contact: contacts,
|
||||
ContactsPresent: &contactsPresent,
|
||||
Agreement: ®.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: ×tamp,
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
1162
grpc/wrappers.go
1162
grpc/wrappers.go
File diff suppressed because it is too large
Load Diff
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package prefixed_db
|
||||
package prefixdb
|
||||
|
||||
import "database/sql/driver"
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package prefixed_db
|
||||
package prefixdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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 ®istrationAuthorityClient{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,
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
}
|
||||
16
sa/sa.go
16
sa/sa.go
|
|
@ -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, "(?, ?, ?)")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
"maxDBConns": 10,
|
||||
"features": {
|
||||
"IDNASupport": true
|
||||
}
|
||||
},
|
||||
"hostnamePolicyFile": "test/hostname-policy.json"
|
||||
},
|
||||
|
||||
"pa": {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"certChecker": {
|
||||
"dbConnectFile": "test/secrets/cert_checker_dburl",
|
||||
"maxDBConns": 10
|
||||
"maxDBConns": 10,
|
||||
"hostnamePolicyFile": "test/hostname-policy.json"
|
||||
},
|
||||
|
||||
"pa": {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
{
|
||||
"ExactBlacklist": [
|
||||
"highrisk.le-test.hoffman-andrews.com",
|
||||
"exactblacklist.letsencrypt.org"
|
||||
],
|
||||
"Blacklist": [
|
||||
"in-addr.arpa",
|
||||
"example",
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
6
va/va.go
6
va/va.go
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
PKCS11Key
|
||||
========
|
||||
|
||||
The pkcs11key package implements a crypto.Signer interface for a PKCS#11 private key.
|
||||
|
||||
[](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.
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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 <
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
22
wfe/wfe.go
22
wfe/wfe.go
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue