func NewS3Session(auth *aws.Auth, region aws.Region) *s3.S3 { var s3Session *s3.S3 cert := x509.Certificate{} // go's systemVerify panics with no verify options set // TODO: EVG-483 if runtime.GOOS == "windows" { s3Session = s3.New(*auth, region) s3Session.ReadTimeout = S3ReadTimeout s3Session.WriteTimeout = S3WriteTimeout s3Session.ConnectTimeout = S3ConnectTimeout return s3Session } // no verify options so system root ca will be used _, err := cert.Verify(x509.VerifyOptions{}) rootsError := x509.SystemRootsError{} if err != nil && err.Error() == rootsError.Error() { // create a Transport which includes our TLSConfig with InsecureSkipVerify // and client timeouts. tlsConfig := tls.Config{InsecureSkipVerify: true} tr := http.Transport{ TLSClientConfig: &tlsConfig} // add the Transport to our http client client := &http.Client{Transport: &tr} s3Session = s3.New(*auth, region, client) } else { s3Session = s3.New(*auth, region) } s3Session.ReadTimeout = S3ReadTimeout s3Session.WriteTimeout = S3WriteTimeout s3Session.ConnectTimeout = S3ConnectTimeout return s3Session }
func Verify(options x509.VerifyOptions, cert *x509.Certificate) Result { result := Result{Certificate: cert} chains, err := cert.Verify(options) result.Error = err for _, chain := range chains { result.Chains = append(result.Chains, CommonNamesFromChain(chain)) } return result }
func (CertificateValidator) validateCertAndChain(certificate *x509.Certificate, certPool *x509.CertPool) error { opts := x509.VerifyOptions{ Roots: certPool, } if _, err := certificate.Verify(opts); err != nil { return fmt.Errorf("certificate and chain mismatch: %s", err.Error()) } return nil }
// Verify operates on an X509Store and validates the existence of a chain of trust // between a leafCertificate and a CA present inside of the X509 Store. // It requires at least two certificates in certList, a leaf Certificate and an // intermediate CA certificate. func Verify(s X509Store, dnsName string, certList []*x509.Certificate) error { // If we have no Certificates loaded return error (we don't want to revert to using // system CAs). if len(s.GetCertificates()) == 0 { return errors.New("no root CAs available") } // At a minimum we should be provided a leaf cert and an intermediate. if len(certList) < 2 { return errors.New("certificate and at least one intermediate needed") } // Get the VerifyOptions from the keystore for a base dnsName opts, err := s.GetVerifyOptions(dnsName) if err != nil { return err } // Create a Certificate Pool for our intermediate certificates intPool := x509.NewCertPool() var leafCert *x509.Certificate // Iterate through all the certificates for _, c := range certList { // If the cert is a CA, we add it to the intermediates pool. If not, we call // it the leaf cert if c.IsCA { intPool.AddCert(c) continue } // Certificate is not a CA, it must be our leaf certificate. // If we already found one, bail with error if leafCert != nil { return errors.New("more than one leaf certificate found") } leafCert = c } // We exited the loop with no leaf certificates if leafCert == nil { return errors.New("no leaf certificates found") } // We have one leaf certificate and at least one intermediate. Lets add this // Cert Pool as the Intermediates list on our VerifyOptions opts.Intermediates = intPool // Finally, let's call Verify on our leafCert with our fully configured options chains, err := leafCert.Verify(opts) if len(chains) == 0 || err != nil { return fmt.Errorf("certificate verification failed: %v", err) } return nil }
func verifyX509Cert(cert *x509.Certificate, dnsName string, roots *x509.CertPool) error { verifyOptions := x509.VerifyOptions{ DNSName: dnsName, Roots: roots, KeyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth, }, } _, err := cert.Verify(verifyOptions) return err }
func (t trustPinChecker) caCheck(leafCert *x509.Certificate, intCerts []*x509.Certificate) bool { // Use intermediate certificates included in the root TUF metadata for our validation caIntPool := x509.NewCertPool() for _, intCert := range intCerts { caIntPool.AddCert(intCert) } // Attempt to find a valid certificate chain from the leaf cert to CA root // Use this certificate if such a valid chain exists (possibly using intermediates) if _, err := leafCert.Verify(x509.VerifyOptions{Roots: t.pinnedCAPool, Intermediates: caIntPool}); err == nil { return true } return false }
func checkCertificate(probeURL *url.URL) (probeResult, *x509.Certificate) { req, _ := http.NewRequest("HEAD", probeURL.String(), nil) req.Header.Set("User-Agent", fmt.Sprintf("Mozilla/5.0 (compatible; PromCertcheck/%s; +https://github.com/Luzifer/promcertcheck)", version)) resp, err := http.DefaultClient.Do(req) switch err.(type) { case nil, redirectFoundError: default: if !strings.Contains(err.Error(), "Found a redirect.") { return generalFailure, nil } } resp.Body.Close() intermediatePool := x509.NewCertPool() var verifyCert *x509.Certificate hostPort := strings.Split(probeURL.Host, ":") host := hostPort[0] for _, cert := range resp.TLS.PeerCertificates { wildHost := "*" + host[strings.Index(host, "."):] if !inSlice(cert.DNSNames, host) && !inSlice(cert.DNSNames, wildHost) { intermediatePool.AddCert(cert) continue } verifyCert = cert } if verifyCert == nil { return certificateNotFound, nil } verificationResult := false if _, err := verifyCert.Verify(x509.VerifyOptions{ Intermediates: intermediatePool, }); err == nil { verificationResult = true } if !verificationResult { return certificateInvalid, verifyCert } if verifyCert.NotAfter.Sub(time.Now()) < config.expireWarning { return certificateExpiresSoon, verifyCert } return certificateOK, verifyCert }
// Normally we can just call cert.Verify(opts), but since we actually want more information about // whether a certificate is not yet valid or expired, we also need to perform the expiry checks ourselves. func verifyCertificate(cert *x509.Certificate, opts x509.VerifyOptions, allowExpired bool) error { _, err := cert.Verify(opts) if invalidErr, ok := err.(x509.CertificateInvalidError); ok && invalidErr.Reason == x509.Expired { now := time.Now().UTC() if now.Before(cert.NotBefore) { return errors.Wrapf(err, "certificate not valid before %s, and it is currently %s", cert.NotBefore.UTC().Format(time.RFC1123), now.Format(time.RFC1123)) } if allowExpired { return nil } return errors.Wrapf(err, "certificate expires at %s, and it is currently %s", cert.NotAfter.UTC().Format(time.RFC1123), now.Format(time.RFC1123)) } return err }
func verify(t *testing.T, cert *x509.Certificate, opts x509.VerifyOptions, success bool, chainLength int) { validChains, err := cert.Verify(opts) if success { if err != nil { t.Fatalf("Unexpected error: %#v", err) } if len(validChains) != 1 { t.Fatalf("Expected a valid chain") } if len(validChains[0]) != chainLength { t.Fatalf("Expected a valid chain of length %d, got %d", chainLength, len(validChains[0])) } } else if err == nil && len(validChains) > 0 { t.Fatalf("Expected failure, got success") } }
func verifyCertificate(cert *x509.Certificate, rootCerts []*x509.Certificate) bool { roots := x509.NewCertPool() for _, root := range rootCerts { roots.AddCert(root) } opts := x509.VerifyOptions{ Roots: roots, } if _, err := cert.Verify(opts); err != nil { fmt.Printf("failed to verify certificate: %s\n", err) return false } fmt.Println("succeeded to verify certificate") return true }
// Checks the following: // (1) cert is valid according to one of the rootCerts. // (2) the subject key of cert corresponds to kPrin. // (3) the subject CommonName of cert is allowed by guard. func validateEndorsementCertificate(cert *x509.Certificate, guard tao.Guard, kPrin *auth.Prin, rootCerts *x509.CertPool) error { verifyOptions := x509.VerifyOptions{Roots: rootCerts} _, err := cert.Verify(verifyOptions) if err != nil { return err } var hwPublicKey *rsa.PublicKey hwPublicKey, ok := cert.PublicKey.(*rsa.PublicKey) if !ok { key, ok := cert.PublicKey.(rsa.PublicKey) if !ok { return errors.New("endorsement cert does not contain a valid RSA public key") } hwPublicKey = &key } ek, err := x509.MarshalPKIXPublicKey(hwPublicKey) if err != nil { return err } hashedCertKey := sha256.Sum256(ek) if kPrin.Type != "tpm" && kPrin.Type != "tpm2" { return errors.New("key principal to be endorsed is not a TPM key, but it's expected to be") } hashedBytes, ok := kPrin.KeyHash.(auth.Bytes) if !ok { return errors.New("key principal to be endorsed does not have bytes as its auth.Term") } if !bytes.Equal(hashedBytes, hashedCertKey[:]) { return errors.New(fmt.Sprintf( "endorsement cert endorses %v but needs to endorse %v", hashedCertKey, hashedBytes)) } machinePrin := auth.Prin{ Type: "MachineInfo", KeyHash: auth.Str(cert.Subject.CommonName), } if !guard.IsAuthorized(machinePrin, "Root", []string{}) { return errors.New( "machine endorsed by certificate is not authorized by policy") } return nil }
// verify checks if a certificate has expired func verify(cert *x509.Certificate) error { _, err := cert.Verify(x509.VerifyOptions{}) if err == nil { return nil } switch e := err.(type) { case x509.CertificateInvalidError: switch e.Reason { case x509.Expired: return ErrExpired default: return err } case x509.UnknownAuthorityError: // Apple cert isn't in the cert pool // ignoring this error return nil default: return err } }
// given a set of IP addresses this will determine what address, if any, can be used to // connect to the host certificate // if none can be found, will return empty string and an err func addrToUse(candidateIPs []net.IP, cert *x509.Certificate, cas []byte) (string, error) { if cert == nil { return "", errors.New("unable to determine suitable address with nil certificate") } log.Debug("Loading CAs for client auth") pool := x509.NewCertPool() pool.AppendCertsFromPEM(cas) // update target to use FQDN for _, ip := range candidateIPs { names, err := net.LookupAddr(ip.String()) if err != nil { log.Debugf("Unable to perform reverse lookup of IP address: %s", err) } // check all the returned names, and lastly the raw IP for _, n := range append(names, ip.String()) { opts := x509.VerifyOptions{ Roots: pool, DNSName: n, } _, err := cert.Verify(opts) if err == nil { // this identifier will work log.Debugf("Matched %s for use against host certificate", n) // trim '.' fqdn suffix if fqdn return strings.TrimSuffix(n, "."), nil } log.Debugf("Checked %s, no match for host cert", n) } } // no viable address return "", errors.New("unable to determine viable address") }
func main() { interPEMPtr := flag.String("inter", "", "a PEM file containing intermediates") rootPEMPtr := flag.String("roots", "", "a PEM file containing roots") crlPtr := flag.String("crl", "", "a CRL file") flag.Parse() var rootPool, intermediatePool *x509.CertPool var roots, intermediates []*x509.Certificate if nil != rootPEMPtr && len(*rootPEMPtr) > 0 { rootPool, roots = loadCertPool(*rootPEMPtr) } if nil != interPEMPtr && len(*interPEMPtr) > 0 { intermediatePool, intermediates = loadCertPool(*interPEMPtr) } var crlData []byte if nil != crlPtr && len(*crlPtr) > 0 { // Get the crl from the args var err error crlData, err = ioutil.ReadFile(*crlPtr) check(err) } if len(crlData) > 0 { // Maybe it's PEM; try to parse as PEM, if that fails, just use the bytes block, _ := pem.Decode(crlData) if block != nil { crlData = block.Bytes } crl, err := x509.ParseCRL(crlData) if err != nil { panic("could not parse CRL") } // check the CRL is still current if crl.HasExpired(time.Now()) { fmt.Printf("crl has expired\n") } var signer *x509.Certificate if nil != roots { signer = findSigningCert(roots, crl) if nil == signer { fmt.Printf("Not signed by a root; trying known intermediates\n") if nil != intermediates { signer = findSigningCert(intermediates, crl) } } } if nil != signer { fmt.Printf("found signer! %v\n", signer.Subject) opts := x509.VerifyOptions{ Roots: rootPool, Intermediates: intermediatePool, } if _, err := signer.Verify(opts); err != nil { fmt.Println("Warning! Can't verify signer!") } } issuerData, err := asn1.Marshal(crl.TBSCertList.Issuer) if nil == err { issuerString := base64.StdEncoding.EncodeToString(issuerData) fmt.Printf("%v\n", issuerString) } for revoked := range crl.TBSCertList.RevokedCertificates { cert := crl.TBSCertList.RevokedCertificates[revoked] fmt.Printf(" %v\n", base64.StdEncoding.EncodeToString(cert.SerialNumber.Bytes())) } } }
//isChainValid creates the valid certificate chains by combining the chain retrieved with the provided truststore. //It return true if it finds at least on validation chain or false if no valid chain of trust can be created. //It also updates the certificate map which gets pushed at the end of each iteration. func isChainValid(endEntity *x509.Certificate, intermediates []*x509.Certificate, truststore *certificate.TrustStore, domain, IP string, certmap map[string]certificate.Certificate) bool { valInfo := &certificate.ValidationInfo{ IsValid: true, } // build a CA verification pool from the list of cacerts interPool := x509.NewCertPool() for _, entity := range intermediates { interPool.AddCert(entity) } // get a list of domains this certificate is supposedly valid for // if the end entity is a CA, use its common name dnsName := domain if endEntity.IsCA { dnsName = endEntity.Subject.CommonName } // configure the verification logic to use the current trustore opts := x509.VerifyOptions{ DNSName: dnsName, Intermediates: interPool, Roots: truststore.Certs, } // Verify attempts to build all the path between the end entity and the // root in the truststore that validate the certificate // If no valid path is found, err is not nil and the certificate is not trusted chains, err := endEntity.Verify(opts) if err == nil { // the end entity is trusted, we need to go through each // chain of trust and store them in database for i, chain := range chains { log.WithFields(logrus.Fields{ "trust chain no": i, "path len": len(chain), }).Debug("domain: " + domain) // loop through each certificate in the chain and for _, cert := range chain { parentSignature := "" parentCert := getFirstParent(cert, chain) if parentCert != nil { parentSignature = certificate.SHA256Hash(parentCert.Raw) } else { log.Println("could not retrieve parent for " + dnsName) } updateCert(cert, parentSignature, domain, IP, truststore.Name, valInfo, certmap) } } return true } // the certificate is not trusted. // we store the cert in DB with its validation error if len(chains) > 0 { log.WithFields(logrus.Fields{ "domain": domain, }).Warning("Got validation error but chains are populated") } valInfo.ValidationError = err.Error() valInfo.IsValid = false parentSignature := "" c := getFirstParent(endEntity, intermediates) if c != nil { parentSignature = certificate.SHA256Hash(c.Raw) } else { log.WithFields(logrus.Fields{ "domain": domain, "servercert": certificate.SHA256Hash(endEntity.Raw), }).Info("Could not get parent") } updateCert(endEntity, parentSignature, domain, IP, truststore.Name, valInfo, certmap) return false }
func (conf *config) validCert(cert *x509.Certificate, intermediates []*x509.Certificate) bool { pool := certPoolWith(intermediates) _, err := cert.Verify(x509.VerifyOptions{Intermediates: pool}) if err == nil { return true } if _, ok := err.(x509.UnknownAuthorityError); !ok { // There was an error, but not because the certificate wasn't signed // by a recognized CA. So we go ahead and use the cert and let // the client experience the same error. return true } if conf.ExtraRootCerts != nil { _, err = cert.Verify(x509.VerifyOptions{Roots: conf.ExtraRootCerts, Intermediates: pool}) if err == nil { return true } if _, ok := err.(x509.UnknownAuthorityError); !ok { return true } } // Before we give up, we'll try fetching some intermediate certificates. if len(cert.IssuingCertificateURL) == 0 { return false } toFetch := cert.IssuingCertificateURL fetched := make(map[string]bool) for i := 0; i < len(toFetch); i++ { certURL := toFetch[i] if fetched[certURL] { continue } resp, err := http.Get(certURL) if err == nil { defer resp.Body.Close() } if err != nil || resp.StatusCode != 200 { continue } fetchedCert, err := ioutil.ReadAll(resp.Body) if err != nil { continue } // The fetched certificate might be in either DER or PEM format. if bytes.Contains(fetchedCert, []byte("-----BEGIN CERTIFICATE-----")) { // It's PEM. var certDER *pem.Block for { certDER, fetchedCert = pem.Decode(fetchedCert) if certDER == nil { break } if certDER.Type != "CERTIFICATE" { continue } thisCert, err := x509.ParseCertificate(certDER.Bytes) if err != nil { continue } pool.AddCert(thisCert) toFetch = append(toFetch, thisCert.IssuingCertificateURL...) } } else { // Hopefully it's DER. thisCert, err := x509.ParseCertificate(fetchedCert) if err != nil { continue } pool.AddCert(thisCert) toFetch = append(toFetch, thisCert.IssuingCertificateURL...) } } _, err = cert.Verify(x509.VerifyOptions{Intermediates: pool}) if err == nil { return true } if _, ok := err.(x509.UnknownAuthorityError); !ok { // There was an error, but not because the certificate wasn't signed // by a recognized CA. So we go ahead and use the cert and let // the client experience the same error. return true } return false }
func (hs *clientHandshakeState) doFullHandshake() error { c := hs.c var leaf *x509.Certificate if hs.suite.flags&suitePSK == 0 { msg, err := c.readHandshake() if err != nil { return err } certMsg, ok := msg.(*certificateMsg) if !ok || len(certMsg.certificates) == 0 { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(certMsg, msg) } hs.writeServerHash(certMsg.marshal()) certs := make([]*x509.Certificate, len(certMsg.certificates)) for i, asn1Data := range certMsg.certificates { cert, err := x509.ParseCertificate(asn1Data) if err != nil { c.sendAlert(alertBadCertificate) return errors.New("tls: failed to parse certificate from server: " + err.Error()) } certs[i] = cert } leaf = certs[0] if !c.config.InsecureSkipVerify { opts := x509.VerifyOptions{ Roots: c.config.RootCAs, CurrentTime: c.config.time(), DNSName: c.config.ServerName, Intermediates: x509.NewCertPool(), } for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } c.verifiedChains, err = leaf.Verify(opts) if err != nil { c.sendAlert(alertBadCertificate) return err } } switch leaf.PublicKey.(type) { case *rsa.PublicKey, *ecdsa.PublicKey: break default: c.sendAlert(alertUnsupportedCertificate) return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", leaf.PublicKey) } c.peerCertificates = certs } if hs.serverHello.ocspStapling { msg, err := c.readHandshake() if err != nil { return err } cs, ok := msg.(*certificateStatusMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(cs, msg) } hs.writeServerHash(cs.marshal()) if cs.statusType == statusTypeOCSP { c.ocspResponse = cs.response } } msg, err := c.readHandshake() if err != nil { return err } keyAgreement := hs.suite.ka(c.vers) skx, ok := msg.(*serverKeyExchangeMsg) if ok { hs.writeServerHash(skx.marshal()) err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, leaf, skx) if err != nil { c.sendAlert(alertUnexpectedMessage) return err } msg, err = c.readHandshake() if err != nil { return err } } var chainToSend *Certificate var certRequested bool certReq, ok := msg.(*certificateRequestMsg) if ok { certRequested = true // RFC 4346 on the certificateAuthorities field: // A list of the distinguished names of acceptable certificate // authorities. These distinguished names may specify a desired // distinguished name for a root CA or for a subordinate CA; // thus, this message can be used to describe both known roots // and a desired authorization space. If the // certificate_authorities list is empty then the client MAY // send any certificate of the appropriate // ClientCertificateType, unless there is some external // arrangement to the contrary. hs.writeServerHash(certReq.marshal()) var rsaAvail, ecdsaAvail bool for _, certType := range certReq.certificateTypes { switch certType { case CertTypeRSASign: rsaAvail = true case CertTypeECDSASign: ecdsaAvail = true } } // We need to search our list of client certs for one // where SignatureAlgorithm is RSA and the Issuer is in // certReq.certificateAuthorities findCert: for i, chain := range c.config.Certificates { if !rsaAvail && !ecdsaAvail { continue } for j, cert := range chain.Certificate { x509Cert := chain.Leaf // parse the certificate if this isn't the leaf // node, or if chain.Leaf was nil if j != 0 || x509Cert == nil { if x509Cert, err = x509.ParseCertificate(cert); err != nil { c.sendAlert(alertInternalError) return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error()) } } switch { case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA: case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA: default: continue findCert } if len(certReq.certificateAuthorities) == 0 { // they gave us an empty list, so just take the // first RSA cert from c.config.Certificates chainToSend = &chain break findCert } for _, ca := range certReq.certificateAuthorities { if bytes.Equal(x509Cert.RawIssuer, ca) { chainToSend = &chain break findCert } } } } msg, err = c.readHandshake() if err != nil { return err } } shd, ok := msg.(*serverHelloDoneMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(shd, msg) } hs.writeServerHash(shd.marshal()) // If the server requested a certificate then we have to send a // Certificate message, even if it's empty because we don't have a // certificate to send. if certRequested { certMsg := new(certificateMsg) if chainToSend != nil { certMsg.certificates = chainToSend.Certificate } hs.writeClientHash(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) } preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, leaf) if err != nil { c.sendAlert(alertInternalError) return err } if ckx != nil { if c.config.Bugs.EarlyChangeCipherSpec < 2 { hs.writeClientHash(ckx.marshal()) } c.writeRecord(recordTypeHandshake, ckx.marshal()) } if hs.serverHello.extendedMasterSecret && c.vers >= VersionTLS10 { hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash) c.extendedMasterSecret = true } else { if c.config.Bugs.RequireExtendedMasterSecret { return errors.New("tls: extended master secret required but not supported by peer") } hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) } if chainToSend != nil { var signed []byte certVerify := &certificateVerifyMsg{ hasSignatureAndHash: c.vers >= VersionTLS12, } switch key := c.config.Certificates[0].PrivateKey.(type) { case *ecdsa.PrivateKey: certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureECDSA) if err != nil { break } var digest []byte digest, _, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) if err != nil { break } var r, s *big.Int r, s, err = ecdsa.Sign(c.config.rand(), key, digest) if err == nil { signed, err = asn1.Marshal(ecdsaSignature{r, s}) } case *rsa.PrivateKey: certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureRSA) if err != nil { break } var digest []byte var hashFunc crypto.Hash digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) if err != nil { break } signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest) default: err = errors.New("unknown private key type") } if err != nil { c.sendAlert(alertInternalError) return errors.New("tls: failed to sign handshake with client certificate: " + err.Error()) } certVerify.signature = signed hs.writeClientHash(certVerify.marshal()) c.writeRecord(recordTypeHandshake, certVerify.marshal()) } c.dtlsFlushHandshake() hs.finishedHash.discardHandshakeBuffer() return nil }
func CheckCertAgainRoot(x509Cert *x509.Certificate, certPool *x509.CertPool) ([][]*x509.Certificate, error) { opts := x509.VerifyOptions{ // TODO DNSName: "test.example.com", Roots: certPool, } return x509Cert.Verify(opts) }