Skip to content

Commit

Permalink
Submit final certs to CT logs (#3640)
Browse files Browse the repository at this point in the history
Submits final certificates to any configured CT logs. This doesn't introduce a feature flag as it is config gated, any log we want to submit final certificates to needs to have it's log description updated to include the `"submitFinalCerts": true` field.

Fixes #3605.
  • Loading branch information
Roland Bracewell Shoemaker authored and cpu committed Apr 13, 2018
1 parent 2a1cd49 commit 1271a15
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 28 deletions.
5 changes: 3 additions & 2 deletions cmd/config.go
Expand Up @@ -264,8 +264,9 @@ func (d *ConfigDuration) UnmarshalYAML(unmarshal func(interface{}) error) error
// LogDescription contains the information needed to submit certificates // LogDescription contains the information needed to submit certificates
// to a CT log and verify returned receipts // to a CT log and verify returned receipts
type LogDescription struct { type LogDescription struct {
URI string URI string
Key string Key string
SubmitFinalCert bool
} }


// GRPCClientConfig contains the information needed to talk to the gRPC service // GRPCClientConfig contains the information needed to talk to the gRPC service
Expand Down
36 changes: 36 additions & 0 deletions ctpolicy/ctpolicy.go
Expand Up @@ -20,15 +20,31 @@ type CTPolicy struct {
pub core.Publisher pub core.Publisher
groups []cmd.CTGroup groups []cmd.CTGroup
informational []cmd.LogDescription informational []cmd.LogDescription
finalLogs []cmd.LogDescription
log blog.Logger log blog.Logger
} }


// New creates a new CTPolicy struct // New creates a new CTPolicy struct
func New(pub core.Publisher, groups []cmd.CTGroup, informational []cmd.LogDescription, log blog.Logger) *CTPolicy { func New(pub core.Publisher, groups []cmd.CTGroup, informational []cmd.LogDescription, log blog.Logger) *CTPolicy {
var finalLogs []cmd.LogDescription
for _, group := range groups {
for _, log := range group.Logs {
if log.SubmitFinalCert {
finalLogs = append(finalLogs, log)
}
}
}
for _, log := range informational {
if log.SubmitFinalCert {
finalLogs = append(finalLogs, log)
}
}

return &CTPolicy{ return &CTPolicy{
pub: pub, pub: pub,
groups: groups, groups: groups,
informational: informational, informational: informational,
finalLogs: finalLogs,
log: log, log: log,
} }
} }
Expand Down Expand Up @@ -141,3 +157,23 @@ func (ctp *CTPolicy) GetSCTs(ctx context.Context, cert core.CertDER) (core.SCTDE
} }
return ret, nil return ret, nil
} }

// SubmitFinalCert submits finalized certificates created from precertificates
// to any configured logs
func (ctp *CTPolicy) SubmitFinalCert(cert []byte) {
falseVar := false
for _, log := range ctp.finalLogs {
go func(l cmd.LogDescription) {
_, err := ctp.pub.SubmitToSingleCTWithResult(context.Background(), &pubpb.Request{
LogURL: &l.URI,
LogPublicKey: &l.Key,
Der: cert,
Precert: &falseVar,
StoreSCT: &falseVar,
})
if err != nil {
ctp.log.Warning(fmt.Sprintf("ct submission of final cert to log %q failed: %s", l.URI, err))
}
}(log)
}
}
5 changes: 3 additions & 2 deletions grpc/publisher-wrappers.go
Expand Up @@ -75,6 +75,7 @@ func (pub *PublisherServerWrapper) SubmitToCT(ctx context.Context, request *pubp
return &pubpb.Empty{}, pub.inner.SubmitToCT(ctx, request.Der) return &pubpb.Empty{}, pub.inner.SubmitToCT(ctx, request.Der)
} }


// SubmitToSingleCT is a wrapper
func (pub *PublisherServerWrapper) SubmitToSingleCT(ctx context.Context, request *pubpb.Request) (*pubpb.Empty, error) { func (pub *PublisherServerWrapper) SubmitToSingleCT(ctx context.Context, request *pubpb.Request) (*pubpb.Empty, error) {
if request == nil || request.Der == nil || request.LogURL == nil || request.LogPublicKey == nil { if request == nil || request.Der == nil || request.LogURL == nil || request.LogPublicKey == nil {
return nil, errors.New("incomplete SubmitToSingleCT gRPC message") return nil, errors.New("incomplete SubmitToSingleCT gRPC message")
Expand All @@ -84,9 +85,9 @@ func (pub *PublisherServerWrapper) SubmitToSingleCT(ctx context.Context, request
} }


// SubmitToSingleCTWithResult is a wrapper // SubmitToSingleCTWithResult is a wrapper
func (pc *PublisherServerWrapper) SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Request) (*pubpb.Result, error) { func (pub *PublisherServerWrapper) SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Request) (*pubpb.Result, error) {
if req == nil || req.Der == nil || req.LogURL == nil || req.LogPublicKey == nil { if req == nil || req.Der == nil || req.LogURL == nil || req.LogPublicKey == nil {
return nil, errIncompleteRequest return nil, errIncompleteRequest
} }
return pc.inner.SubmitToSingleCTWithResult(ctx, req) return pub.inner.SubmitToSingleCTWithResult(ctx, req)
} }
39 changes: 24 additions & 15 deletions publisher/proto/publisher.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion publisher/proto/publisher.proto
Expand Up @@ -11,11 +11,13 @@ message Request {
optional string LogURL = 2; optional string LogURL = 2;
optional string LogPublicKey = 3; optional string LogPublicKey = 3;
optional bool precert = 4; optional bool precert = 4;
optional bool storeSCT = 5;
} }


message Result { message Result {
optional bytes sct = 1; optional bytes sct = 1;
} }


message Empty { message Empty {
} }

14 changes: 11 additions & 3 deletions publisher/publisher.go
Expand Up @@ -228,10 +228,19 @@ func (pub *Impl) SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Requ
isPrecert = *req.Precert isPrecert = *req.Precert
} }


// Historically if a cert wasn't a precert we wanted to store the SCT,
// but for SCTs for final certificates generated from precerts we don't
// want to store those SCTs.
storeSCT := !isPrecert
if req.StoreSCT != nil {
storeSCT = *req.StoreSCT
}

sct, err := pub.singleLogSubmit( sct, err := pub.singleLogSubmit(
ctx, ctx,
chain, chain,
isPrecert, isPrecert,
storeSCT,
core.SerialToString(cert.SerialNumber), core.SerialToString(cert.SerialNumber),
ctLog) ctLog)
if err != nil { if err != nil {
Expand Down Expand Up @@ -273,6 +282,7 @@ func (pub *Impl) singleLogSubmit(
ctx context.Context, ctx context.Context,
chain []ct.ASN1Cert, chain []ct.ASN1Cert,
isPrecert bool, isPrecert bool,
storeSCT bool,
serial string, serial string,
ctLog *Log, ctLog *Log,
) (*ct.SignedCertificateTimestamp, error) { ) (*ct.SignedCertificateTimestamp, error) {
Expand Down Expand Up @@ -326,9 +336,7 @@ func (pub *Impl) singleLogSubmit(
return nil, fmt.Errorf("SCT Timestamp was too far in the past (%s)", timestamp) return nil, fmt.Errorf("SCT Timestamp was too far in the past (%s)", timestamp)
} }


// Only store the SCT if it was for a certificate, we have no need for if storeSCT {
// the precert once it is embedded in a certificate
if !isPrecert {
err = pub.sa.AddSCTReceipt(ctx, sctToInternal(sct, serial)) err = pub.sa.AddSCTReceipt(ctx, sctToInternal(sct, serial))
if err != nil { if err != nil {
return nil, err return nil, err
Expand Down
2 changes: 2 additions & 0 deletions ra/ra.go
Expand Up @@ -1114,6 +1114,8 @@ func (ra *RegistrationAuthorityImpl) issueCertificateInner(
if err != nil { if err != nil {
return emptyCert, wrapError(err, "issuing certificate for precertificate") return emptyCert, wrapError(err, "issuing certificate for precertificate")
} }
// Asynchronously submit the final certificate to any configured logs
go ra.ctpolicy.SubmitFinalCert(cert.DER)
} else { } else {
cert, err = ra.CA.IssueCertificate(ctx, issueReq) cert, err = ra.CA.IssueCertificate(ctx, issueReq)
if err != nil { if err != nil {
Expand Down
15 changes: 10 additions & 5 deletions test/config-next/ra.json
Expand Up @@ -62,11 +62,13 @@
"logs": [ "logs": [
{ {
"uri": "http://boulder:4500", "uri": "http://boulder:4500",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYggOxPnPkzKBIhTacSYoIfnSL2jPugcbUKx83vFMvk5gKAz/AGe87w20riuPwEGn229hKVbEKHFB61NIqNHC3Q==" "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYggOxPnPkzKBIhTacSYoIfnSL2jPugcbUKx83vFMvk5gKAz/AGe87w20riuPwEGn229hKVbEKHFB61NIqNHC3Q==",
"submitFinalCert": true
}, },
{ {
"uri": "http://boulder:4501", "uri": "http://boulder:4501",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKtnFevaXV/kB8dmhCNZHmxKVLcHX1plaAsY9LrKilhYxdmQZiu36LvAvosTsqMVqRK9a96nC8VaxAdaHUbM8EA==" "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKtnFevaXV/kB8dmhCNZHmxKVLcHX1plaAsY9LrKilhYxdmQZiu36LvAvosTsqMVqRK9a96nC8VaxAdaHUbM8EA==",
"submitFinalCert": true
} }
] ]
}, },
Expand All @@ -75,19 +77,22 @@
"logs": [ "logs": [
{ {
"uri": "http://boulder:4510", "uri": "http://boulder:4510",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyw1HymhJkuxSIgt3gqW3sVXqMqB3EFsXcMfPFo0vYwjNiRmCJDXKsR0Flp7MAK+wc3X/7Hpc8liUbMhPet7tEA==" "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyw1HymhJkuxSIgt3gqW3sVXqMqB3EFsXcMfPFo0vYwjNiRmCJDXKsR0Flp7MAK+wc3X/7Hpc8liUbMhPet7tEA==",
"submitFinalCert": true
}, },
{ {
"uri": "http://boulder:4511", "uri": "http://boulder:4511",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg==" "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg==",
"submitFinalCert": true
} }
] ]
} }
], ],
"InformationalCTLogs": [ "InformationalCTLogs": [
{ {
"uri": "http://boulder:4512", "uri": "http://boulder:4512",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg==" "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg==",
"submitFinalCert": true
} }
] ]
}, },
Expand Down

0 comments on commit 1271a15

Please sign in to comment.