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)) }
func getSTH(logClient *client.LogClient) { sth, err := logClient.GetSTH() if err != nil { log.Fatal(err) } // Display the STH when := ctTimestampToTime(sth.Timestamp) fmt.Printf("%v: Got STH for %v log (size=%d) at %v, hash %x\n", when, sth.Version, sth.TreeSize, *logURI, sth.SHA256RootHash) fmt.Printf("%v\n", signatureToString(&sth.TreeHeadSignature)) }
func precertSubmitterJob(ctx context.Context, addedCerts chan<- *preload.AddedCert, log_client *client.LogClient, precerts <-chan *ct.LogEntry, wg *sync.WaitGroup) { for c := range precerts { sct, err := log_client.AddPreChain(ctx, c.Chain) if err != nil { log.Printf("failed to add pre-chain with CN %s: %v", c.Precert.TBSCertificate.Subject.CommonName, err) recordFailure(addedCerts, c.Chain[0], err) continue } recordSct(addedCerts, c.Chain[0], sct) if !*quiet { log.Printf("Added precert chain for CN '%s', SCT: %s\n", c.Precert.TBSCertificate.Subject.CommonName, sct) } } wg.Done() }
func certSubmitterJob(ctx context.Context, addedCerts chan<- *preload.AddedCert, log_client *client.LogClient, certs <-chan *ct.LogEntry, wg *sync.WaitGroup) { for c := range certs { chain := make([]ct.ASN1Cert, len(c.Chain)+1) chain[0] = c.X509Cert.Raw copy(chain[1:], c.Chain) sct, err := log_client.AddChain(ctx, chain) if err != nil { log.Printf("failed to add chain with CN %s: %v\n", c.X509Cert.Subject.CommonName, err) recordFailure(addedCerts, chain[0], err) continue } recordSct(addedCerts, chain[0], sct) if !*quiet { log.Printf("Added chain for CN '%s', SCT: %s\n", c.X509Cert.Subject.CommonName, sct) } } wg.Done() }
func getRoots(ctx context.Context, logClient *client.LogClient) { roots, err := logClient.GetAcceptedRoots(ctx) if err != nil { log.Fatal(err) } for _, root := range roots { if *textOut { cert, err := x509.ParseCertificate(root) if err != nil { log.Printf("Error parsing certificate: %q", err.Error()) continue } fmt.Printf("%s\n", x509util.CertificateToString(cert)) } else { if err := pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: root}); err != nil { log.Printf("Failed to PEM encode cert: %q", err.Error()) } } } }
// DownloadRange downloads log entries from the given starting index till one // less than upTo. If status is not nil then status updates will be written to // it until the function is complete, when it will be closed. The log entries // are provided to an output channel. func downloadCTRangeToChannel(ctLog *client.LogClient, outEntries chan<- ct.LogEntry, status chan<- OperationStatus, start, upTo int64) (int64, error) { if outEntries == nil { return 0, fmt.Errorf("No output channel provided") } defer close(outEntries) if status != nil { defer close(status) } index := start for index < upTo { if status != nil { status <- OperationStatus{start, index, upTo} } max := index + 2000 if max >= upTo { max = upTo - 1 } rawEnts, err := ctLog.GetEntries(index, max) if err != nil { return index, err } for _, ent := range rawEnts { outEntries <- ent if (ent.Index) != index { return index, fmt.Errorf("Index mismatch, local: %v, remote: %v", index, ent.Index) } index++ } } return index, nil }
func downloadLog(ctLogUrl *url.URL, ctLog *client.LogClient, db *sqldb.EntriesDatabase) error { if *config.OffsetByte > 0 { return fmt.Errorf("Cannot set offsetByte for CT log downloads") } fmt.Printf("Fetching signed tree head... ") sth, err := ctLog.GetSTH() if err != nil { return err } // Set pointer in DB, now that we've verified the log works err = db.SetLog(fmt.Sprintf("%s%s", ctLogUrl.Host, ctLogUrl.Path)) if err != nil { log.Fatalf("unable to set Certificate Log: %s", err) } var origCount uint64 // Now we're OK to use the DB if *config.Offset > 0 { log.Printf("Starting from offset %d", *config.Offset) origCount = *config.Offset } else { log.Printf("Counting existing entries... ") origCount, err = db.Count() if err != nil { err = fmt.Errorf("Failed to read entries file: %s", err) return err } } fmt.Printf("%d total entries at %s\n", sth.TreeSize, sqldb.Uint64ToTimestamp(sth.Timestamp).Format(time.ANSIC)) if origCount == sth.TreeSize { fmt.Printf("Nothing to do\n") return nil } endPos := sth.TreeSize if *config.Limit > 0 && endPos > origCount+*config.Limit { endPos = origCount + *config.Limit } fmt.Printf("Going from %d to %d\n", origCount, endPos) entryChan := make(chan ct.LogEntry, 100) statusChan := make(chan OperationStatus, 1) wg := new(sync.WaitGroup) displayProgress(statusChan, wg) numWorkers := *config.NumThreads * runtime.NumCPU() for i := 0; i < numWorkers; i++ { go insertCTWorker(entryChan, db, wg) } _, err = downloadCTRangeToChannel(ctLog, entryChan, statusChan, int64(origCount), int64(endPos)) wg.Wait() clearLine() if err != nil { err = fmt.Errorf("Error while downloading: %s", err) return err } return nil }