func addChain(logClient *client.LogClient) {
	if *certChain == "" {
		log.Fatalf("No certificate chain file specified with -cert_chain")
	}
	rest, err := ioutil.ReadFile(*certChain)
	if err != nil {
		log.Fatalf("Failed to read certificate file: %v", err)
	}
	var chain []ct.ASN1Cert
	for {
		var block *pem.Block
		block, rest = pem.Decode(rest)
		if block == nil {
			break
		}
		if block.Type == "CERTIFICATE" {
			chain = append(chain, ct.ASN1Cert(block.Bytes))
		}
	}

	sct, err := logClient.AddChain(chain)
	if err != nil {
		log.Fatal(err)
	}
	// Display the SCT
	when := ctTimestampToTime(sct.Timestamp)
	fmt.Printf("%v: Uploaded chain of %d certs to %v log at %v\n", when, len(chain), sct.SCTVersion, *logURI)
	fmt.Printf("%v\n", signatureToString(&sct.Signature))
}
Example #2
0
func main() {
	app := cmd.NewAppShell("boulder-publisher", "Submits issued certificates to CT logs")
	app.Action = func(c cmd.Config, stats metrics.Statter, logger blog.Logger) {
		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 == "" {
			logger.AuditErr("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.New(bundle, logs, c.Publisher.SubmissionTimeout.Duration, logger)

		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")

		if c.Publisher.GRPC != nil {
			s, l, err := bgrpc.NewServer(c.Publisher.GRPC)
			cmd.FailOnError(err, "Failed to setup gRPC server")
			gw := bgrpc.NewPublisherServerWrapper(pubi)
			pubPB.RegisterPublisherServer(s, gw)
			go func() {
				err = s.Serve(l)
				cmd.FailOnError(err, "gRPC service failed")
			}()
		}

		pubs, err := rpc.NewAmqpRPCServer(amqpConf, c.Publisher.MaxConcurrentRPCServerRequests, stats, logger)
		cmd.FailOnError(err, "Unable to create Publisher RPC server")
		err = rpc.NewPublisherServer(pubs, pubi)
		cmd.FailOnError(err, "Unable to setup Publisher RPC server")

		err = pubs.Start(amqpConf)
		cmd.FailOnError(err, "Unable to run Publisher RPC server")
	}

	app.Run()
}
// SubmitToCT will submit the certificate represented by certDER to any CT
// logs configured in pub.CT.Logs (AMQP RPC method).
func (pub *Impl) SubmitToCT(ctx context.Context, der []byte) error {
	cert, err := x509.ParseCertificate(der)
	if err != nil {
		pub.log.AuditErr(fmt.Sprintf("Failed to parse certificate: %s", err))
		return err
	}

	localCtx, cancel := context.WithTimeout(ctx, pub.submissionTimeout)
	defer cancel()
	chain := append([]ct.ASN1Cert{der}, pub.issuerBundle...)
	for _, ctLog := range pub.ctLogs {
		sct, err := ctLog.client.AddChainWithContext(localCtx, chain)
		if err != nil {
			// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
			pub.log.AuditErr(fmt.Sprintf("Failed to submit certificate to CT log at %s: %s", ctLog.uri, 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.AuditErr(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.AuditErr(fmt.Sprintf("Failed to convert SCT receipt: %s", err))
			continue
		}

		err = pub.SA.AddSCTReceipt(localCtx, internalSCT)
		if err != nil {
			// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
			pub.log.AuditErr(fmt.Sprintf("Failed to store SCT receipt in database: %s", err))
			continue
		}
	}

	return nil
}
func setup(t *testing.T) (*Impl, *x509.Certificate, *ecdsa.PrivateKey) {
	intermediatePEM, _ := pem.Decode([]byte(testIntermediate))

	pub := New(nil, nil, 0, log)
	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
}
Example #5
0
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)
}
Example #6
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var c config
	err := cmd.ReadConfigFile(*configFile, &c)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
	scope := metrics.NewStatsdScope(stats, "Publisher")
	defer logger.AuditPanic()
	logger.Info(cmd.VersionString(clientName))

	logs := make([]*publisher.Log, len(c.Common.CT.Logs))
	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 == "" {
		logger.AuditErr("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))
	}

	amqpConf := c.Publisher.AMQP
	var sac core.StorageAuthority
	if c.Publisher.SAService != nil {
		conn, err := bgrpc.ClientSetup(c.Publisher.SAService, scope)
		cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
		sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
	} else {
		sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
		cmd.FailOnError(err, "Unable to create SA client")
	}

	pubi := publisher.New(
		bundle,
		logs,
		c.Publisher.SubmissionTimeout.Duration,
		logger,
		scope,
		sac)

	var grpcSrv *grpc.Server
	if c.Publisher.GRPC != nil {
		s, l, err := bgrpc.NewServer(c.Publisher.GRPC, scope)
		cmd.FailOnError(err, "Unable to setup Publisher gRPC server")
		gw := bgrpc.NewPublisherServerWrapper(pubi)
		pubPB.RegisterPublisherServer(s, gw)
		go func() {
			err = s.Serve(l)
			cmd.FailOnError(err, "Publisher gRPC service failed")
		}()
		grpcSrv = s
	}

	pubs, err := rpc.NewAmqpRPCServer(amqpConf, c.Publisher.MaxConcurrentRPCServerRequests, scope, logger)
	cmd.FailOnError(err, "Unable to create Publisher RPC server")

	go cmd.CatchSignals(logger, func() {
		pubs.Stop()
		if grpcSrv != nil {
			grpcSrv.GracefulStop()
		}
	})

	err = rpc.NewPublisherServer(pubs, pubi)
	cmd.FailOnError(err, "Unable to setup Publisher RPC server")

	go cmd.DebugServer(c.Publisher.DebugAddr)
	go cmd.ProfileCmd(scope)

	err = pubs.Start(amqpConf)
	cmd.FailOnError(err, "Unable to run Publisher RPC server")
}