Skip to content
Permalink
Browse files

Submit final certs to CT logs (#3640)

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...
rolandshoemaker authored and cpu committed Apr 13, 2018
1 parent 2a1cd49 commit 1271a15be79b9717ee5b98e707b76e7ac86a9a0e
@@ -264,8 +264,9 @@ func (d *ConfigDuration) UnmarshalYAML(unmarshal func(interface{}) error) error
// LogDescription contains the information needed to submit certificates
// to a CT log and verify returned receipts
type LogDescription struct {
URI string
Key string
URI string
Key string
SubmitFinalCert bool
}

// GRPCClientConfig contains the information needed to talk to the gRPC service
@@ -20,15 +20,31 @@ type CTPolicy struct {
pub core.Publisher
groups []cmd.CTGroup
informational []cmd.LogDescription
finalLogs []cmd.LogDescription
log blog.Logger
}

// New creates a new CTPolicy struct
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{
pub: pub,
groups: groups,
informational: informational,
finalLogs: finalLogs,
log: log,
}
}
@@ -141,3 +157,23 @@ func (ctp *CTPolicy) GetSCTs(ctx context.Context, cert core.CertDER) (core.SCTDE
}
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)
}
}
@@ -75,6 +75,7 @@ func (pub *PublisherServerWrapper) SubmitToCT(ctx context.Context, request *pubp
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) {
if request == nil || request.Der == nil || request.LogURL == nil || request.LogPublicKey == nil {
return nil, errors.New("incomplete SubmitToSingleCT gRPC message")
@@ -84,9 +85,9 @@ func (pub *PublisherServerWrapper) SubmitToSingleCT(ctx context.Context, request
}

// 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 {
return nil, errIncompleteRequest
}
return pc.inner.SubmitToSingleCTWithResult(ctx, req)
return pub.inner.SubmitToSingleCTWithResult(ctx, req)
}

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -11,11 +11,13 @@ message Request {
optional string LogURL = 2;
optional string LogPublicKey = 3;
optional bool precert = 4;
optional bool storeSCT = 5;
}

message Result {
optional bytes sct = 1;
}

message Empty {
}
}

@@ -228,10 +228,19 @@ func (pub *Impl) SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Requ
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(
ctx,
chain,
isPrecert,
storeSCT,
core.SerialToString(cert.SerialNumber),
ctLog)
if err != nil {
@@ -273,6 +282,7 @@ func (pub *Impl) singleLogSubmit(
ctx context.Context,
chain []ct.ASN1Cert,
isPrecert bool,
storeSCT bool,
serial string,
ctLog *Log,
) (*ct.SignedCertificateTimestamp, error) {
@@ -326,9 +336,7 @@ func (pub *Impl) singleLogSubmit(
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
// the precert once it is embedded in a certificate
if !isPrecert {
if storeSCT {
err = pub.sa.AddSCTReceipt(ctx, sctToInternal(sct, serial))
if err != nil {
return nil, err
@@ -1114,6 +1114,8 @@ func (ra *RegistrationAuthorityImpl) issueCertificateInner(
if err != nil {
return emptyCert, wrapError(err, "issuing certificate for precertificate")
}
// Asynchronously submit the final certificate to any configured logs
go ra.ctpolicy.SubmitFinalCert(cert.DER)
} else {
cert, err = ra.CA.IssueCertificate(ctx, issueReq)
if err != nil {
@@ -62,11 +62,13 @@
"logs": [
{
"uri": "http://boulder:4500",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYggOxPnPkzKBIhTacSYoIfnSL2jPugcbUKx83vFMvk5gKAz/AGe87w20riuPwEGn229hKVbEKHFB61NIqNHC3Q=="
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYggOxPnPkzKBIhTacSYoIfnSL2jPugcbUKx83vFMvk5gKAz/AGe87w20riuPwEGn229hKVbEKHFB61NIqNHC3Q==",
"submitFinalCert": true
},
{
"uri": "http://boulder:4501",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKtnFevaXV/kB8dmhCNZHmxKVLcHX1plaAsY9LrKilhYxdmQZiu36LvAvosTsqMVqRK9a96nC8VaxAdaHUbM8EA=="
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKtnFevaXV/kB8dmhCNZHmxKVLcHX1plaAsY9LrKilhYxdmQZiu36LvAvosTsqMVqRK9a96nC8VaxAdaHUbM8EA==",
"submitFinalCert": true
}
]
},
@@ -75,19 +77,22 @@
"logs": [
{
"uri": "http://boulder:4510",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyw1HymhJkuxSIgt3gqW3sVXqMqB3EFsXcMfPFo0vYwjNiRmCJDXKsR0Flp7MAK+wc3X/7Hpc8liUbMhPet7tEA=="
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyw1HymhJkuxSIgt3gqW3sVXqMqB3EFsXcMfPFo0vYwjNiRmCJDXKsR0Flp7MAK+wc3X/7Hpc8liUbMhPet7tEA==",
"submitFinalCert": true
},
{
"uri": "http://boulder:4511",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg=="
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg==",
"submitFinalCert": true
}
]
}
],
"InformationalCTLogs": [
{
"uri": "http://boulder:4512",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg=="
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFRu37ZRLg8lT4rVQwMwh4oAOpXb4Sx+9hgQ+JFCjmAv3oDV+sDOMsC7hULkGTn+LB5L1SRo/XIY4Kw5V+nFXgg==",
"submitFinalCert": true
}
]
},

0 comments on commit 1271a15

Please sign in to comment.
You can’t perform that action at this time.