Example #1
0
func getResponse(cert, issuer *x509.Certificate) ([]byte, error) {
	if len(cert.OCSPServer) == 0 {
		return nil, errors.New("no OCSPServer provided")
	}

	req, err := ocsp.CreateRequest(cert, issuer, nil)
	if err != nil {
		return nil, err
	}

	for _, server := range cert.OCSPServer {
		if u, err := url.Parse(server); err == nil {
			u.Path = base64.StdEncoding.EncodeToString(req)
			if resp, err := http.Get(u.String()); err == nil && resp.StatusCode == http.StatusOK {
				body, err := ioutil.ReadAll(resp.Body)
				resp.Body.Close()
				if err == nil {
					return body, nil
				}
				log.Println(err)
			} else {
				log.Println(err)
			}
		} else {
			log.Println(err)
		}
	}
	return nil, errors.New("no OCSP response")
}
Example #2
0
func (cp *TLSConf) OCSP() (err error) {
	if cp.IsEnabled() && len(cp.kp.Certificate) > 1 {
		for _, ocsp_server := range cp.cert.OCSPServer {
			for _, issuing := range cp.cert.IssuingCertificateURL {
				//log.Println("OCSP : ["+ocsp_server+"] ["+issuing+"]")
				issuer, err := load_issuer(issuing)
				if err != nil {
					return err
				}

				request, err := ocsp.CreateRequest(cp.cert, issuer, &ocsp.RequestOptions{crypto.SHA1})
				if err != nil {
					return err
				}

				staple := get_or_post_OCSP(ocsp_server, "application/ocsp-request", request)
				if len(staple) < MIN_STAPLE_SIZE {
					return nil
				}

				_, err = ocsp.ParseResponse(staple, issuer)
				//log.Printf("\n%+v\n", struct{
				//		ProducedAt, ThisUpdate, NextUpdate string
				//	}{ resp.ProducedAt.Format(time.RFC3339), resp.ThisUpdate.Format(time.RFC3339), resp.NextUpdate.Format(time.RFC3339) } )
				if err == nil {
					cp.kp.OCSPStaple = staple
					return nil
				}
			}
		}
	}
	return err
}
Example #3
0
// sendPurge should only be called as a Goroutine as it will block until the purge
// request is successful
func (updater *OCSPUpdater) sendPurge(der []byte) {
	cert, err := x509.ParseCertificate(der)
	if err != nil {
		updater.log.AuditErr(fmt.Sprintf("Failed to parse certificate for cache purge: %s", err))
		return
	}

	req, err := ocsp.CreateRequest(cert, updater.issuer, nil)
	if err != nil {
		updater.log.AuditErr(fmt.Sprintf("Failed to create OCSP request for cache purge: %s", err))
		return
	}

	// Create a GET style OCSP url for each endpoint in cert.OCSPServer (still waiting
	// on word from Akamai on how to properly purge cached POST requests, for now just
	// do GET)
	urls := []string{}
	for _, ocspServer := range cert.OCSPServer {
		urls = append(
			urls,
			path.Join(ocspServer, url.QueryEscape(base64.StdEncoding.EncodeToString(req))),
		)
	}

	err = updater.ccu.Purge(urls)
	if err != nil {
		updater.log.AuditErr(fmt.Sprintf("Failed to purge OCSP response from CDN: %s", err))
	}
}
Example #4
0
// GetOCSPForCert takes a PEM encoded cert or cert bundle and returns a OCSP
// response from the OCSP endpoint in the certificate.
// This []byte can be passed directly  into the OCSPStaple property of a tls.Certificate.
// If the bundle only contains the issued certificate, this function will try
// to get the issuer certificate from the IssuingCertificateURL in the certificate.
func GetOCSPForCert(bundle []byte) ([]byte, error) {
	certificates, err := parsePEMBundle(bundle)
	if err != nil {
		return nil, err
	}

	// We only got one certificate, means we have no issuer certificate - get it.
	if len(certificates) == 1 {
		// TODO: build fallback. If this fails, check the remaining array entries.
		resp, err := http.Get(certificates[0].IssuingCertificateURL[0])
		if err != nil {
			return nil, err
		}

		issuerBytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}

		issuerCert, err := x509.ParseCertificate(issuerBytes)
		if err != nil {
			return nil, err
		}

		// Insert it into the slice on position 0
		// We want it ordered right SRV CRT -> CA
		certificates = append(certificates, issuerCert)
	}

	// We expect the certificate slice to be ordered downwards the chain.
	// SRV CRT -> CA. We need to pull the cert and issuer cert out of it,
	// which should always be the last two certificates.
	issuedCert := certificates[0]
	issuerCert := certificates[1]

	// Finally kick off the OCSP request.
	ocspReq, err := ocsp.CreateRequest(issuedCert, issuerCert, nil)
	if err != nil {
		return nil, err
	}

	reader := bytes.NewReader(ocspReq)
	req, err := http.Post(issuedCert.OCSPServer[0], "application/ocsp-request", reader)
	if err != nil {
		return nil, err
	}

	ocspResBytes, err := ioutil.ReadAll(req.Body)
	_, err = ocsp.ParseResponse(ocspResBytes, nil)
	if err != nil {
		log.Printf("OCSPParse Error: %v", err)
		return nil, err
	}

	return ocspResBytes, nil
}
Example #5
0
func certIsRevokedOCSP(leaf *x509.Certificate, strict bool) (revoked, ok bool) {
	var err error

	ocspURLs := leaf.OCSPServer
	if len(ocspURLs) == 0 {
		// OCSP not enabled for this certificate.
		return false, true
	}

	var issuer *x509.Certificate
	for _, issuingCert := range leaf.IssuingCertificateURL {
		issuer, err = fetchRemote(issuingCert)
		if err != nil {
			continue
		}
		break
	}

	if issuer == nil {
		return
	}

	ocspRequest, err := ocsp.CreateRequest(leaf, issuer, &ocspOpts)
	if err != nil {
		return
	}

	for _, server := range ocspURLs {
		resp, err := sendOCSPRequest(server, ocspRequest, issuer)
		if err != nil {
			if strict {
				return
			}
			continue
		}

		// There wasn't an error fetching the OCSP status.
		ok = true

		if resp.Status != ocsp.Good {
			// The certificate was revoked.
			revoked = true
		}

		return
	}
	return
}
Example #6
0
File: ocsp.go Project: hlandau/acme
// Checks OCSP for a certificate. The immediate issuer must be specified. If
// the certificate does not support OCSP, (nil, nil) is returned.  Uses HTTP
// GET rather than POST. The response is verified. The caller must check the
// response status. The raw OCSP response is also returned, even if parsing
// failed and err is non-nil.
func (c *Client) CheckOCSPRaw(crt, issuer *x509.Certificate, ctx context.Context) (parsedResponse *ocsp.Response, rawResponse []byte, err error) {
	if len(crt.OCSPServer) == 0 {
		return
	}

	b, err := ocsp.CreateRequest(crt, issuer, nil)
	if err != nil {
		return
	}

	b64 := base64.StdEncoding.EncodeToString(b)
	path := crt.OCSPServer[0] + "/" + b64

	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return
	}

	req.Header.Set("Accept", "application/ocsp-response")

	res, err := c.doReqActual(req, ctx)
	if err != nil {
		return
	}

	defer res.Body.Close()

	if res.StatusCode != 200 {
		err = fmt.Errorf("OCSP response has status %#v", res.Status)
		return
	}

	if res.Header.Get("Content-Type") != "application/ocsp-response" {
		err = fmt.Errorf("response to OCSP request had unexpected content type")
		return
	}

	// Read response, limiting response to 1MiB.
	rawResponse, err = ioutil.ReadAll(denet.LimitReader(res.Body, 1*1024*1024))
	if err != nil {
		return
	}

	parsedResponse, err = ocsp.ParseResponse(rawResponse, issuer)
	return
}
Example #7
0
// Checks OCSP for a certificate. The immediate issuer must be specified. If
// the HTTP client is nil, the default client is used. If the certificate does
// not support OCSP, (nil, nil) is returned.  Uses HTTP GET rather than POST.
// The response is verified. The caller must check the response status.
func CheckOCSP(httpClient *http.Client, crt, issuer *x509.Certificate) (*ocsp.Response, error) {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	if len(crt.OCSPServer) == 0 {
		return nil, nil
	}

	b, err := ocsp.CreateRequest(crt, issuer, nil)
	if err != nil {
		return nil, err
	}

	b64 := base64.StdEncoding.EncodeToString(b)
	path := crt.OCSPServer[0] + "/" + b64

	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Accept", "application/ocsp-response")

	res, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()

	if res.StatusCode != 200 {
		return nil, fmt.Errorf("OCSP response has status %#v", res.Status)
	}

	if res.Header.Get("Content-Type") != "application/ocsp-response" {
		return nil, fmt.Errorf("response to OCSP request had unexpected content type")
	}

	resb, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	return ocsp.ParseResponse(resb, issuer)
}
Example #8
0
func main() {
	http.HandleFunc("/", newLoggingHandleFunc(rootHandler))
	http.HandleFunc("/new", newLoggingHandleFunc(newHandler))
	http.HandleFunc("/view/", newLoggingHandleFunc(newGzipHandleFunc(titleHandler(viewHandler))))
	http.HandleFunc("/edit/", newLoggingHandleFunc(newGzipHandleFunc(titleHandler(editHandler))))
	http.HandleFunc("/save/", newLoggingHandleFunc(titleHandler(saveHandler)))
	http.HandleFunc("/del/", newLoggingHandleFunc(titleHandler(delHandler)))
	http.HandleFunc("/front", newLoggingHandleFunc(newGzipHandleFunc(frontHandler)))
	http.HandleFunc("/hsts_hpkp", hsts_hpkp)
	log.SetPrefix("goWiki: ")
	log.Println("listening... on port", HTTPS_PORT)
	go func() {
		for {
			err := func() error {
				var OCSPC OCSPCert
				var err error
				cert, err := tls.LoadX509KeyPair(CERT, KEY)
				if err != nil {
					return err
				}
				OCSPC.cert = &cert
				if OCSPC.cert.Leaf, err = x509.ParseCertificate(OCSPC.cert.Certificate[0]); err != nil {
					return err
				}
				issuerRAW, err := ioutil.ReadFile(ISSUER)
				if err != nil {
					return err
				}
				for {
					var issuerPEM *pem.Block
					issuerPEM, issuerRAW = pem.Decode(issuerRAW)
					if issuerPEM == nil {
						break
					}
					if issuerPEM.Type == "CERTIFICATE" {
						OCSPC.issuer, err = x509.ParseCertificate(issuerPEM.Bytes)
						if err != nil {
							return err
						}
					}
				}
				if OCSPC.issuer == nil {
					return errors.New("no issuer")
				}
				OCSPC.req, err = ocsp.CreateRequest(OCSPC.cert.Leaf, OCSPC.issuer, nil)
				if err != nil {
					return err
				}
				err = OCSPC.updateStaple()
				if err != nil {
					return err
				}
				go OCSPC.stapleLoop()
				TLSConfig := new(tls.Config)
				TLSConfig.Certificates = []tls.Certificate{cert}
				TLSConfig.CipherSuites = []uint16{
					tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
					tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
					tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
					tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
					tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
					tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
					tls.TLS_RSA_WITH_AES_128_CBC_SHA,
					tls.TLS_RSA_WITH_AES_256_CBC_SHA,
					tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
					tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}
				TLSConfig.PreferServerCipherSuites = true
				TLSConfig.MinVersion = tls.VersionTLS11
				//MaxVersion needed because of bug with TLS_FALLBACK_SCSV gonna be fixed in go 1.5
				TLSConfig.MaxVersion = tls.VersionTLS12
				TLSConfig.NextProtos = []string{"http/1.1"}
				TLSConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
					OCSPC.RLock()
					defer OCSPC.RUnlock()
					return OCSPC.cert, nil
				}
				ln, err := net.Listen("tcp", HTTPS_PORT)
				if err != nil {
					return err
				}
				tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, TLSConfig)
				return new(http.Server).Serve(tlsListener)
			}()
			if err != nil {
				log.Println(err)
			}
			time.Sleep(time.Second * TIMEOUT)
		}
	}()
	for {
		log.Println("redirecting from port", HTTP_PORT, "to", HTTPS_PORT)
		err := http.ListenAndServe(HTTP_PORT, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("X-Frame-Options", "SAMEORIGIN")
			w.Header().Set("Server", "Jesus")
			log.Println("redirecting http", r.RemoteAddr, "to https", DOMAIN+HTTPS_PORT+r.URL.Path)
			http.Redirect(w, r, "https://"+DOMAIN+HTTPS_PORT+r.URL.Path, http.StatusMovedPermanently)
		}))
		if err != nil {
			log.Println(err)
		}
		time.Sleep(time.Second * TIMEOUT)
	}
}
Example #9
0
// GetOCSPForCert takes a PEM encoded cert or cert bundle returning the raw OCSP response,
// the parsed response, and an error, if any. The returned []byte can be passed directly
// into the OCSPStaple property of a tls.Certificate. If the bundle only contains the
// issued certificate, this function will try to get the issuer certificate from the
// IssuingCertificateURL in the certificate. If the []byte and/or ocsp.Response return
// values are nil, the OCSP status may be assumed OCSPUnknown.
func GetOCSPForCert(bundle []byte) ([]byte, *ocsp.Response, error) {
	certificates, err := parsePEMBundle(bundle)
	if err != nil {
		return nil, nil, err
	}

	// We expect the certificate slice to be ordered downwards the chain.
	// SRV CRT -> CA. We need to pull the leaf and issuer certs out of it,
	// which should always be the first two certificates. If there's no
	// OCSP server listed in the leaf cert, there's nothing to do. And if
	// we have only one certificate so far, we need to get the issuer cert.
	issuedCert := certificates[0]
	if len(issuedCert.OCSPServer) == 0 {
		return nil, nil, errors.New("no OCSP server specified in cert")
	}
	if len(certificates) == 1 {
		// TODO: build fallback. If this fails, check the remaining array entries.
		if len(issuedCert.IssuingCertificateURL) == 0 {
			return nil, nil, errors.New("no issuing certificate URL")
		}

		resp, err := httpGet(issuedCert.IssuingCertificateURL[0])
		if err != nil {
			return nil, nil, err
		}
		defer resp.Body.Close()

		issuerBytes, err := ioutil.ReadAll(limitReader(resp.Body, 1024*1024))
		if err != nil {
			return nil, nil, err
		}

		issuerCert, err := x509.ParseCertificate(issuerBytes)
		if err != nil {
			return nil, nil, err
		}

		// Insert it into the slice on position 0
		// We want it ordered right SRV CRT -> CA
		certificates = append(certificates, issuerCert)
	}
	issuerCert := certificates[1]

	// Finally kick off the OCSP request.
	ocspReq, err := ocsp.CreateRequest(issuedCert, issuerCert, nil)
	if err != nil {
		return nil, nil, err
	}

	reader := bytes.NewReader(ocspReq)
	req, err := httpPost(issuedCert.OCSPServer[0], "application/ocsp-request", reader)
	if err != nil {
		return nil, nil, err
	}
	defer req.Body.Close()

	ocspResBytes, err := ioutil.ReadAll(limitReader(req.Body, 1024*1024))
	ocspRes, err := ocsp.ParseResponse(ocspResBytes, issuerCert)
	if err != nil {
		return nil, nil, err
	}

	if ocspRes.Certificate == nil {
		err = ocspRes.CheckSignatureFrom(issuerCert)
		if err != nil {
			return nil, nil, err
		}
	}

	return ocspResBytes, ocspRes, nil
}
Example #10
0
func main() {
	flag.Parse()
	if logURL == nil || logKey == nil || fileName == nil {
		flag.PrintDefaults()
		return
	}
	statuses[ocsp.Good] = "good"
	statuses[ocsp.Revoked] = "revoked"
	statuses[ocsp.Unknown] = "unknown"
	statuses[ocsp.ServerFailed] = "fail"

	pemPublicKey := fmt.Sprintf(`-----BEGIN PUBLIC KEY-----
%s
-----END PUBLIC KEY-----`, *logKey)
	ctLog, err := certificatetransparency.NewLog(*logURL, pemPublicKey)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize log: %s\n", err)
		os.Exit(1)
	}

	file, err := os.OpenFile(*fileName, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open entries file: %s\n", err)
		os.Exit(1)
	}
	defer file.Close()

	entriesFile := certificatetransparency.EntriesFile{file}

	if !*skipUpdate {
		sth, err := ctLog.GetSignedTreeHead()
		if err != nil {
			fmt.Fprintf(os.Stderr, "GetSignedTreeHead: %s\n", err)
			os.Exit(1)
		}
		fmt.Printf("%d total entries at %s\n", sth.Size, sth.Time.Format(time.ANSIC))

		count, err := entriesFile.Count()
		if err != nil {
			fmt.Fprintf(os.Stderr, "\nFailed to read entries file: %s\n", err)
			os.Exit(1)
		}
		if count < sth.Size {
			_, err = ctLog.DownloadRange(file, nil, count, sth.Size)
			if err != nil {
				fmt.Fprintf(os.Stderr, "\nFailed to update CT log: %s\n", err)
				os.Exit(1)
			}
		}
		entriesFile.Seek(0, 0)
		treeHash, err := entriesFile.HashTree(nil, sth.Size)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error hashing tree: %s", err)
			os.Exit(1)
		}
		if !bytes.Equal(treeHash[:], sth.Hash) {
			fmt.Fprintf(os.Stderr, "Hashes do not match! Calculated: %x, STH contains %x\n", treeHash, sth.Hash)
			os.Exit(1)
		}
		fmt.Println("Hashes match! Calculated: %s, STH contains %s\n", hex.EncodeToString(treeHash[:]), hex.EncodeToString(sth.Hash[:]))
		entriesFile.Seek(0, 0)
	}

	dataChan := make(chan data)

	go func() {
		entriesFile.Map(func(ent *certificatetransparency.EntryAndPosition, err error) {
			if err != nil {
				return
			}

			cert, err := x509.ParseCertificate(ent.Entry.X509Cert)
			if err != nil {
				return
			}
			if cert.Issuer.CommonName != "Let's Encrypt Authority X1" {
				return
			}
			if time.Now().After(cert.NotAfter) {
				return
			}

			var issuer *x509.Certificate
			if len(ent.Entry.ExtraCerts) > 0 {
				issuer, err = x509.ParseCertificate(ent.Entry.ExtraCerts[0])
				if err != nil {
					fmt.Fprintf(os.Stderr, "Failed to parse issuer: %s\n", err)
					return
				}
			}
			if len(cert.OCSPServer) == 0 {
				if cert.Issuer.CommonName != "Merge Delay Intermediate 1" {
					fmt.Fprintf(os.Stderr, "No OCSP Server for %s\n", cert.Issuer.CommonName)
				}
				return
			}
			ocspServer := cert.OCSPServer[0]
			req, err := ocsp.CreateRequest(cert, issuer, &ocsp.RequestOptions{})
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating OCSP request: %s\n", err)
				return
			}
			url := fmt.Sprintf("%s%s", ocspServer, base64.StdEncoding.EncodeToString(req))
			start := time.Now()
			httpResponse, err := http.Post(ocspServer, "application/ocsp-request", bytes.NewBuffer(req))
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error fetching OCSP: %s %s\n", err, url)
				return
			}
			defer httpResponse.Body.Close()
			datum := data{
				serial:      fmt.Sprintf("%032x", cert.SerialNumber),
				names:       cert.DNSNames,
				ocspLatency: time.Now().Sub(start),
				notBefore:   cert.NotBefore,
				url:         url,
			}
			if datum.ocspLatency > time.Second {
				fmt.Printf("slow response (%dms) for %x: %s\n", datum.ocspLatency/time.Millisecond, cert.SerialNumber, url)
			}
			names := strings.Join(cert.DNSNames, ", ")
			if err != nil {
				datum.ocspErr = fmt.Errorf("error fetching OCSP for %s %s: %s\n", names, url, err)
				dataChan <- datum
				return
			}
			ocspResponse, err := ioutil.ReadAll(httpResponse.Body)
			if err != nil {
				datum.ocspErr = fmt.Errorf("error reading OCSP for %s %s: %s\n", names, url, err)
				dataChan <- datum
				return
			}
			parsedResponse, err := ocsp.ParseResponse(ocspResponse, issuer)
			if err != nil {
				datum.ocspErr = fmt.Errorf("error parsing OCSP response for %s %s: %s\n", names, url, err)
				dataChan <- datum
				return
			}
			datum.nextUpdate = parsedResponse.NextUpdate
			datum.thisUpdate = parsedResponse.ThisUpdate
			dataChan <- datum
		})
		close(dataChan)
	}()
	processData(dataChan)
}