CA: Implement IssuePrecertificate. (#2946)

* CA: Stub IssuePrecertificate gPRC method.

* CA: Implement IssuePrecertificate.

* CA: Test Precertificate flow in TestIssueCertificate().

move verification of certificate storage

IssuePrecertificate tests

Add CT precertificate poison extension to CFSSL whitelist.

CFSSL won't allow us to add an extension to a certificate unless that
certificate is in the whitelist.

According to its documentation, "Extensions requested in the CSR are
ignored, except for those processed by ParseCertificateRequest (mainly
subjectAltName)." Still, at least we need to add tests to make sure a
poison extension in a CSR isn't copied into the final certificate.

This allows us to avoid making invasive changes to CFSSL.

* CA: Test precertificate issuance in TestInvalidCSRs().

* CA: Only support IssuePrecertificate() if it is explicitly enabled.

* CA: Test that we produce CT poison extensions in the valid form.

The poison extension must be critical in order to work correctly. It probably wouldn't
matter as much what the value is, but the spec requires the value to be ASN.1 NULL, so
verify that it is.
This commit is contained in:
Brian Smith 2017-08-09 18:05:39 -10:00 committed by Jacob Hoffman-Andrews
parent 3c8742ffaa
commit d2291f6c5a
12 changed files with 423 additions and 143 deletions

104
ca/ca.go
View File

@ -29,6 +29,7 @@ import (
caPB "github.com/letsencrypt/boulder/ca/proto"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
corePB "github.com/letsencrypt/boulder/core/proto"
csrlib "github.com/letsencrypt/boulder/csr"
berrors "github.com/letsencrypt/boulder/errors"
"github.com/letsencrypt/boulder/features"
@ -73,6 +74,13 @@ var (
Critical: false,
Value: hex.EncodeToString(mustStapleFeatureValue),
}
// https://tools.ietf.org/html/rfc6962#section-3.1
ctPoisonExtension = signer.Extension{
ID: cfsslConfig.OID(signer.CTPoisonOID),
Critical: true,
Value: "0500", // ASN.1 DER NULL, Hex encoded.
}
)
// Metrics for CA statistics
@ -100,20 +108,21 @@ type CertificateAuthorityImpl struct {
// A map from issuer cert common name to an internalIssuer struct
issuers map[string]*internalIssuer
// The common name of the default issuer cert
defaultIssuer *internalIssuer
sa certificateStorage
pa core.PolicyAuthority
keyPolicy goodkey.KeyPolicy
clk clock.Clock
log blog.Logger
stats metrics.Scope
prefix int // Prepended to the serial number
validityPeriod time.Duration
maxNames int
forceCNFromSAN bool
enableMustStaple bool
signatureCount *prometheus.CounterVec
csrExtensionCount *prometheus.CounterVec
defaultIssuer *internalIssuer
sa certificateStorage
pa core.PolicyAuthority
keyPolicy goodkey.KeyPolicy
clk clock.Clock
log blog.Logger
stats metrics.Scope
prefix int // Prepended to the serial number
validityPeriod time.Duration
maxNames int
forceCNFromSAN bool
enableMustStaple bool
enablePrecertificateFlow bool
signatureCount *prometheus.CounterVec
csrExtensionCount *prometheus.CounterVec
}
// Issuer represents a single issuer certificate, along with its key.
@ -236,21 +245,22 @@ func NewCertificateAuthorityImpl(
stats.MustRegister(signatureCount)
ca = &CertificateAuthorityImpl{
sa: sa,
pa: pa,
issuers: internalIssuers,
defaultIssuer: defaultIssuer,
rsaProfile: rsaProfile,
ecdsaProfile: ecdsaProfile,
prefix: config.SerialPrefix,
clk: clk,
log: logger,
stats: stats,
keyPolicy: keyPolicy,
forceCNFromSAN: !config.DoNotForceCN, // Note the inversion here
enableMustStaple: config.EnableMustStaple,
signatureCount: signatureCount,
csrExtensionCount: csrExtensionCount,
sa: sa,
pa: pa,
issuers: internalIssuers,
defaultIssuer: defaultIssuer,
rsaProfile: rsaProfile,
ecdsaProfile: ecdsaProfile,
prefix: config.SerialPrefix,
clk: clk,
log: logger,
stats: stats,
keyPolicy: keyPolicy,
forceCNFromSAN: !config.DoNotForceCN, // Note the inversion here
enableMustStaple: config.EnableMustStaple,
enablePrecertificateFlow: config.EnablePrecertificateFlow,
signatureCount: signatureCount,
csrExtensionCount: csrExtensionCount,
}
if config.Expiry == "" {
@ -401,7 +411,7 @@ func (ca *CertificateAuthorityImpl) IssueCertificate(ctx context.Context, issueR
return emptyCert, err
}
certDER, err := ca.issueCertificateOrPrecertificate(ctx, issueReq, notAfter, serialBigInt, "cert")
certDER, err := ca.issueCertificateOrPrecertificate(ctx, issueReq, notAfter, serialBigInt, "cert", nil)
if err != nil {
return emptyCert, err
}
@ -444,6 +454,30 @@ func (ca *CertificateAuthorityImpl) IssueCertificate(ctx context.Context, issueR
return cert, nil
}
func (ca *CertificateAuthorityImpl) IssuePrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error) {
if !ca.enablePrecertificateFlow {
return nil, berrors.NotSupportedError("Precertificate flow is disabled")
}
if issueReq.RegistrationID == nil {
return nil, berrors.InternalServerError("RegistrationID is nil")
}
notAfter, serialBigInt, err := ca.generateNotAfterAndSerialNumber()
if err != nil {
return nil, err
}
precertDER, err := ca.issueCertificateOrPrecertificate(ctx, issueReq, notAfter, serialBigInt, "cert", &ctPoisonExtension)
if err != nil {
return nil, err
}
return &caPB.IssuePrecertificateResponse{
Precert: &corePB.Precertificate{Der: precertDER},
SctFetchingConfig: &corePB.SCTFetchingConfig{},
}, nil
}
func (ca *CertificateAuthorityImpl) generateNotAfterAndSerialNumber() (time.Time, *big.Int, error) {
notAfter := ca.clk.Now().Add(ca.validityPeriod)
@ -463,7 +497,7 @@ func (ca *CertificateAuthorityImpl) generateNotAfterAndSerialNumber() (time.Time
return notAfter, serialBigInt, nil
}
func (ca *CertificateAuthorityImpl) issueCertificateOrPrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest, notAfter time.Time, serialBigInt *big.Int, certType string) ([]byte, error) {
func (ca *CertificateAuthorityImpl) issueCertificateOrPrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest, notAfter time.Time, serialBigInt *big.Int, certType string, addedExtension *signer.Extension) ([]byte, error) {
csr, err := x509.ParseCertificateRequest(issueReq.Csr)
if err != nil {
return nil, err
@ -481,11 +515,15 @@ func (ca *CertificateAuthorityImpl) issueCertificateOrPrecertificate(ctx context
return nil, berrors.MalformedError(err.Error())
}
requestedExtensions, err := ca.extensionsFromCSR(csr)
extensions, err := ca.extensionsFromCSR(csr)
if err != nil {
return nil, err
}
if addedExtension != nil {
extensions = append(extensions, *addedExtension)
}
issuer := ca.defaultIssuer
if issuer.cert.NotAfter.Before(notAfter) {
@ -521,7 +559,7 @@ func (ca *CertificateAuthorityImpl) issueCertificateOrPrecertificate(ctx context
CN: csr.Subject.CommonName,
},
Serial: serialBigInt,
Extensions: requestedExtensions,
Extensions: extensions,
}
serialHex := core.SerialToString(serialBigInt)

View File

@ -113,6 +113,12 @@ var (
// OIDExtensionCTPoison is defined in RFC 6962 s3.1.
OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
issuanceModes = []IssuanceMode{
{name: "non-precertificate", usePrecertificateFlow: false, enablePrecertificateFlow: false},
{name: "precertificate", usePrecertificateFlow: true, enablePrecertificateFlow: true},
{name: "precertificate-disabled", usePrecertificateFlow: true, enablePrecertificateFlow: false},
}
)
// CFSSL config
@ -173,6 +179,11 @@ func setup(t *testing.T) *testCtx {
err = pa.SetHostnamePolicyFile("../test/hostname-policy.json")
test.AssertNotError(t, err, "Couldn't set hostname policy")
allowedExtensions := []cfsslConfig.OID{
cfsslConfig.OID(oidTLSFeature),
cfsslConfig.OID(OIDExtensionCTPoison),
}
// Create a CA
caConfig := cmd.CAConfig{
RSAProfile: rsaProfileName,
@ -203,9 +214,7 @@ func setup(t *testing.T) *testCtx {
SignatureAlgorithm: true,
},
ClientProvidesSerialNumbers: true,
AllowedExtensions: []cfsslConfig.OID{
cfsslConfig.OID(oidTLSFeature),
},
AllowedExtensions: allowedExtensions,
},
ecdsaProfileName: {
Usage: []string{"digital signature", "server auth"},
@ -226,6 +235,7 @@ func setup(t *testing.T) *testCtx {
SignatureAlgorithm: true,
},
ClientProvidesSerialNumbers: true,
AllowedExtensions: allowedExtensions,
},
},
Default: &cfsslConfig.SigningProfile{
@ -276,10 +286,17 @@ type TestCertificateIssuance struct {
ca *CertificateAuthorityImpl
sa *mockSA
req *x509.CertificateRequest
mode IssuanceMode
certDER []byte
cert *x509.Certificate
}
type IssuanceMode struct {
name string
usePrecertificateFlow bool
enablePrecertificateFlow bool
}
func TestIssueCertificate(t *testing.T) {
testCases := []struct {
name string
@ -300,27 +317,58 @@ func TestIssueCertificate(t *testing.T) {
}
for _, testCase := range testCases {
ca, sa := testCase.setup(t)
t.Run(testCase.name, func(t *testing.T) {
req, err := x509.ParseCertificateRequest(testCase.csr)
test.AssertNotError(t, err, "Certificate request failed to parse")
for _, mode := range issuanceModes {
ca, sa := testCase.setup(t)
ca.enablePrecertificateFlow = mode.enablePrecertificateFlow
coreCert, err := ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: testCase.csr, RegistrationID: &arbitraryRegID})
test.AssertNotError(t, err, "Failed to issue certificate")
t.Run(mode.name+"-"+testCase.name, func(t *testing.T) {
req, err := x509.ParseCertificateRequest(testCase.csr)
test.AssertNotError(t, err, "Certificate request failed to parse")
cert, err := x509.ParseCertificate(coreCert.DER)
test.AssertNotError(t, err, "Certificate failed to parse")
issueReq := &caPB.IssueCertificateRequest{Csr: testCase.csr, RegistrationID: &arbitraryRegID}
i := TestCertificateIssuance{
ca: ca,
sa: sa,
req: req,
certDER: coreCert.DER,
cert: cert,
}
certDER := []byte{}
if !mode.usePrecertificateFlow {
coreCert, err := ca.IssueCertificate(ctx, issueReq)
test.AssertNotError(t, err, "Failed to issue certificate")
certDER = coreCert.DER
testCase.subTest(t, &i)
})
// Verify that the cert got stored in the DB
test.Assert(t, bytes.Equal(certDER, sa.certificate.DER), "Retrieved cert not equal to issued cert.")
} else {
response, err := ca.IssuePrecertificate(ctx, issueReq)
if !mode.enablePrecertificateFlow {
test.AssertError(t, err, "Precertificate flow not disabled as expected")
return
}
test.AssertNotError(t, err, "Failed to issue precertificate")
certDER = response.Precert.Der
}
cert, err := x509.ParseCertificate(certDER)
test.AssertNotError(t, err, "Certificate failed to parse")
poisonExtension := findExtension(cert.Extensions, OIDExtensionCTPoison)
test.AssertEquals(t, mode.usePrecertificateFlow, poisonExtension != nil)
if poisonExtension != nil {
test.AssertEquals(t, poisonExtension.Critical, true)
test.AssertDeepEquals(t, poisonExtension.Value, []byte{0x05, 0x00}) // ASN.1 DER NULL
}
i := TestCertificateIssuance{
ca: ca,
sa: sa,
req: req,
mode: mode,
certDER: certDER,
cert: cert,
}
testCase.subTest(t, &i)
})
}
}
}
@ -359,12 +407,10 @@ func issueCertificateSubTestIssueCertificate(t *testing.T, i *TestCertificateIss
t.Errorf("Subject contained unauthorized values: %v", cert.Subject)
}
// Verify that the cert got stored in the DB
serialString := core.SerialToString(cert.SerialNumber)
if cert.Subject.SerialNumber != serialString {
t.Errorf("SerialNumber: want %#v, got %#v", serialString, cert.Subject.SerialNumber)
}
test.Assert(t, bytes.Equal(i.certDER, i.sa.certificate.DER), "Retrieved cert not equal to issued cert.")
}
// Test issuing when multiple issuers are present.
@ -550,29 +596,43 @@ func TestInvalidCSRs(t *testing.T) {
}
for _, testCase := range testCases {
testCtx := setup(t)
sa := &mockSA{}
ca, err := NewCertificateAuthorityImpl(
testCtx.caConfig,
sa,
testCtx.pa,
testCtx.fc,
testCtx.stats,
testCtx.issuers,
testCtx.keyPolicy,
testCtx.logger)
test.AssertNotError(t, err, "Failed to create CA")
for _, mode := range issuanceModes {
testCtx := setup(t)
sa := &mockSA{}
ca, err := NewCertificateAuthorityImpl(
testCtx.caConfig,
sa,
testCtx.pa,
testCtx.fc,
testCtx.stats,
testCtx.issuers,
testCtx.keyPolicy,
testCtx.logger)
test.AssertNotError(t, err, "Failed to create CA")
ca.enablePrecertificateFlow = mode.usePrecertificateFlow
t.Run(testCase.name, func(t *testing.T) {
serializedCSR := mustRead(testCase.csrPath)
_, err = ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: serializedCSR, RegistrationID: &arbitraryRegID})
test.AssertError(t, err, testCase.errorMessage)
test.Assert(t, berrors.Is(err, berrors.Malformed), "Incorrect error type returned")
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 0)
if testCase.check != nil {
testCase.check(t, ca, sa)
}
})
t.Run(mode.name+"-"+testCase.name, func(t *testing.T) {
serializedCSR := mustRead(testCase.csrPath)
issueReq := &caPB.IssueCertificateRequest{Csr: serializedCSR, RegistrationID: &arbitraryRegID}
if !mode.usePrecertificateFlow {
_, err = ca.IssueCertificate(ctx, issueReq)
} else {
_, err = ca.IssuePrecertificate(ctx, issueReq)
}
test.Assert(t, berrors.Is(err, berrors.Malformed), "Incorrect error type returned")
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 0)
if mode.usePrecertificateFlow == mode.enablePrecertificateFlow {
test.AssertError(t, err, testCase.errorMessage)
if testCase.check != nil {
testCase.check(t, ca, sa)
}
} else {
test.AssertError(t, err, "Precertificate flow not disabled as expected")
}
})
}
}
}
@ -694,24 +754,29 @@ func issueCertificateSubTestUnknownExtension(t *testing.T, i *TestCertificateIss
// NOTE: The hard-coded value here will have to change over time as Boulder
// adds new (unrequested) extensions to certificates.
test.AssertEquals(t, len(i.cert.Extensions), 9)
expectedExtensionCount := 9
if i.mode.usePrecertificateFlow {
expectedExtensionCount += 1
}
test.AssertEquals(t, len(i.cert.Extensions), expectedExtensionCount)
}
func issueCertificateSubTestCTPoisonExtension(t *testing.T, i *TestCertificateIssuance) {
// The CT poison extension in the CSR should be silently ignored like an
// unknown extension, whether it has a valid or invalid value.
// unknown extension, whether it has a valid or invalid value. The check
// for whether or not the poison extension is present in the issued
// certificate/precertificate is done in the caller.
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionOther, i.ca.csrExtensionCount), 1)
test.AssertEquals(t, signatureCountByPurpose("cert", i.ca.signatureCount), 1)
test.Assert(t, !extensionPresent(i.cert.Extensions, OIDExtensionCTPoison), "CT poison extension is present")
}
func extensionPresent(extensions []pkix.Extension, id asn1.ObjectIdentifier) bool {
func findExtension(extensions []pkix.Extension, id asn1.ObjectIdentifier) *pkix.Extension {
for _, ext := range extensions {
if ext.Id.Equal(id) {
return true
return &ext
}
}
return false
return nil
}
func signatureCountByPurpose(signatureType string, signatureCount *prometheus.CounterVec) int {

View File

@ -10,6 +10,7 @@ It is generated from these files:
It has these top-level messages:
IssueCertificateRequest
IssuePrecertificateResponse
GenerateOCSPRequest
OCSPResponse
*/
@ -61,6 +62,31 @@ func (m *IssueCertificateRequest) GetRegistrationID() int64 {
return 0
}
type IssuePrecertificateResponse struct {
Precert *core.Precertificate `protobuf:"bytes,1,opt,name=precert" json:"precert,omitempty"`
SctFetchingConfig *core.SCTFetchingConfig `protobuf:"bytes,2,opt,name=sctFetchingConfig" json:"sctFetchingConfig,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *IssuePrecertificateResponse) Reset() { *m = IssuePrecertificateResponse{} }
func (m *IssuePrecertificateResponse) String() string { return proto1.CompactTextString(m) }
func (*IssuePrecertificateResponse) ProtoMessage() {}
func (*IssuePrecertificateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *IssuePrecertificateResponse) GetPrecert() *core.Precertificate {
if m != nil {
return m.Precert
}
return nil
}
func (m *IssuePrecertificateResponse) GetSctFetchingConfig() *core.SCTFetchingConfig {
if m != nil {
return m.SctFetchingConfig
}
return nil
}
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"`
@ -72,7 +98,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{1} }
func (*GenerateOCSPRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *GenerateOCSPRequest) GetCertDER() []byte {
if m != nil {
@ -110,7 +136,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{2} }
func (*OCSPResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *OCSPResponse) GetResponse() []byte {
if m != nil {
@ -121,6 +147,7 @@ func (m *OCSPResponse) GetResponse() []byte {
func init() {
proto1.RegisterType((*IssueCertificateRequest)(nil), "ca.IssueCertificateRequest")
proto1.RegisterType((*IssuePrecertificateResponse)(nil), "ca.IssuePrecertificateResponse")
proto1.RegisterType((*GenerateOCSPRequest)(nil), "ca.GenerateOCSPRequest")
proto1.RegisterType((*OCSPResponse)(nil), "ca.OCSPResponse")
}
@ -137,6 +164,7 @@ const _ = grpc.SupportPackageIsVersion4
type CertificateAuthorityClient interface {
IssueCertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*core.Certificate, error)
IssuePrecertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*IssuePrecertificateResponse, error)
}
type certificateAuthorityClient struct {
@ -156,10 +184,20 @@ func (c *certificateAuthorityClient) IssueCertificate(ctx context.Context, in *I
return out, nil
}
func (c *certificateAuthorityClient) IssuePrecertificate(ctx context.Context, in *IssueCertificateRequest, opts ...grpc.CallOption) (*IssuePrecertificateResponse, error) {
out := new(IssuePrecertificateResponse)
err := grpc.Invoke(ctx, "/ca.CertificateAuthority/IssuePrecertificate", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for CertificateAuthority service
type CertificateAuthorityServer interface {
IssueCertificate(context.Context, *IssueCertificateRequest) (*core.Certificate, error)
IssuePrecertificate(context.Context, *IssueCertificateRequest) (*IssuePrecertificateResponse, error)
}
func RegisterCertificateAuthorityServer(s *grpc.Server, srv CertificateAuthorityServer) {
@ -184,6 +222,24 @@ func _CertificateAuthority_IssueCertificate_Handler(srv interface{}, ctx context
return interceptor(ctx, in, info, handler)
}
func _CertificateAuthority_IssuePrecertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(IssueCertificateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CertificateAuthorityServer).IssuePrecertificate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ca.CertificateAuthority/IssuePrecertificate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CertificateAuthorityServer).IssuePrecertificate(ctx, req.(*IssueCertificateRequest))
}
return interceptor(ctx, in, info, handler)
}
var _CertificateAuthority_serviceDesc = grpc.ServiceDesc{
ServiceName: "ca.CertificateAuthority",
HandlerType: (*CertificateAuthorityServer)(nil),
@ -192,6 +248,10 @@ var _CertificateAuthority_serviceDesc = grpc.ServiceDesc{
MethodName: "IssueCertificate",
Handler: _CertificateAuthority_IssueCertificate_Handler,
},
{
MethodName: "IssuePrecertificate",
Handler: _CertificateAuthority_IssuePrecertificate_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "ca/proto/ca.proto",
@ -264,23 +324,27 @@ var _OCSPGenerator_serviceDesc = grpc.ServiceDesc{
func init() { proto1.RegisterFile("ca/proto/ca.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 276 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0xcd, 0x4b, 0xf3, 0x40,
0x10, 0xc6, 0x9b, 0xe6, 0xed, 0x5b, 0x3b, 0xc6, 0x9a, 0xac, 0x1f, 0x0d, 0xf1, 0x12, 0x72, 0xca,
0x29, 0x85, 0x5e, 0x05, 0xa1, 0x36, 0x22, 0x05, 0x41, 0xa9, 0x27, 0xc5, 0xcb, 0xb2, 0x8e, 0x1a,
0x84, 0x6c, 0x9d, 0x99, 0x08, 0xfe, 0xf7, 0x92, 0x8f, 0x42, 0x10, 0xbd, 0xcd, 0xf2, 0xf0, 0xfc,
0x76, 0x7e, 0x03, 0x81, 0xd1, 0xf3, 0x2d, 0x59, 0xb1, 0x73, 0xa3, 0xb3, 0x66, 0x50, 0x43, 0xa3,
0xa3, 0x13, 0x63, 0x09, 0x77, 0x81, 0x25, 0x6c, 0xa3, 0xe4, 0x02, 0x66, 0x6b, 0xe6, 0x0a, 0x57,
0x48, 0x52, 0xbc, 0x14, 0x46, 0x0b, 0x6e, 0xf0, 0xa3, 0x42, 0x16, 0xb5, 0x0f, 0xae, 0x61, 0x0a,
0x9d, 0xd8, 0x49, 0x3d, 0x75, 0x0a, 0x53, 0xc2, 0xd7, 0x82, 0x85, 0xb4, 0x14, 0xb6, 0x5c, 0xe7,
0xe1, 0x30, 0x76, 0x52, 0x37, 0x79, 0x80, 0xa3, 0x6b, 0x2c, 0x91, 0xb4, 0xe0, 0xed, 0xea, 0xfe,
0x6e, 0xd7, 0x3d, 0x84, 0xb1, 0x41, 0x92, 0xfc, 0x6a, 0xd3, 0xf5, 0xa7, 0xf0, 0x9f, 0x45, 0x4b,
0xc5, 0x4d, 0x6f, 0x52, 0xbf, 0x09, 0x35, 0xdb, 0x32, 0x74, 0x63, 0x27, 0x1d, 0xa9, 0x00, 0x26,
0x84, 0x9f, 0xf6, 0x1d, 0x9f, 0x97, 0x12, 0xfe, 0x6b, 0xd0, 0x31, 0x78, 0x2d, 0x92, 0xb7, 0xb6,
0x64, 0x54, 0x3e, 0xec, 0x51, 0x37, 0xb7, 0xd0, 0xc5, 0x13, 0x1c, 0xf7, 0xf6, 0x5e, 0x56, 0xf2,
0x66, 0xa9, 0x90, 0x2f, 0x95, 0x83, 0xff, 0x53, 0x4a, 0x9d, 0x65, 0x46, 0x67, 0x7f, 0xa8, 0x46,
0x41, 0xd6, 0x9c, 0xa4, 0x97, 0x24, 0x83, 0xc5, 0x0d, 0x1c, 0xd4, 0xff, 0x77, 0x7a, 0x96, 0xd4,
0x39, 0x78, 0x7d, 0x57, 0x35, 0xab, 0x91, 0xbf, 0xd8, 0x47, 0x7e, 0x1d, 0xf4, 0x77, 0x4f, 0x06,
0x97, 0xe3, 0xc7, 0x51, 0x73, 0xf1, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd4, 0x60, 0xcf, 0xa9,
0xa0, 0x01, 0x00, 0x00,
// 348 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0x41, 0x4f, 0xf2, 0x40,
0x10, 0x86, 0x29, 0x7c, 0x7c, 0xc8, 0x80, 0x48, 0x17, 0x94, 0x06, 0x0e, 0x36, 0x4d, 0x4c, 0x38,
0x95, 0xa4, 0x57, 0x13, 0x13, 0x2c, 0x6a, 0x48, 0x4c, 0x24, 0xa0, 0x07, 0xbd, 0x6d, 0xd6, 0x01,
0x1a, 0x93, 0x2e, 0xee, 0x4e, 0x8d, 0xfe, 0x2e, 0xff, 0xa0, 0xe9, 0xb6, 0x98, 0x62, 0xd0, 0xdb,
0x36, 0x6f, 0xf7, 0x99, 0x79, 0x9f, 0x16, 0x6c, 0xc1, 0x47, 0x1b, 0x25, 0x49, 0x8e, 0x04, 0xf7,
0xcd, 0x81, 0x95, 0x05, 0xef, 0x1f, 0x0b, 0xa9, 0x70, 0x1b, 0x48, 0x85, 0x59, 0xe4, 0x5d, 0x40,
0x6f, 0xaa, 0x75, 0x82, 0x21, 0x2a, 0x8a, 0x96, 0x91, 0xe0, 0x84, 0x73, 0x7c, 0x4d, 0x50, 0x13,
0x6b, 0x40, 0x45, 0x68, 0xe5, 0x58, 0xae, 0x35, 0x6c, 0xb2, 0x13, 0x68, 0x29, 0x5c, 0x45, 0x9a,
0x14, 0xa7, 0x48, 0xc6, 0xd3, 0x89, 0x53, 0x76, 0xad, 0x61, 0xc5, 0x7b, 0x87, 0x81, 0xb9, 0x3f,
0x53, 0x28, 0x8a, 0x08, 0xbd, 0x91, 0xb1, 0x46, 0x76, 0x06, 0xb5, 0x4d, 0x96, 0x18, 0x4e, 0x23,
0xe8, 0xfa, 0x66, 0xf8, 0xee, 0xeb, 0x2c, 0x00, 0x5b, 0x0b, 0xba, 0x46, 0x12, 0xeb, 0x28, 0x5e,
0x85, 0x32, 0x5e, 0x46, 0x2b, 0x33, 0xa0, 0x11, 0xf4, 0xb2, 0x0b, 0x8b, 0xf0, 0x7e, 0x37, 0xf6,
0x1e, 0xa1, 0x73, 0x83, 0x31, 0x2a, 0x4e, 0x78, 0x17, 0x2e, 0x66, 0xdb, 0xad, 0x8f, 0xa0, 0x96,
0x92, 0x27, 0x57, 0xf3, 0x7c, 0xf3, 0x16, 0xfc, 0xd7, 0xc4, 0x29, 0xd1, 0x06, 0x58, 0x4f, 0x9f,
0x15, 0x72, 0x2d, 0x63, 0xa7, 0xe2, 0x5a, 0xc3, 0x2a, 0xb3, 0xa1, 0xae, 0xf0, 0x4d, 0xbe, 0xe0,
0xf3, 0x98, 0x9c, 0x7f, 0xa6, 0x94, 0x0b, 0xcd, 0x0c, 0x99, 0xb7, 0x68, 0xc3, 0x81, 0xca, 0xcf,
0x19, 0x34, 0xf8, 0xb4, 0xa0, 0x5b, 0x50, 0x36, 0x4e, 0x68, 0x2d, 0x55, 0x44, 0x1f, 0x6c, 0x02,
0xed, 0x9f, 0x3e, 0xd9, 0xc0, 0x17, 0xdc, 0xff, 0xc5, 0x72, 0xdf, 0xce, 0xfa, 0x15, 0x12, 0xaf,
0xc4, 0x1e, 0xa0, 0xb3, 0xc7, 0xea, 0xdf, 0xa0, 0xd3, 0xef, 0x70, 0xff, 0xb7, 0xf0, 0x4a, 0xc1,
0x2d, 0x1c, 0xa6, 0xbd, 0x72, 0x6d, 0x52, 0xb1, 0x73, 0x68, 0x16, 0x1d, 0xb2, 0x5e, 0xca, 0xd8,
0x63, 0xb5, 0xdf, 0x4e, 0x83, 0xa2, 0x13, 0xaf, 0x74, 0x59, 0x7b, 0xaa, 0x9a, 0x7f, 0xe8, 0x2b,
0x00, 0x00, 0xff, 0xff, 0x0b, 0x4b, 0x68, 0xdb, 0x72, 0x02, 0x00, 0x00,
}

View File

@ -8,6 +8,7 @@ import "core/proto/core.proto";
// CertificateAuthority issues certificates.
service CertificateAuthority {
rpc IssueCertificate(IssueCertificateRequest) returns (core.Certificate) {}
rpc IssuePrecertificate(IssueCertificateRequest) returns (IssuePrecertificateResponse) {}
}
// OCSPGenerator generates OCSP. We separate this out from
@ -23,6 +24,11 @@ message IssueCertificateRequest {
optional int64 registrationID = 2;
}
message IssuePrecertificateResponse {
optional core.Precertificate precert = 1;
optional core.SCTFetchingConfig sctFetchingConfig = 2;
}
message GenerateOCSPRequest {
optional bytes certDER = 1;
optional string status = 2;

View File

@ -112,6 +112,10 @@ type CAConfig struct {
// triggers issuance of certificates with Must Staple.
EnableMustStaple bool
// EnablePrecertificateFlow governs whether precertificate-based issuance
// is enabled.
EnablePrecertificateFlow bool
// WeakKeyFile is the path to a JSON file containing truncated RSA modulus
// hashes of known easily enumerable keys.
WeakKeyFile string

View File

@ -38,6 +38,10 @@ func (ca *mockCA) IssueCertificate(_ context.Context, _ *caPB.IssueCertificateRe
return core.Certificate{}, nil
}
func (ca *mockCA) IssuePrecertificate(_ context.Context, _ *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error) {
return nil, errors.New("IssuePrecertificate is not implemented by mockCA")
}
func (ca *mockCA) GenerateOCSP(_ context.Context, xferObj core.OCSPSigningRequest) (ocsp []byte, err error) {
ocsp = []byte{1, 2, 3}
time.Sleep(ca.sleepTime)

View File

@ -84,6 +84,10 @@ type RegistrationAuthority interface {
type CertificateAuthority interface {
// [RegistrationAuthority]
IssueCertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest) (Certificate, error)
// [RegistrationAuthority]
IssuePrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error)
GenerateOCSP(ctx context.Context, ocspReq OCSPSigningRequest) ([]byte, error)
}

View File

@ -427,6 +427,12 @@ func (jb *JSONBuffer) UnmarshalJSON(data []byte) (err error) {
return
}
// Precertificate objects are entirely internal to the server. The only
// thing exposed on the wire is the precertificate itself.
type Precertificate struct {
DER []byte `db:"der"`
}
// Certificate objects are entirely internal to the server. The only
// thing exposed on the wire is the certificate itself.
type Certificate struct {

View File

@ -12,6 +12,9 @@ It has these top-level messages:
Challenge
ValidationRecord
ProblemDetails
Precertificate
SCTFetchingConfig
SCTFetchingLogSet
Certificate
Registration
Authorization
@ -208,6 +211,57 @@ func (m *ProblemDetails) GetHttpStatus() int32 {
return 0
}
type Precertificate struct {
Der []byte `protobuf:"bytes,1,opt,name=der" json:"der,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Precertificate) Reset() { *m = Precertificate{} }
func (m *Precertificate) String() string { return proto1.CompactTextString(m) }
func (*Precertificate) ProtoMessage() {}
func (*Precertificate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *Precertificate) GetDer() []byte {
if m != nil {
return m.Der
}
return nil
}
type SCTFetchingConfig struct {
LogSets []*SCTFetchingLogSet `protobuf:"bytes,1,rep,name=logSets" json:"logSets,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *SCTFetchingConfig) Reset() { *m = SCTFetchingConfig{} }
func (m *SCTFetchingConfig) String() string { return proto1.CompactTextString(m) }
func (*SCTFetchingConfig) ProtoMessage() {}
func (*SCTFetchingConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *SCTFetchingConfig) GetLogSets() []*SCTFetchingLogSet {
if m != nil {
return m.LogSets
}
return nil
}
type SCTFetchingLogSet struct {
LogURLs []string `protobuf:"bytes,1,rep,name=logURLs" json:"logURLs,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *SCTFetchingLogSet) Reset() { *m = SCTFetchingLogSet{} }
func (m *SCTFetchingLogSet) String() string { return proto1.CompactTextString(m) }
func (*SCTFetchingLogSet) ProtoMessage() {}
func (*SCTFetchingLogSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *SCTFetchingLogSet) GetLogURLs() []string {
if m != nil {
return m.LogURLs
}
return nil
}
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"`
@ -221,7 +275,7 @@ type Certificate struct {
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 (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *Certificate) GetRegistrationID() int64 {
if m != nil && m.RegistrationID != nil {
@ -280,7 +334,7 @@ type Registration struct {
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 (*Registration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *Registration) GetId() int64 {
if m != nil && m.Id != nil {
@ -352,7 +406,7 @@ type Authorization struct {
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 (*Authorization) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *Authorization) GetId() string {
if m != nil && m.Id != nil {
@ -410,12 +464,15 @@ type Empty struct {
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 (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func init() {
proto1.RegisterType((*Challenge)(nil), "core.Challenge")
proto1.RegisterType((*ValidationRecord)(nil), "core.ValidationRecord")
proto1.RegisterType((*ProblemDetails)(nil), "core.ProblemDetails")
proto1.RegisterType((*Precertificate)(nil), "core.Precertificate")
proto1.RegisterType((*SCTFetchingConfig)(nil), "core.SCTFetchingConfig")
proto1.RegisterType((*SCTFetchingLogSet)(nil), "core.SCTFetchingLogSet")
proto1.RegisterType((*Certificate)(nil), "core.Certificate")
proto1.RegisterType((*Registration)(nil), "core.Registration")
proto1.RegisterType((*Authorization)(nil), "core.Authorization")
@ -425,39 +482,43 @@ func init() {
func init() { proto1.RegisterFile("core/proto/core.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 530 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x93, 0xcd, 0x52, 0xdb, 0x30,
0x10, 0xc7, 0xc7, 0x28, 0x26, 0x78, 0x6d, 0x02, 0x71, 0x29, 0x55, 0x6f, 0x1e, 0x73, 0xc9, 0x09,
0xa6, 0xbc, 0x01, 0x85, 0x1e, 0xb8, 0x65, 0x52, 0xda, 0x43, 0x6f, 0xc2, 0xda, 0x26, 0x9a, 0x38,
0x96, 0x67, 0xb5, 0x61, 0x9a, 0x3e, 0x4a, 0xa7, 0xb7, 0x3e, 0x4a, 0x5f, 0xac, 0x23, 0xd9, 0x81,
0xa4, 0xdc, 0xa4, 0x5d, 0x69, 0x3f, 0x7e, 0xfb, 0x5f, 0x78, 0x5b, 0x59, 0xc2, 0xab, 0x96, 0x2c,
0xdb, 0x2b, 0x7f, 0xbc, 0x0c, 0xc7, 0x7c, 0xe0, 0xcf, 0xe5, 0xdf, 0x08, 0x92, 0xdb, 0x85, 0xaa,
0x6b, 0x6c, 0xe6, 0x98, 0x03, 0x1c, 0x18, 0x2d, 0xa3, 0x22, 0x9a, 0x88, 0x3c, 0x83, 0x01, 0x6f,
0x5a, 0x94, 0x07, 0x45, 0x34, 0x49, 0xf2, 0x11, 0x1c, 0x3a, 0x56, 0xbc, 0x76, 0xf2, 0x30, 0xdc,
0x53, 0x10, 0x6b, 0x32, 0x32, 0x09, 0x97, 0x63, 0x88, 0xd9, 0x2e, 0xb1, 0x91, 0x22, 0x5c, 0x25,
0x9c, 0x2e, 0x71, 0x73, 0xb3, 0xe6, 0x85, 0x25, 0xf3, 0x53, 0xb1, 0xb1, 0x8d, 0x8c, 0x83, 0xe7,
0x03, 0x8c, 0x9f, 0x54, 0x6d, 0x74, 0xb0, 0x11, 0x56, 0x96, 0xb4, 0x93, 0x50, 0x88, 0x49, 0x7a,
0x7d, 0x7e, 0x19, 0x6a, 0xfb, 0xfa, 0xec, 0x9e, 0x05, 0x77, 0x7e, 0x01, 0x31, 0x12, 0x59, 0x92,
0xc3, 0x22, 0x9a, 0xa4, 0xd7, 0x67, 0xdd, 0xb3, 0x29, 0xd9, 0xc7, 0x1a, 0x57, 0x77, 0xc8, 0xca,
0xd4, 0xae, 0xfc, 0x1d, 0xc1, 0xe9, 0xab, 0x9f, 0xa7, 0x70, 0xb4, 0xb0, 0x8e, 0x1b, 0xb5, 0xc2,
0xd0, 0x52, 0xe2, 0x5b, 0x6a, 0x2d, 0x71, 0xdf, 0xd2, 0x7b, 0x18, 0x2b, 0xad, 0x09, 0x9d, 0x43,
0x37, 0x43, 0x67, 0xeb, 0x27, 0xd4, 0x52, 0x14, 0x62, 0x92, 0xe5, 0x6f, 0x20, 0xed, 0x5d, 0x5f,
0x1c, 0x6a, 0x39, 0x28, 0xa2, 0xde, 0xd8, 0xf5, 0xc4, 0x06, 0x9d, 0x8c, 0x0b, 0xb1, 0xe5, 0x50,
0xf7, 0x50, 0xce, 0x61, 0xf4, 0x1c, 0xf1, 0x81, 0x0c, 0x6a, 0x39, 0xf4, 0xe1, 0xca, 0x7b, 0x18,
0xed, 0x17, 0xec, 0x63, 0xb5, 0x9d, 0xe5, 0xc1, 0x33, 0x8e, 0xb6, 0x8c, 0x75, 0xf0, 0xf7, 0x05,
0xe6, 0x00, 0x0b, 0xe6, 0xf6, 0x73, 0xc7, 0xdd, 0xb3, 0x8d, 0x4b, 0x07, 0xe9, 0x2d, 0x12, 0x9b,
0xef, 0xa6, 0x52, 0x8c, 0x3e, 0x23, 0xe1, 0xdc, 0x38, 0xa6, 0xd0, 0xf9, 0xfd, 0x5d, 0x3f, 0x3c,
0x3f, 0x2e, 0x24, 0xa3, 0xea, 0x97, 0xf1, 0x69, 0x33, 0x47, 0xc7, 0xfd, 0x88, 0x52, 0x10, 0x1a,
0xa9, 0x6f, 0x6c, 0x04, 0x87, 0xc6, 0xb9, 0x35, 0xea, 0x30, 0x25, 0x91, 0x9f, 0xc0, 0x10, 0x7f,
0xb4, 0x86, 0xb0, 0x1b, 0xb6, 0x28, 0x7f, 0x45, 0x90, 0xcd, 0x76, 0xd2, 0xec, 0xe9, 0x24, 0x05,
0xb1, 0xc4, 0x4d, 0xc8, 0x93, 0xf9, 0xaf, 0x95, 0x6d, 0x58, 0x55, 0x1c, 0x48, 0x26, 0xf9, 0x3b,
0x38, 0xe9, 0x0d, 0x6e, 0x4a, 0xe8, 0xb0, 0xe1, 0x90, 0xf4, 0x28, 0x1f, 0x43, 0xa2, 0xe6, 0x84,
0xb8, 0xf2, 0xa6, 0x4e, 0x1d, 0x63, 0x48, 0x4c, 0x63, 0xd8, 0xa8, 0xfa, 0x7e, 0x1a, 0x32, 0x67,
0xde, 0x54, 0x11, 0x2a, 0x46, 0x7d, 0xc3, 0x41, 0x01, 0x62, 0x47, 0x89, 0x47, 0xfe, 0x57, 0xf9,
0x27, 0x82, 0xe3, 0x3d, 0xad, 0xed, 0x54, 0x17, 0x18, 0x1a, 0x8d, 0x8d, 0x07, 0x86, 0xd4, 0xc3,
0x78, 0x0d, 0x4d, 0xfc, 0x17, 0x79, 0x10, 0xde, 0xed, 0x70, 0xe8, 0xc0, 0x5c, 0x00, 0x54, 0xdb,
0x5d, 0xf1, 0x6c, 0xbc, 0x6e, 0x4f, 0x3a, 0x41, 0xbe, 0xec, 0xd0, 0x19, 0x64, 0x95, 0x5d, 0x3d,
0x9a, 0x26, 0x04, 0x77, 0xa1, 0xea, 0xac, 0x1c, 0x42, 0xfc, 0x69, 0xd5, 0xf2, 0xe6, 0xe3, 0xf0,
0x5b, 0x1c, 0xf6, 0xef, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x47, 0x04, 0x32, 0x70, 0x97, 0x03,
0x00, 0x00,
// 596 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x94, 0xc1, 0x4e, 0xdb, 0x40,
0x10, 0x86, 0x65, 0x1c, 0x13, 0x3c, 0x31, 0x81, 0xb8, 0x14, 0xb6, 0x87, 0x4a, 0x96, 0xe9, 0x21,
0x27, 0x50, 0xb9, 0xf7, 0x40, 0x43, 0x2b, 0x21, 0x71, 0x40, 0x01, 0x7a, 0xe8, 0x6d, 0xf1, 0x0e,
0xce, 0x0a, 0xc7, 0x6b, 0xed, 0x4e, 0x50, 0xd3, 0x47, 0xa9, 0x7a, 0xeb, 0xa3, 0xf4, 0xc5, 0xaa,
0x1d, 0x3b, 0x90, 0x94, 0x9b, 0x77, 0x66, 0x67, 0xe6, 0xdf, 0x6f, 0xff, 0x35, 0xbc, 0x2d, 0x8c,
0xc5, 0xd3, 0xc6, 0x1a, 0x32, 0xa7, 0xfe, 0xf3, 0x84, 0x3f, 0xd3, 0x9e, 0xff, 0xce, 0xff, 0x06,
0x10, 0x4f, 0x66, 0xb2, 0xaa, 0xb0, 0x2e, 0x31, 0x05, 0xd8, 0xd2, 0x4a, 0x04, 0x59, 0x30, 0x0e,
0xd3, 0x04, 0x7a, 0xb4, 0x6c, 0x50, 0x6c, 0x65, 0xc1, 0x38, 0x4e, 0x87, 0xb0, 0xed, 0x48, 0xd2,
0xc2, 0x89, 0x6d, 0x5e, 0x0f, 0x20, 0x5c, 0x58, 0x2d, 0x62, 0x5e, 0xec, 0x42, 0x44, 0xe6, 0x11,
0x6b, 0x11, 0xf2, 0x52, 0xc0, 0xfe, 0x23, 0x2e, 0xcf, 0x17, 0x34, 0x33, 0x56, 0xff, 0x94, 0xa4,
0x4d, 0x2d, 0x22, 0xce, 0x7c, 0x84, 0xd1, 0x93, 0xac, 0xb4, 0xe2, 0x98, 0xc5, 0xc2, 0x58, 0xe5,
0x04, 0x64, 0xe1, 0x78, 0x70, 0x76, 0x78, 0xc2, 0xda, 0xbe, 0x3d, 0xa7, 0xa7, 0x9c, 0x4e, 0x8f,
0x21, 0x42, 0x6b, 0x8d, 0x15, 0xfd, 0x2c, 0x18, 0x0f, 0xce, 0x0e, 0xda, 0x6d, 0xd7, 0xd6, 0xdc,
0x57, 0x38, 0xbf, 0x40, 0x92, 0xba, 0x72, 0xf9, 0xef, 0x00, 0xf6, 0x5f, 0x55, 0xee, 0xc3, 0xce,
0xcc, 0x38, 0xaa, 0xe5, 0x1c, 0xf9, 0x48, 0xb1, 0x3f, 0x52, 0x63, 0x2c, 0x75, 0x47, 0x7a, 0x07,
0x23, 0xa9, 0x94, 0x45, 0xe7, 0xd0, 0x4d, 0xd1, 0x99, 0xea, 0x09, 0x95, 0x08, 0xb3, 0x70, 0x9c,
0xa4, 0x6f, 0x60, 0xd0, 0xa5, 0xee, 0x1c, 0x2a, 0xd1, 0xcb, 0x82, 0x2e, 0xd8, 0x9e, 0x89, 0x34,
0x3a, 0x11, 0x65, 0xe1, 0x8a, 0x43, 0xd5, 0x41, 0x39, 0x84, 0xe1, 0x73, 0xc7, 0x5b, 0xab, 0x51,
0x89, 0xbe, 0x6f, 0x97, 0x5f, 0xc2, 0x70, 0x53, 0xb0, 0xef, 0xd5, 0xb4, 0x91, 0x5b, 0xcf, 0x38,
0x58, 0x31, 0x56, 0x9c, 0xef, 0x04, 0xa6, 0x00, 0x33, 0xa2, 0xe6, 0xa6, 0xe5, 0xee, 0xd9, 0x46,
0xf9, 0x7b, 0xdf, 0x0a, 0x0b, 0xb4, 0xa4, 0x1f, 0x74, 0x21, 0x09, 0xbd, 0x02, 0x85, 0x96, 0x5b,
0x24, 0xf9, 0x27, 0x18, 0xdd, 0x4c, 0x6e, 0xbf, 0x22, 0x15, 0x33, 0x5d, 0x97, 0x13, 0x53, 0x3f,
0xe8, 0x32, 0x1d, 0x43, 0xbf, 0x32, 0xe5, 0x0d, 0x92, 0x13, 0x01, 0xb3, 0x3e, 0x6a, 0x21, 0xae,
0xed, 0xbc, 0xe2, 0x7c, 0xfe, 0x61, 0xa3, 0xbc, 0x0d, 0xa6, 0x7b, 0x5c, 0x7e, 0x37, 0xbd, 0x6a,
0xcb, 0xe3, 0xdc, 0xc1, 0x60, 0xb2, 0x26, 0xe0, 0x10, 0x86, 0x16, 0x4b, 0xed, 0xc8, 0x32, 0xfd,
0xcb, 0x8b, 0xce, 0x40, 0xde, 0x32, 0x68, 0xb5, 0xac, 0x5e, 0x2c, 0xa4, 0x74, 0x89, 0x8e, 0x3a,
0x9b, 0x74, 0xc2, 0x5b, 0xb8, 0x43, 0xd8, 0xd6, 0xce, 0x2d, 0x50, 0xb1, 0x53, 0x42, 0x3f, 0x14,
0x7f, 0x34, 0xda, 0x62, 0x6b, 0xb8, 0x30, 0xff, 0x15, 0x40, 0x32, 0x5d, 0x1b, 0xb3, 0xe1, 0xd5,
0x01, 0x84, 0x8f, 0xb8, 0xe4, 0x39, 0x89, 0x2f, 0x2d, 0x4c, 0x4d, 0xb2, 0x20, 0xbe, 0xcd, 0x38,
0x3d, 0x82, 0xbd, 0x2e, 0xe0, 0xae, 0x2d, 0x3a, 0xac, 0x89, 0x87, 0xee, 0xa4, 0x23, 0x88, 0x65,
0x69, 0x11, 0xe7, 0x3e, 0xd4, 0x3a, 0x74, 0x04, 0xb1, 0xae, 0x35, 0x69, 0x59, 0x5d, 0x5e, 0xf3,
0xe4, 0xc4, 0x87, 0x0a, 0x8b, 0x92, 0x50, 0x9d, 0x13, 0xbb, 0x30, 0x5c, 0x7b, 0x0d, 0x3b, 0xbe,
0x2a, 0xff, 0x13, 0xc0, 0xee, 0x86, 0xdf, 0xd7, 0xd4, 0xf1, 0x3d, 0x6a, 0x85, 0xb5, 0x07, 0x86,
0xb6, 0x83, 0xf1, 0x1a, 0x5a, 0xf8, 0x5f, 0xe7, 0x1e, 0xef, 0x5b, 0xe3, 0xd0, 0x82, 0x39, 0x06,
0x28, 0x56, 0xef, 0xd5, 0xb3, 0xf1, 0xf7, 0xb9, 0xd7, 0xde, 0xe7, 0xcb, 0x3b, 0x3e, 0x80, 0xa4,
0x30, 0xf3, 0x7b, 0x5d, 0x73, 0x73, 0xc7, 0xaa, 0x93, 0xbc, 0x0f, 0xd1, 0x97, 0x79, 0x43, 0xcb,
0xcf, 0xfd, 0xef, 0x11, 0xff, 0x03, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x1f, 0xc5, 0x5b, 0xb3,
0x1b, 0x04, 0x00, 0x00,
}

View File

@ -34,6 +34,18 @@ message ProblemDetails {
optional int32 httpStatus = 3;
}
message Precertificate {
optional bytes der = 1;
}
message SCTFetchingConfig {
repeated SCTFetchingLogSet logSets = 1;
}
message SCTFetchingLogSet {
repeated string logURLs = 1;
}
message Certificate {
optional int64 registrationID = 1;
optional string serial = 2;

View File

@ -44,6 +44,13 @@ func (cac CertificateAuthorityClientWrapper) IssueCertificate(ctx context.Contex
return pbToCert(res), nil
}
func (cac CertificateAuthorityClientWrapper) IssuePrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error) {
if cac.inner == nil {
return nil, errors.New("this CA client does not support issuing precertificates")
}
return cac.inner.IssuePrecertificate(ctx, issueReq)
}
func (cac CertificateAuthorityClientWrapper) GenerateOCSP(ctx context.Context, ocspReq core.OCSPSigningRequest) ([]byte, error) {
if cac.innerOCSP == nil {
return nil, errors.New("this CA client does not support generating OCSP")
@ -79,6 +86,10 @@ func (cas *CertificateAuthorityServerWrapper) IssueCertificate(ctx context.Conte
return certToPB(cert), nil
}
func (cas *CertificateAuthorityServerWrapper) IssuePrecertificate(ctx context.Context, request *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error) {
return cas.inner.IssuePrecertificate(ctx, request)
}
func (cas *CertificateAuthorityServerWrapper) GenerateOCSP(ctx context.Context, request *caPB.GenerateOCSPRequest) (*caPB.OCSPResponse, error) {
res, err := cas.inner.GenerateOCSP(ctx, core.OCSPSigningRequest{
CertDER: request.CertDER,

View File

@ -33,6 +33,11 @@ func (ca *MockCA) IssueCertificate(ctx context.Context, _ *caPB.IssueCertificate
}, nil
}
// IssuePrecertificate is a mock
func (ca *MockCA) IssuePrecertificate(ctx context.Context, _ *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error) {
return nil, fmt.Errorf("MockCA does not implement IssuePrecertificate")
}
// GenerateOCSP is a mock
func (ca *MockCA) GenerateOCSP(ctx context.Context, xferObj core.OCSPSigningRequest) (ocsp []byte, err error) {
return