// UnmarshalJSON converts the JSON representation of a FixError back to a FixError func UnmarshalJSON(b []byte) (*FixError, error) { var u struct { Type string Cert []byte Chain [][]byte URL string Bad []byte Error string Code int } err := json.Unmarshal(b, &u) if err != nil { return nil, err } ferr := &FixError{} switch u.Type { case "None": ferr.Type = None case "ParseFailure": ferr.Type = ParseFailure case "CannotFetchURL": ferr.Type = CannotFetchURL case "FixFailed": ferr.Type = FixFailed case "PostFailed": ferr.Type = PostFailed case "LogPostFailed": ferr.Type = LogPostFailed case "VerifyFailed": ferr.Type = VerifyFailed default: return nil, errors.New("cannot parse FixError Type") } if u.Cert != nil { cert, err := x509.ParseCertificate(u.Cert) if err != nil { return nil, fmt.Errorf("cannot parse FixError Cert: %s", err) } ferr.Cert = cert } for _, c := range u.Chain { cert, err := x509.ParseCertificate(c) if err != nil { return nil, fmt.Errorf("cannot parse FixError Chain: %s", err) } ferr.Chain = append(ferr.Chain, cert) } ferr.URL = u.URL ferr.Bad = u.Bad if u.Error != "" { ferr.Error = errors.New(u.Error) } ferr.Code = u.Code return ferr, nil }
// Assumes chains to be stores in a file in JSON encoded with the certificates // in DER format. func processChains(file string, fl *fixchain.FixAndLog) { f, err := os.Open(file) if err != nil { log.Fatalf("Can't open %q: %s", file, err) } defer f.Close() type Chain struct { Chain [][]byte } dec := json.NewDecoder(f) for { var m Chain if err := dec.Decode(&m); err == io.EOF { break } else if err != nil { log.Fatal(err) } var chain []*x509.Certificate for _, derBytes := range m.Chain { cert, err := x509.ParseCertificate(derBytes) switch err.(type) { case nil, x509.NonFatalErrors: // ignore default: log.Fatalf("can't parse certificate: %s %#v", err, derBytes) } chain = append(chain, cert) } fl.QueueAllCertsInChain(chain) } }
// Processes the given |entry| in the specified log. func (s *Scanner) processEntry(entry ct.LogEntry, foundCert func(*ct.LogEntry), foundPrecert func(*ct.LogEntry)) { atomic.AddInt64(&s.certsProcessed, 1) switch entry.Leaf.TimestampedEntry.EntryType { case ct.X509LogEntryType: if s.opts.PrecertOnly { // Only interested in precerts and this is an X.509 cert, early-out. return } cert, err := x509.ParseCertificate(entry.Leaf.TimestampedEntry.X509Entry) if err = s.handleParseEntryError(err, entry.Leaf.TimestampedEntry.EntryType, entry.Index); err != nil { // We hit an unparseable entry, already logged inside handleParseEntryError() return } if s.opts.Matcher.CertificateMatches(cert) { entry.X509Cert = cert foundCert(&entry) } case ct.PrecertLogEntryType: c, err := x509.ParseTBSCertificate(entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate) if err = s.handleParseEntryError(err, entry.Leaf.TimestampedEntry.EntryType, entry.Index); err != nil { // We hit an unparseable entry, already logged inside handleParseEntryError() return } precert := &ct.Precertificate{ Raw: entry.Chain[0], TBSCertificate: *c, IssuerKeyHash: entry.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash} if s.opts.Matcher.PrecertificateMatches(precert) { entry.Precert = precert foundPrecert(&entry) } atomic.AddInt64(&s.precertsSeen, 1) } }
func (edb *EntriesDatabase) InsertCensysEntry(entry *censysdata.CensysEntry) error { cert, err := x509.ParseCertificate(entry.CertBytes) if err != nil { return err } txn, certId, err := edb.insertCertificate(cert) if err != nil { if edb.Verbose { fmt.Printf("Error inserting cert, %s\n", err) } if txn != nil { txn.Rollback() } return err } // // Insert the appropriate CensysEntry // certEntry := &CensysEntry{ CertID: certId, EntryTime: *entry.Timestamp, } // Ignore errors on insertion for Censys entry markers err = txn.Insert(certEntry) if errorIsNotDuplicate(err) { return err } return txn.Commit() }
func (l *Logger) getRoots() (*x509.CertPool, error) { rootsJSON, err := l.client.Get(l.url + "/ct/v1/get-roots") if err != nil { return nil, fmt.Errorf("can't get roots from %s: %s", l.url, err) } defer rootsJSON.Body.Close() j, err := ioutil.ReadAll(rootsJSON.Body) if err != nil { return nil, fmt.Errorf("can't read body from %s: %s", l.url, err) } if rootsJSON.StatusCode != 200 { return nil, fmt.Errorf("can't deal with status other than 200 from %s: %d\nbody: %s", l.url, rootsJSON.StatusCode, string(j)) } type Certificates struct { Certificates [][]byte } var certs Certificates err = json.Unmarshal(j, &certs) if err != nil { return nil, fmt.Errorf("can't parse json (%s) from %s: %s", err, l.url, j) } ret := x509.NewCertPool() for i := 0; i < len(certs.Certificates); i++ { r, err := x509.ParseCertificate(certs.Certificates[i]) switch err.(type) { case nil, x509.NonFatalErrors: // ignore default: return nil, fmt.Errorf("can't parse certificate from %s: %s %#v", l.url, err, certs.Certificates[i]) } ret.AddCert(r) } return ret, nil }
func urlReplacement(url string) []*x509.Certificate { cs, ok := replacements[url] if !ok { return nil } var r []*x509.Certificate for _, c := range cs { s, _ := pem.Decode([]byte(c)) if s == nil { log.Fatalf("Can't decode built-in: %s", c) return nil } cert, err := x509.ParseCertificate(s.Bytes) if err != nil { log.Fatalf("Can't parse built-in: %s\n%s", c, err) return nil } if cert == nil { log.Fatalf("Parse didn't produce a cert: %s", c) return nil } r = append(r, cert) } return r }
// CertificateFromPEM takes a string representing a certificate in PEM format // and returns the corresponding x509.Certificate object. func CertificateFromPEM(pemBytes string) (*x509.Certificate, error) { block, _ := pem.Decode([]byte(pemBytes)) if block == nil { return nil, errors.New("failed to decode PEM") } return x509.ParseCertificate(block.Bytes) }
func (edb *EntriesDatabase) InsertCTEntry(entry *ct.LogEntry) error { var cert *x509.Certificate var err error switch entry.Leaf.TimestampedEntry.EntryType { case ct.X509LogEntryType: cert, err = x509.ParseCertificate(entry.Leaf.TimestampedEntry.X509Entry) case ct.PrecertLogEntryType: cert, err = x509.ParseTBSCertificate(entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate) } if err != nil { return err } // Skip unimportant entries, if configured if edb.IssuerFilter != nil && !strings.HasPrefix(cert.Issuer.CommonName, *edb.IssuerFilter) { return nil } backoff := &backoff.Backoff{ Jitter: true, } for count := 0; count < 10; count++ { txn, certId, err := edb.insertCertificate(cert) if err != nil { if edb.Verbose { fmt.Printf("Error inserting cert, retrying (%d/10) %s\n", count, err) } if txn != nil { txn.Rollback() } time.Sleep(backoff.Duration()) continue } // // Insert the appropriate CertificateLogEntry, ignoring errors if there was a collision // certLogEntry := &CertificateLogEntry{ CertID: certId, LogID: edb.LogId, EntryID: uint64(entry.Index), EntryTime: Uint64ToTimestamp(entry.Leaf.TimestampedEntry.Timestamp), } err = txn.Insert(certLogEntry) if errorIsNotDuplicate(err) { txn.Rollback() continue } return txn.Commit() } return err }
// Get the certs that correspond to the given url. func (fix *toFix) getIntermediates(url string) ([]*x509.Certificate, *FixError) { var icerts []*x509.Certificate // PKCS#7 additions as (at time of writing) there is no standard Go PKCS#7 // implementation r := urlReplacement(url) if r != nil { return r, nil } body, err := fix.cache.getURL(url) if err != nil { return nil, &FixError{ Type: CannotFetchURL, Cert: fix.cert, Chain: fix.chain.certs, URL: url, Error: err, } } icert, err := x509.ParseCertificate(body) if err != nil { s, _ := pem.Decode(body) if s != nil { icert, err = x509.ParseCertificate(s.Bytes) } } if err != nil { return nil, &FixError{ Type: ParseFailure, Cert: fix.cert, Chain: fix.chain.certs, URL: url, Bad: body, Error: err, } } icerts = append(icerts, icert) return icerts, nil }
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()) } } } }
func sysCerts() (certs []*x509.Certificate, err error) { cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") data, err := cmd.Output() if err != nil { return nil, err } for len(data) > 0 { var block *pem.Block block, data = pem.Decode(data) if block == nil { break } if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { continue } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { continue } certs = append(certs, cert) } return certs, nil }
// X509Certificate returns the X.509 Certificate contained within the // MerkleTreeLeaf. // Returns a pointer to an x509.Certificate or a non-nil error. func (m *MerkleTreeLeaf) X509Certificate() (*x509.Certificate, error) { return x509.ParseCertificate(m.TimestampedEntry.X509Entry) }
func (rt testRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { url := fmt.Sprintf("%s://%s%s", request.URL.Scheme, request.URL.Host, request.URL.Path) switch url { case "https://ct.googleapis.com/pilot/ct/v1/get-roots": b := stringRootsToJSON([]string{verisignRoot, testRoot}) return &http.Response{ Status: "200 OK", StatusCode: 200, Proto: request.Proto, ProtoMajor: request.ProtoMajor, ProtoMinor: request.ProtoMinor, Body: &bytesReadCloser{bytes.NewReader(b)}, ContentLength: int64(len(b)), Request: request, }, nil case "https://ct.googleapis.com/pilot/ct/v1/add-chain": body, err := ioutil.ReadAll(request.Body) request.Body.Close() if err != nil { errStr := fmt.Sprintf("#%d: Could not read request body: %s", rt.testIndex, err.Error()) rt.t.Error(errStr) return nil, errors.New(errStr) } type Chain struct { Chain [][]byte } var chainBytes Chain err = json.Unmarshal(body, &chainBytes) if err != nil { errStr := fmt.Sprintf("#%d: Could not unmarshal json: %s", rt.testIndex, err.Error()) rt.t.Error(errStr) return nil, errors.New(errStr) } var chain []*x509.Certificate for _, certBytes := range chainBytes.Chain { cert, err := x509.ParseCertificate(certBytes) if err != nil { errStr := fmt.Sprintf("#%d: Could not parse certificate: %s", rt.testIndex, err.Error()) rt.t.Error(errStr) return nil, errors.New(errStr) } chain = append(chain, cert) } TryNextExpected: for i, expChain := range rt.test.expLoggedChains { if rt.seen[i] || len(chain) != len(expChain) { continue } for j, cert := range chain { if !strings.Contains(nameToKey(&cert.Subject), expChain[j]) { continue TryNextExpected } } rt.seen[i] = true goto Return } rt.t.Errorf("#%d: Logged chain was not expected: %s", rt.testIndex, chainToDebugString(chain)) Return: return &http.Response{ Status: "200 OK", StatusCode: 200, Proto: request.Proto, ProtoMajor: request.ProtoMajor, ProtoMinor: request.ProtoMinor, Body: &bytesReadCloser{bytes.NewReader([]byte(""))}, ContentLength: 0, Request: request, }, nil default: var cert string switch url { case "http://www.thawte.com/repository/Thawte_SGC_CA.crt": cert = thawteIntermediate case "http://crt.comodoca.com/EssentialSSLCA_2.crt": cert = comodoIntermediate case "http://crt.comodoca.com/ComodoUTNSGCCA.crt": cert = comodoRoot case "http://www.example.com/intermediate2.crt": cert = testIntermediate2 case "http://www.example.com/intermediate1.crt": cert = testIntermediate1 case "http://www.example.com/ca.crt": cert = testRoot case "http://www.example.com/a.crt": cert = testA case "http://www.example.com/b.crt": cert = testB default: return nil, fmt.Errorf("can't reach url %s", url) } return &http.Response{ Status: "200 OK", StatusCode: 200, Proto: request.Proto, ProtoMajor: request.ProtoMajor, ProtoMinor: request.ProtoMinor, Body: &bytesReadCloser{bytes.NewReader([]byte(cert))}, ContentLength: int64(len([]byte(cert))), Request: request, }, nil } }
func main() { var ( err error offset int ) // create a certificate transparency client ctLog := client.New("http://ct.googleapis.com/aviator", nil) httpCli := &http.Client{ Transport: &http.Transport{ DisableCompression: true, DisableKeepAlives: false, }, Timeout: 10 * time.Second, } if len(os.Args) > 1 { offset, err = strconv.Atoi(os.Args[1]) if err != nil { log.Fatal(err) } } for { log.Printf("retrieving CT logs %d to %d", offset, offset+100) rawEnts, err := ctLog.GetEntries(int64(offset), int64(offset+100)) if err != nil { log.Fatal(err) } // loop over CT records for i, ent := range rawEnts { log.Printf("CT index=%d", offset+i) var cert *x509.Certificate switch ent.Leaf.TimestampedEntry.EntryType { case ct.X509LogEntryType: cert, err = x509.ParseCertificate(ent.Leaf.TimestampedEntry.X509Entry) case ct.PrecertLogEntryType: cert, err = x509.ParseTBSCertificate(ent.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate) } if err != nil { log.Fatal(err) } log.Printf("CN=%s", cert.Subject.CommonName) log.Printf("Not Before=%s", cert.NotBefore) log.Printf("Not After=%s", cert.NotAfter) // Format the PEM certificate payload := base64.StdEncoding.EncodeToString(cert.Raw) buf := new(bytes.Buffer) fmt.Fprintf(buf, "-----BEGIN CERTIFICATE-----\n") for len(payload) > 0 { chunkLen := len(payload) if chunkLen > 64 { chunkLen = 64 } fmt.Fprintf(buf, "%s\n", payload[0:chunkLen]) payload = payload[chunkLen:] } fmt.Fprintf(buf, "-----END CERTIFICATE-----") // create a mime/multipart form with the certificate var b bytes.Buffer w := multipart.NewWriter(&b) fw, err := w.CreateFormFile("certificate", certificate.SHA256Hash(cert.Raw)) if err != nil { log.Fatal(err) } _, err = io.Copy(fw, buf) if err != nil { log.Fatal(err) } w.Close() // post the form to the tls-observatory api r, err := http.NewRequest("POST", "https://tls-observatory.services.mozilla.com/api/v1/certificate", &b) if err != nil { log.Fatal(err) } r.Header.Set("Content-Type", w.FormDataContentType()) resp, err := httpCli.Do(r) if err != nil { log.Printf("%v\n\n", err) continue } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } if resp.StatusCode != http.StatusCreated { log.Fatalf("Expected HTTP 201 Created, got %q\n%s", resp.Status, body) } // parse the returned cert var tlsobs_cert certificate.Certificate err = json.Unmarshal(body, &tlsobs_cert) if err != nil { log.Fatal(err) } log.Printf("https://tls-observatory.services.mozilla.com/api/v1/certificate?id=%d\n\n", tlsobs_cert.ID) } offset += 100 } }
func ExampleCertificate_Verify() { // Verifying with a custom list of root certificates. const rootPEM = ` -----BEGIN CERTIFICATE----- MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7 qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY /iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/ zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6 yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx -----END CERTIFICATE-----` const certPEM = ` -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q 5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC 7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+ gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283 TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq 0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA== -----END CERTIFICATE-----` // First, create the set of root certificates. For this example we only // have one. It's also possible to omit this in order to use the // default root set of the current operating system. roots := x509.NewCertPool() ok := roots.AppendCertsFromPEM([]byte(rootPEM)) if !ok { panic("failed to parse root certificate") } block, _ := pem.Decode([]byte(certPEM)) if block == nil { panic("failed to parse certificate PEM") } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { panic("failed to parse certificate: " + err.Error()) } opts := x509.VerifyOptions{ DNSName: "mail.google.com", Roots: roots, } if _, err := cert.Verify(opts); err != nil { panic("failed to verify certificate: " + err.Error()) } }