package main import ( "crypto/tls" "crypto/x509" "encoding/pem" "encoding/xml" "fmt" "io" "net" "net/url" "os" "strings" ) type xmppStreamsFeatures struct { XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"` } type xmppTlsProceed struct { XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls proceed"` } func xmppStartTLS(connRaw net.Conn, host string) error { decoder := xml.NewDecoder(connRaw) // send start _, err := fmt.Fprintf(connRaw, "", host) if err != nil { return err } // read start for { t, err := decoder.Token() if err != nil || t == nil { return err } if se, ok := t.(xml.StartElement); ok { if se.Name.Local != "stream" { return xml.UnmarshalError(fmt.Sprintf("expected element of type <%s> but have <%s>", "stream", se.Name.Local)) } break } } // read var features xmppStreamsFeatures err = decoder.DecodeElement(&features, nil) if err != nil { return err } // send _, err = io.WriteString(connRaw, "") if err != nil { return err } // read var proceed xmppTlsProceed err = decoder.DecodeElement(&proceed, nil) if err != nil { return err } return nil } func getcert(socket string) (*x509.Certificate, error) { u, err := url.Parse(socket) if err != nil { return nil, err } host, _, err := net.SplitHostPort(u.Host) if err != nil { return nil, err } connRaw, err := net.Dial(u.Scheme, u.Host) if err != nil { return nil, err } switch u.Path { case "", "/": // do nothing case "/xmpp": err = xmppStartTLS(connRaw, host) if err != nil { return nil, err } default: return nil, fmt.Errorf("Unknown negotiation path: %q", u.Path) } connTLS := tls.Client(connRaw, &tls.Config{InsecureSkipVerify: true}) defer connTLS.Close() err = connTLS.Handshake() if err != nil { return nil, err } cstate := connTLS.ConnectionState() opts := x509.VerifyOptions{ DNSName: host, Intermediates: x509.NewCertPool(), } for _, cert := range cstate.PeerCertificates[1:] { opts.Intermediates.AddCert(cert) } cert := cstate.PeerCertificates[0] _, err = cert.Verify(opts) return cert, err } func split(socket string) (net, addr string) { ary := strings.SplitN(socket, ":", 2) if len(ary) == 1 { return "tcp", ary[0] } return ary[0], ary[1] } func main() { for _, socket := range os.Args[1:] { block := pem.Block{ Type: "CERTIFICATE", Headers: map[string]string{"X-Socket": socket}, Bytes: nil, } cert, err := getcert(socket) if cert != nil { block.Bytes = cert.Raw } if err != nil { block.Headers["X-Error"] = err.Error() } pem.Encode(os.Stdout, &block) } }