// 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 }
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) } }