func decodeCertChain(chainPEM string) (chain x509Chain, err error) { certPEMBlock := []byte(chainPEM) var certDERBlock *pem.Block var cert tls.Certificate for { certDERBlock, certPEMBlock = pem.Decode([]byte(certPEMBlock)) if certDERBlock == nil { break } if certDERBlock.Type == "CERTIFICATE" { cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) } } if len(cert.Certificate) == 0 { err = errors.New("failed to parse certificate PEM data") return } var x509Cert *x509.Certificate for _, c := range cert.Certificate { x509Cert, err = x509.ParseCertificate(c) if err != nil { return } chain = append(chain, *x509Cert) } return }
// FromPemBytes loads a PEM certificate from an in memory byte array and // returns a tls.Certificate. This function is similar to the crypto/tls // X509KeyPair function, however it supports PEM files with the cert and // key combined, as well as password protected keys which are both common with // APNs certificates. // // Use "" as the password argument if the PEM certificate is not password // protected. func FromPemBytes(bytes []byte, password string) (tls.Certificate, error) { var cert tls.Certificate var block *pem.Block for { block, bytes = pem.Decode(bytes) if block == nil { break } if block.Type == "CERTIFICATE" { cert.Certificate = append(cert.Certificate, block.Bytes) } if block.Type == "PRIVATE KEY" || strings.HasSuffix(block.Type, "PRIVATE KEY") { key, err := unencryptPrivateKey(block, password) if err != nil { return tls.Certificate{}, err } cert.PrivateKey = key } } if len(cert.Certificate) == 0 { return tls.Certificate{}, ErrNoCertificate } if cert.PrivateKey == nil { return tls.Certificate{}, ErrNoPrivateKey } if c, e := x509.ParseCertificate(cert.Certificate[0]); e == nil { cert.Leaf = c } return cert, nil }
// Intercepts an SSL connection to a remote server. The request will instead be // redirected to the socket configured at p.SocketPath. // // SSL Added and removed here! :-) func (p *InterceptingProxyHandler) interceptRequest(w http.ResponseWriter, r *http.Request) { log.Println("hijacking TLS connection") tlsConn, err := tls.Dial("tcp", r.URL.Host, nil) defer tlsConn.Close() if err != nil { log.Println("error dialing TLS, falling back:", err) p.doConnectRequest(w, r) return } cs := tlsConn.ConnectionState() peerCerts := cs.PeerCertificates fakedCert := tls.Certificate{} fakedCert.PrivateKey = p.privateKey for _, peerCert := range peerCerts { fakedCert.Certificate = append(fakedCert.Certificate, peerCert.Raw) } host, _, _ := net.SplitHostPort(r.URL.Host) config := &tls.Config{ Certificates: []tls.Certificate{fakedCert}, ServerName: host, PreferServerCipherSuites: true, CipherSuites: VulnerableCipherSuites, MaxVersion: tls.VersionTLS11, } w.WriteHeader(http.StatusOK) hijackedConnection, _, err := w.(http.Hijacker).Hijack() if err != nil { log.Println("error hijacking connection", err) return } serverConn := tls.Server(hijackedConnection, config) if err := serverConn.Handshake(); err != nil { log.Println("error during handshake:", err) return } interceptorConn, err := net.Dial("unix", p.SocketPath) if err != nil { log.Println("error dialing socket:", err) return } go io.Copy(serverConn, interceptorConn) go io.Copy(interceptorConn, serverConn) }
// GetTLSConfig returns a TLS config generally suitable for client // authentiation. The returned TLS config can be modified slightly // to be made suitable for a server requiring client authentication; // specifically, you should set the value of ClientAuth in the returned // config to match your needs. func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) { tlsCert := tls.Certificate{ Certificate: [][]byte{}, } tlsConfig := &tls.Config{ MinVersion: tls.VersionTLS12, } if p.Certificate != nil { tlsCert.Leaf = p.Certificate } if p.PrivateKey != nil { tlsCert.PrivateKey = p.PrivateKey } if p.CertificateBytes != nil && len(p.CertificateBytes) > 0 { tlsCert.Certificate = append(tlsCert.Certificate, p.CertificateBytes) } if len(p.CAChain) > 0 { for _, cert := range p.CAChain { tlsCert.Certificate = append(tlsCert.Certificate, cert.Bytes) } // Technically we only need one cert, but this doesn't duplicate code certBundle, err := p.ToCertBundle() if err != nil { return nil, fmt.Errorf("Error converting parsed bundle to string bundle when getting TLS config: %s", err) } caPool := x509.NewCertPool() ok := caPool.AppendCertsFromPEM([]byte(certBundle.CAChain[0])) if !ok { return nil, fmt.Errorf("Could not append CA certificate") } if usage&TLSServer > 0 { tlsConfig.ClientCAs = caPool tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven } if usage&TLSClient > 0 { tlsConfig.RootCAs = caPool } } if tlsCert.Certificate != nil && len(tlsCert.Certificate) > 0 { tlsConfig.Certificates = []tls.Certificate{tlsCert} tlsConfig.BuildNameToCertificate() } return tlsConfig, nil }
// imitateCertificate returns a new TLS certificate that has most of the same // data as serverCert but is signed by Redwood's root certificate, or // self-signed. func imitateCertificate(serverCert *x509.Certificate, selfSigned bool, conf *config) (cert tls.Certificate, err error) { template := serverCert if selfSigned { template = &x509.Certificate{ SerialNumber: new(big.Int).SetInt64(0), Subject: serverCert.Subject, NotBefore: serverCert.NotBefore, NotAfter: serverCert.NotAfter, KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, ExtKeyUsage: serverCert.ExtKeyUsage, DNSNames: serverCert.DNSNames, } } else { // Use a hash of the real certificate as the serial number. h := md5.New() h.Write(serverCert.Raw) h.Write([]byte{1}) // To give different serial numbers after the key usage change. template.SerialNumber = big.NewInt(0).SetBytes(h.Sum(nil)) if err != nil { return tls.Certificate{}, fmt.Errorf("failed to generate serial number: %s", err) } template.SubjectKeyId = nil template.AuthorityKeyId = nil template.OCSPServer = nil template.IssuingCertificateURL = nil template.CRLDistributionPoints = nil template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment template.BasicConstraintsValid = false template.SignatureAlgorithm = x509.UnknownSignatureAlgorithm } var newCertBytes []byte if selfSigned { newCertBytes, err = x509.CreateCertificate(rand.Reader, template, template, conf.ParsedTLSCert.PublicKey, conf.TLSCert.PrivateKey) } else { newCertBytes, err = x509.CreateCertificate(rand.Reader, template, conf.ParsedTLSCert, conf.ParsedTLSCert.PublicKey, conf.TLSCert.PrivateKey) } if err != nil { return tls.Certificate{}, err } newCert := tls.Certificate{ Certificate: [][]byte{newCertBytes}, PrivateKey: conf.TLSCert.PrivateKey, } if !selfSigned { newCert.Certificate = append(newCert.Certificate, conf.TLSCert.Certificate...) } return newCert, nil }
func (uh *UsersCertificateHandler) Get(request *http.Request) (userid string, err error) { if uh.verifiedHeader != "" && uh.verifiedHeaderValue != "" { // Use incoming HTTP headers. if request.Header.Get(uh.verifiedHeader) != uh.verifiedHeaderValue { // Verify header does not match - ignore incoming userid. return } if uh.certificateHeader != "" { // Read userid from certificate in header if configured. var cert tls.Certificate var certDERBlock *pem.Block // Whuahah this is an evil fix to get back valid PEM data from Nginx $ssl_client_cert values. certString := strings.Replace(request.Header.Get(uh.certificateHeader), " ", "\n", -1) certString = strings.Replace(certString, "BEGIN\n", "BEGIN ", 1) certString = strings.Replace(certString, "END\n", "END ", 1) certPEMBlock := []byte(certString) for { certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) if certDERBlock == nil { break } if certDERBlock.Type == "CERTIFICATE" { cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) } } if len(cert.Certificate) == 0 { err = errors.New("failed to parse certificate PEM data") return } var certificates []*x509.Certificate if certificates, err = x509.ParseCertificates(cert.Certificate[0]); err == nil { userid = certificates[0].Subject.CommonName } } } else { // Direct TLS termination and authentication. if request.TLS == nil || len(request.TLS.VerifiedChains) == 0 { return } chain := request.TLS.VerifiedChains[0] if len(chain) == 0 { return } cert := chain[0] userid = cert.Subject.CommonName } log.Printf("Client certificate found for user: %s\n", userid) return }
func decodePem(certInput string) tls.Certificate { var cert tls.Certificate certPEMBlock := []byte(certInput) var certDERBlock *pem.Block for { certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) if certDERBlock == nil { break } if certDERBlock.Type == "CERTIFICATE" { cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) } } return cert }
// Include our root certificate in TLS. // // THIS IS A MODIFICATION TO THE ORIGINAL // VERSION OF THE SOURCE CODE. // CHANGED ON SEPTEMBER 05, 2013 // // This builds on the gist available at: // https://gist.github.com/laher/5795578 // and is meant to resolve the error: // "x509: failed to load system roots and no roots provided" // This happens since cross-compiling disables cgo - // however cgo is required to find system root // certificates on darwin machines. Note that the client // returned can only connect successfully to the // supplied s3's region. func getHttpClient(s3 *S3) (*http.Client, error) { // get the pem string by running openssl. Note that the // endpoint will only work for the regional s3 endpoint // supplied out, err := exec.Command("openssl", "s_client", "-showcerts", "-connect", strings.Replace(s3.Region.S3Endpoint, "https://", "", -1)+":443").Output() if err != nil { return nil, err } certInput := string(out) // decode the pem string returned by openssl var certChain tls.Certificate certPEMBlock := []byte(certInput) var certDERBlock *pem.Block for { certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) if certDERBlock == nil { break } if certDERBlock.Type == "CERTIFICATE" { certChain.Certificate = append(certChain.Certificate, certDERBlock.Bytes) } } // inititalize our tls certificate config conf := tls.Config{} // we're creating a new cert pool here // to use for TLS conf.RootCAs = x509.NewCertPool() for _, cert := range certChain.Certificate { x509Cert, err := x509.ParseCertificate(cert) if err != nil { return nil, err } conf.RootCAs.AddCert(x509Cert) } // map certificate names to actual certificates conf.BuildNameToCertificate() // create a Transport which inlcudes our TLS config tr := http.Transport{TLSClientConfig: &conf} // add the Transport to our http client return &http.Client{Transport: &tr}, nil }
func loadCertificate() (tls.Certificate, error) { if *p12File != "" { cert := tls.Certificate{} b, err := ioutil.ReadFile(*p12File) if err != nil { return cert, err } key, cer, err := pkcs12.Decode(b, *p12Password) if err != nil { return cert, err } cert.PrivateKey = key cert.Certificate = [][]byte{cer.Raw} return cert, nil } else { return tls.LoadX509KeyPair(*cerFile, *keyFile) } }
// imitateCertificate returns a new TLS certificate that has most of the same // data as serverCert but is signed by Redwood's root certificate, or // self-signed. func imitateCertificate(serverCert *x509.Certificate, selfSigned bool, conf *config) (cert tls.Certificate, err error) { // Use a hash of the real certificate as the serial number. h := md5.New() h.Write(serverCert.Raw) h.Write([]byte{2}) template := &x509.Certificate{ SerialNumber: big.NewInt(0).SetBytes(h.Sum(nil)), Subject: serverCert.Subject, NotBefore: serverCert.NotBefore, NotAfter: serverCert.NotAfter, KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, ExtKeyUsage: serverCert.ExtKeyUsage, UnknownExtKeyUsage: serverCert.UnknownExtKeyUsage, BasicConstraintsValid: false, SubjectKeyId: nil, DNSNames: serverCert.DNSNames, PermittedDNSDomainsCritical: serverCert.PermittedDNSDomainsCritical, PermittedDNSDomains: serverCert.PermittedDNSDomains, SignatureAlgorithm: x509.UnknownSignatureAlgorithm, } var newCertBytes []byte if selfSigned { newCertBytes, err = x509.CreateCertificate(rand.Reader, template, template, conf.ParsedTLSCert.PublicKey, conf.TLSCert.PrivateKey) } else { newCertBytes, err = x509.CreateCertificate(rand.Reader, template, conf.ParsedTLSCert, conf.ParsedTLSCert.PublicKey, conf.TLSCert.PrivateKey) } if err != nil { return tls.Certificate{}, err } newCert := tls.Certificate{ Certificate: [][]byte{newCertBytes}, PrivateKey: conf.TLSCert.PrivateKey, } if !selfSigned { newCert.Certificate = append(newCert.Certificate, conf.TLSCert.Certificate...) } return newCert, nil }