// SubmitToCT will submit the certificate represented by certDER to any CT // logs configured in pub.CT.Logs func (pub *PublisherImpl) SubmitToCT(der []byte) error { cert, err := x509.ParseCertificate(der) if err != nil { pub.log.Audit(fmt.Sprintf("Failed to parse certificate: %s", err)) return err } chain := append([]ct.ASN1Cert{der}, pub.issuerBundle...) for _, ctLog := range pub.ctLogs { sct, err := ctLog.client.AddChain(chain) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 pub.log.Audit(fmt.Sprintf("Failed to submit certificate to CT log: %s", err)) continue } err = ctLog.verifier.VerifySCTSignature(*sct, ct.LogEntry{ Leaf: ct.MerkleTreeLeaf{ LeafType: ct.TimestampedEntryLeafType, TimestampedEntry: ct.TimestampedEntry{ X509Entry: ct.ASN1Cert(der), EntryType: ct.X509LogEntryType, }, }, }) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 pub.log.Audit(fmt.Sprintf("Failed to verify SCT receipt: %s", err)) continue } internalSCT, err := sctToInternal(sct, core.SerialToString(cert.SerialNumber)) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 pub.log.Audit(fmt.Sprintf("Failed to convert SCT receipt: %s", err)) continue } err = pub.SA.AddSCTReceipt(internalSCT) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 pub.log.Audit(fmt.Sprintf("Failed to store SCT receipt in database: %s", err)) continue } } return nil }
func setup(t *testing.T) (*PublisherImpl, *x509.Certificate, *ecdsa.PrivateKey) { intermediatePEM, _ := pem.Decode([]byte(testIntermediate)) pub := NewPublisherImpl(nil, nil) pub.issuerBundle = append(pub.issuerBundle, ct.ASN1Cert(intermediatePEM.Bytes)) pub.SA = mocks.NewStorageAuthority(clock.NewFake()) leafPEM, _ := pem.Decode([]byte(testLeaf)) leaf, err := x509.ParseCertificate(leafPEM.Bytes) test.AssertNotError(t, err, "Couldn't parse leafPEM.Bytes") k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) test.AssertNotError(t, err, "Couldn't generate test key") return &pub, leaf, k }
func createSignedSCT(leaf []byte, k *ecdsa.PrivateKey) string { rawKey, _ := x509.MarshalPKIXPublicKey(&k.PublicKey) pkHash := sha256.Sum256(rawKey) sct := ct.SignedCertificateTimestamp{ SCTVersion: ct.V1, LogID: pkHash, Timestamp: 1337, } serialized, _ := ct.SerializeSCTSignatureInput(sct, ct.LogEntry{ Leaf: ct.MerkleTreeLeaf{ LeafType: ct.TimestampedEntryLeafType, TimestampedEntry: ct.TimestampedEntry{ X509Entry: ct.ASN1Cert(leaf), EntryType: ct.X509LogEntryType, }, }, }) hashed := sha256.Sum256(serialized) var ecdsaSig struct { R, S *big.Int } ecdsaSig.R, ecdsaSig.S, _ = ecdsa.Sign(rand.Reader, k, hashed[:]) sig, _ := asn1.Marshal(ecdsaSig) ds := ct.DigitallySigned{ HashAlgorithm: ct.SHA256, SignatureAlgorithm: ct.ECDSA, Signature: sig, } var jsonSCTObj struct { SCTVersion ct.Version `json:"sct_version"` ID string `json:"id"` Timestamp uint64 `json:"timestamp"` Extensions string `json:"extensions"` Signature string `json:"signature"` } jsonSCTObj.SCTVersion = ct.V1 jsonSCTObj.ID = base64.StdEncoding.EncodeToString(pkHash[:]) jsonSCTObj.Timestamp = 1337 jsonSCTObj.Signature, _ = ds.Base64String() jsonSCT, _ := json.Marshal(jsonSCTObj) return string(jsonSCT) }
func main() { app := cmd.NewAppShell("boulder-publisher", "Submits issued certificates to CT logs") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { logs := make([]*publisher.Log, len(c.Common.CT.Logs)) var err error for i, ld := range c.Common.CT.Logs { logs[i], err = publisher.NewLog(ld.URI, ld.Key) cmd.FailOnError(err, "Unable to parse CT log description") } if c.Common.CT.IntermediateBundleFilename == "" { auditlogger.Err("No CT submission bundle provided") os.Exit(1) } pemBundle, err := core.LoadCertBundle(c.Common.CT.IntermediateBundleFilename) cmd.FailOnError(err, "Failed to load CT submission bundle") bundle := []ct.ASN1Cert{} for _, cert := range pemBundle { bundle = append(bundle, ct.ASN1Cert(cert.Raw)) } pubi := publisher.NewPublisherImpl(bundle, logs) go cmd.DebugServer(c.Publisher.DebugAddr) go cmd.ProfileCmd("Publisher", stats) amqpConf := c.Publisher.AMQP pubi.SA, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, stats) cmd.FailOnError(err, "Unable to create SA client") pubs, err := rpc.NewAmqpRPCServer(amqpConf, c.Publisher.MaxConcurrentRPCServerRequests, stats) cmd.FailOnError(err, "Unable to create Publisher RPC server") rpc.NewPublisherServer(pubs, &pubi) err = pubs.Start(amqpConf) cmd.FailOnError(err, "Unable to run Publisher RPC server") } app.Run() }