1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package xmpp implements the XMPP IM protocol, as specified in RFC 6120 and 6// 6121. 7package xmpp 8 9import ( 10 "crypto/tls" 11 "crypto/x509" 12 "errors" 13 "fmt" 14 "io" 15 "net" 16 17 "github.com/coyim/coyim/xmpp/interfaces" 18) 19 20var tlsVersionStrings = map[uint16]string{ 21 tls.VersionSSL30: "SSL 3.0", 22 tls.VersionTLS10: "TLS 1.0", 23 tls.VersionTLS11: "TLS 1.1", 24 tls.VersionTLS12: "TLS 1.2", 25} 26 27var tlsCipherSuiteNames = map[uint16]string{ 28 tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA", 29 tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", 30 tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", 31 tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA", 32 tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 33 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 34 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 35 tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", 36 tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 37 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 38 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 39 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 40 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 41} 42 43func certName(cert *x509.Certificate) string { 44 name := cert.Subject 45 ret := "" 46 47 for _, org := range name.Organization { 48 ret += "O=" + org + "/" 49 } 50 for _, ou := range name.OrganizationalUnit { 51 ret += "OU=" + ou + "/" 52 } 53 if len(name.CommonName) > 0 { 54 ret += "CN=" + name.CommonName + "/" 55 } 56 return ret 57} 58 59// GetCipherSuiteName returns a human readable string of the cipher suite used in the state 60func GetCipherSuiteName(tlsState tls.ConnectionState) string { 61 cipherSuite, ok := tlsCipherSuiteNames[tlsState.CipherSuite] 62 if !ok { 63 return "unknown" 64 } 65 return cipherSuite 66} 67 68// GetTLSVersion returns a human readable string of the TLS version used in the state 69func GetTLSVersion(tlsState tls.ConnectionState) string { 70 version, ok := tlsVersionStrings[tlsState.Version] 71 if !ok { 72 return "unknown" 73 } 74 75 return version 76} 77 78func printTLSDetails(w io.Writer, tlsState tls.ConnectionState) { 79 fmt.Fprintf(w, " SSL/TLS version: %s\n", GetTLSVersion(tlsState)) 80 fmt.Fprintf(w, " Cipher suite: %s\n", GetCipherSuiteName(tlsState)) 81} 82 83// RFC 6120, section 5.4 84func (d *dialer) negotiateSTARTTLS(c interfaces.Conn, conn net.Conn) error { 85 // RFC 6120, section 5.3 86 mandatoryToNegotiate := c.Features().StartTLS.Required.Local == "required" 87 if c.Config().SkipTLS && !mandatoryToNegotiate { 88 return nil 89 } 90 91 // Section 5.2 states: 92 // "Support for STARTTLS is REQUIRED in XMPP client and server implementations" 93 if c.Features().StartTLS.XMLName.Local == "" { 94 return errors.New("xmpp: server doesn't support TLS") 95 } 96 97 if err := d.startTLS(c, conn); err != nil { 98 return err 99 } 100 101 return c.SendInitialStreamHeader() 102} 103 104func (d *dialer) startTLS(c interfaces.Conn, conn net.Conn) error { 105 fmt.Fprintf(c.Out(), "<starttls xmlns='%s'/>", NsTLS) 106 107 proceed, err := nextStart(c.In()) 108 if err != nil { 109 return err 110 } 111 112 if proceed.Name.Space != NsTLS || proceed.Name.Local != "proceed" { 113 return errors.New("xmpp: expected <proceed> after <starttls> but got <" + proceed.Name.Local + "> in " + proceed.Name.Space) 114 } 115 116 l := c.Config().GetLog() 117 io.WriteString(l, "Starting TLS handshake\n") 118 119 tlsConfig := c.Config().TLSConfig 120 if tlsConfig == nil { 121 tlsConfig = &tls.Config{} 122 } 123 124 tlsConfig.ServerName = c.OriginDomain() 125 tlsConfig.InsecureSkipVerify = true 126 127 tlsConn := d.tlsConnFactory(conn, tlsConfig) 128 if err := tlsConn.Handshake(); err != nil { 129 return err 130 } 131 132 tlsState := tlsConn.ConnectionState() 133 printTLSDetails(l, tlsState) 134 135 if err = d.verifier.Verify(tlsState, tlsConfig, c.OriginDomain()); err != nil { 136 return err 137 } 138 139 d.bindTransport(c, tlsConn) 140 141 return nil 142} 143