Add precert submission changes to ct-test-serv and boulder-publisher

This commit is contained in:
Roland Bracewell Shoemaker 2018-03-08 02:46:26 +00:00
parent b82c06d874
commit 7077740875
4 changed files with 94 additions and 42 deletions

View File

@ -39,6 +39,7 @@ type Request struct {
Der []byte `protobuf:"bytes,1,opt,name=der" json:"der,omitempty"`
LogURL *string `protobuf:"bytes,2,opt,name=LogURL,json=logURL" json:"LogURL,omitempty"`
LogPublicKey *string `protobuf:"bytes,3,opt,name=LogPublicKey,json=logPublicKey" json:"LogPublicKey,omitempty"`
Precert *bool `protobuf:"varint,4,opt,name=precert" json:"precert,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -68,6 +69,13 @@ func (m *Request) GetLogPublicKey() string {
return ""
}
func (m *Request) GetPrecert() bool {
if m != nil && m.Precert != nil {
return *m.Precert
}
return false
}
type Result struct {
Sct []byte `protobuf:"bytes,1,opt,name=sct" json:"sct,omitempty"`
XXX_unrecognized []byte `json:"-"`
@ -241,18 +249,19 @@ var _Publisher_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("publisher.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 207 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2f, 0x28, 0x4d, 0xca,
0xc9, 0x2c, 0xce, 0x48, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x0a, 0xe7, 0x62, 0x0f,
0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe0, 0x62, 0x4e, 0x49, 0x2d, 0x92, 0x60, 0x54,
0x60, 0xd4, 0xe0, 0x09, 0x02, 0x31, 0x85, 0xc4, 0xb8, 0xd8, 0x7c, 0xf2, 0xd3, 0x43, 0x83, 0x7c,
0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x83, 0xd8, 0x72, 0xc0, 0x3c, 0x21, 0x25, 0x2e, 0x1e, 0x9f,
0xfc, 0xf4, 0x00, 0x90, 0x51, 0xc9, 0xde, 0xa9, 0x95, 0x12, 0xcc, 0x60, 0x59, 0x9e, 0x1c, 0x24,
0x31, 0x25, 0x29, 0x2e, 0xb6, 0xa0, 0xd4, 0xe2, 0xd2, 0x1c, 0xb0, 0xb9, 0xc5, 0xc9, 0x25, 0x30,
0x73, 0x8b, 0x93, 0x4b, 0x94, 0xd8, 0xb9, 0x58, 0x5d, 0x73, 0x0b, 0x4a, 0x2a, 0x8d, 0x3a, 0x18,
0xb9, 0x38, 0x03, 0x60, 0x2e, 0x12, 0x52, 0xe0, 0xe2, 0x0a, 0x2e, 0x4d, 0xca, 0xcd, 0x2c, 0x09,
0xc9, 0x77, 0x0e, 0x11, 0xe2, 0xd0, 0x83, 0x3a, 0x4c, 0x8a, 0x4d, 0x0f, 0xac, 0x5a, 0x89, 0x41,
0x48, 0x8d, 0x4b, 0x00, 0xa6, 0x22, 0x38, 0x33, 0x2f, 0x3d, 0x27, 0x15, 0x87, 0x3a, 0x43, 0x2e,
0x29, 0x74, 0x75, 0xe1, 0x99, 0x25, 0x19, 0x50, 0x07, 0x21, 0x74, 0xb0, 0xeb, 0x41, 0x84, 0x94,
0x18, 0x00, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x2a, 0x83, 0x37, 0x1a, 0x01, 0x00, 0x00,
// 224 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x8e, 0x41, 0x4b, 0x03, 0x31,
0x10, 0x85, 0x1b, 0xab, 0xbb, 0xed, 0xb0, 0x60, 0xc9, 0x41, 0xc2, 0x9e, 0x96, 0x1c, 0x64, 0x4f,
0x0b, 0xfa, 0x17, 0xc4, 0x93, 0x7b, 0x28, 0x69, 0xc5, 0x7b, 0xe3, 0xb0, 0x0d, 0xa4, 0x26, 0x4d,
0x26, 0x87, 0xfe, 0x03, 0x7f, 0xb6, 0x34, 0x36, 0x28, 0x82, 0xb7, 0x79, 0x6f, 0xbe, 0x99, 0xf7,
0xe0, 0xd6, 0xa7, 0x9d, 0x35, 0x71, 0x8f, 0x61, 0xf0, 0xc1, 0x91, 0x93, 0x47, 0xa8, 0x15, 0x1e,
0x13, 0x46, 0xe2, 0x2b, 0x98, 0xbf, 0x63, 0x10, 0xac, 0x63, 0x7d, 0xa3, 0xce, 0x23, 0xbf, 0x83,
0x6a, 0x74, 0xd3, 0xab, 0x1a, 0xc5, 0x55, 0xc7, 0xfa, 0xa5, 0xaa, 0x6c, 0x56, 0x5c, 0x42, 0x33,
0xba, 0x69, 0x7d, 0x7e, 0xa5, 0x5f, 0xf0, 0x24, 0xe6, 0x79, 0xdb, 0xd8, 0x5f, 0x1e, 0x17, 0x50,
0xfb, 0x80, 0x1a, 0x03, 0x89, 0xeb, 0x8e, 0xf5, 0x0b, 0x55, 0xa4, 0x6c, 0xa1, 0x52, 0x18, 0x93,
0xcd, 0x89, 0x51, 0x53, 0x49, 0x8c, 0x9a, 0x64, 0x0d, 0x37, 0xcf, 0x07, 0x4f, 0xa7, 0xc7, 0x4f,
0x06, 0xcb, 0x75, 0xe9, 0xca, 0x3b, 0x80, 0x4d, 0xda, 0x1d, 0x0c, 0x6d, 0xdd, 0xd3, 0x96, 0x2f,
0x86, 0x4b, 0xe5, 0xb6, 0x1a, 0x32, 0x2d, 0x67, 0xfc, 0x1e, 0x56, 0x85, 0xd8, 0x98, 0x8f, 0xc9,
0xe2, 0x3f, 0xdc, 0x03, 0xb4, 0x7f, 0xb9, 0x37, 0x43, 0xfb, 0x4b, 0xa1, 0x9f, 0x8b, 0x7a, 0xf8,
0xb6, 0xe4, 0xec, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x6e, 0xb0, 0x3d, 0x34, 0x01, 0x00, 0x00,
}

View File

@ -10,6 +10,7 @@ message Request {
optional bytes der = 1;
optional string LogURL = 2;
optional string LogPublicKey = 3;
optional bool precert = 4;
}
message Result {

View File

@ -1,6 +1,7 @@
package publisher
import (
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"fmt"
@ -10,10 +11,11 @@ import (
"sync"
"time"
ct "github.com/google/certificate-transparency-go"
"github.com/google/certificate-transparency-go"
ctClient "github.com/google/certificate-transparency-go/client"
"github.com/google/certificate-transparency-go/jsonclient"
"github.com/google/certificate-transparency-go/tls"
ctx509 "github.com/google/certificate-transparency-go/x509"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
@ -216,9 +218,15 @@ func (pub *Impl) SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Requ
return nil, err
}
isPrecert := false
if req.Precert != nil && *req.Precert {
isPrecert = true
}
sct, err := pub.singleLogSubmit(
ctx,
chain,
isPrecert,
core.SerialToString(cert.SerialNumber),
ctLog)
if err != nil {
@ -259,11 +267,18 @@ func (pub *Impl) SubmitToCT(ctx context.Context, der []byte) error {
func (pub *Impl) singleLogSubmit(
ctx context.Context,
chain []ct.ASN1Cert,
isPrecert bool,
serial string,
ctLog *Log) (*ct.SignedCertificateTimestamp, error) {
ctLog *Log,
) (*ct.SignedCertificateTimestamp, error) {
var submissionMethod func(context.Context, []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error)
submissionMethod = ctLog.client.AddChain
if isPrecert {
submissionMethod = ctLog.client.AddPreChain
}
start := time.Now()
sct, err := ctLog.client.AddChain(ctx, chain)
sct, err := submissionMethod(ctx, chain)
took := time.Since(start).Seconds()
if err != nil {
status := "error"
@ -281,15 +296,30 @@ func (pub *Impl) singleLogSubmit(
"status": "success",
}).Observe(took)
err = ctLog.verifier.VerifySCTSignature(*sct, ct.LogEntry{
Leaf: ct.MerkleTreeLeaf{
LeafType: ct.TimestampedEntryLeafType,
TimestampedEntry: &ct.TimestampedEntry{
X509Entry: &chain[0],
EntryType: ct.X509LogEntryType,
input := ct.LogEntry{Leaf: ct.MerkleTreeLeaf{LeafType: ct.TimestampedEntryLeafType}}
if isPrecert {
tbsCert, err := ctx509.BuildPrecertTBS(chain[0].Data, nil)
if err != nil {
return nil, err
}
issuer, err := x509.ParseCertificate(chain[1].Data)
if err != nil {
return nil, err
}
input.Leaf.TimestampedEntry = &ct.TimestampedEntry{
PrecertEntry: &ct.PreCert{
IssuerKeyHash: sha256.Sum256(issuer.RawSubjectPublicKeyInfo),
TBSCertificate: tbsCert,
},
},
})
EntryType: ct.PrecertLogEntryType,
}
} else {
input.Leaf.TimestampedEntry = &ct.TimestampedEntry{
X509Entry: &chain[0],
EntryType: ct.X509LogEntryType,
}
}
err = ctLog.verifier.VerifySCTSignature(*sct, input)
if err != nil {
return nil, err
}

View File

@ -26,23 +26,34 @@ import (
"github.com/letsencrypt/boulder/cmd"
)
func createSignedSCT(leaf []byte, k *ecdsa.PrivateKey) []byte {
func createSignedSCT(req []string, k *ecdsa.PrivateKey, precert bool) []byte {
rawKey, _ := x509.MarshalPKIXPublicKey(&k.PublicKey)
pkHash := sha256.Sum256(rawKey)
sct := ct.SignedCertificateTimestamp{
SCTVersion: ct.V1,
LogID: ct.LogID{KeyID: pkHash},
Timestamp: 1337,
Timestamp: uint64(time.Now().Unix()),
}
serialized, _ := ct.SerializeSCTSignatureInput(sct, ct.LogEntry{
Leaf: ct.MerkleTreeLeaf{
LeafType: ct.TimestampedEntryLeafType,
TimestampedEntry: &ct.TimestampedEntry{
X509Entry: &ct.ASN1Cert{Data: leaf},
EntryType: ct.X509LogEntryType,
},
},
})
chain := make([]ct.ASN1Cert, len(req))
for i, str := range req {
b, err := base64.StdEncoding.DecodeString(str)
if err != nil {
panic("cannot decode chain")
}
chain[i] = ct.ASN1Cert{Data: b}
}
etype := ct.X509LogEntryType
if precert {
etype = ct.PrecertLogEntryType
}
leaf, err := ct.MerkleTreeLeafFromRawChain(chain, etype, sct.Timestamp)
if err != nil {
panic("failed to create leaf")
}
serialized, _ := ct.SerializeSCTSignatureInput(sct, ct.LogEntry{Leaf: *leaf})
hashed := sha256.Sum256(serialized)
var ecdsaSig struct {
R, S *big.Int
@ -67,7 +78,7 @@ func createSignedSCT(leaf []byte, k *ecdsa.PrivateKey) []byte {
}
jsonSCTObj.SCTVersion = ct.V1
jsonSCTObj.ID = base64.StdEncoding.EncodeToString(pkHash[:])
jsonSCTObj.Timestamp = 1337
jsonSCTObj.Timestamp = sct.Timestamp
jsonSCTObj.Signature, _ = ds.Base64String()
jsonSCT, _ := json.Marshal(jsonSCTObj)
@ -88,6 +99,8 @@ type integrationSrv struct {
func (is *integrationSrv) handler(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/ct/v1/add-pre-chain":
fallthrough
case "/ct/v1/add-chain":
if r.Method != "POST" {
http.NotFound(w, r)
@ -117,14 +130,13 @@ func (is *integrationSrv) handler(w http.ResponseWriter, r *http.Request) {
return
}
leaf, err := base64.StdEncoding.DecodeString(addChainReq.Chain[0])
if err != nil {
w.WriteHeader(400)
return
precert := false
if r.URL.Path == "/ct/v1/add-pre-chain" {
precert = true
}
w.WriteHeader(http.StatusOK)
w.Write(createSignedSCT(leaf, is.key))
w.Write(createSignedSCT(addChainReq.Chain, is.key, precert))
case "/submissions":
if r.Method != "GET" {
http.NotFound(w, r)