github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/protocol/serverEntry.go (about)

     1  /*
     2   * Copyright (c) 2015, Psiphon Inc.
     3   * All rights reserved.
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package protocol
    21  
    22  import (
    23  	"bufio"
    24  	"bytes"
    25  	"crypto/ed25519"
    26  	"crypto/hmac"
    27  	"crypto/rand"
    28  	"crypto/sha256"
    29  	"encoding/base64"
    30  	"encoding/hex"
    31  	"encoding/json"
    32  	"fmt"
    33  	"io"
    34  	"net"
    35  	"strings"
    36  	"time"
    37  
    38  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
    39  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
    40  )
    41  
    42  // ServerEntry represents a Psiphon server. It contains information
    43  // about how to establish a tunnel connection to the server through
    44  // several protocols. Server entries are JSON records downloaded from
    45  // various sources.
    46  type ServerEntry struct {
    47  	Tag                           string   `json:"tag"`
    48  	IpAddress                     string   `json:"ipAddress"`
    49  	WebServerPort                 string   `json:"webServerPort"` // not an int
    50  	WebServerSecret               string   `json:"webServerSecret"`
    51  	WebServerCertificate          string   `json:"webServerCertificate"`
    52  	SshPort                       int      `json:"sshPort"`
    53  	SshUsername                   string   `json:"sshUsername"`
    54  	SshPassword                   string   `json:"sshPassword"`
    55  	SshHostKey                    string   `json:"sshHostKey"`
    56  	SshObfuscatedPort             int      `json:"sshObfuscatedPort"`
    57  	SshObfuscatedQUICPort         int      `json:"sshObfuscatedQUICPort"`
    58  	LimitQUICVersions             []string `json:"limitQUICVersions"`
    59  	SshObfuscatedTapDancePort     int      `json:"sshObfuscatedTapdancePort"`
    60  	SshObfuscatedConjurePort      int      `json:"sshObfuscatedConjurePort"`
    61  	SshObfuscatedKey              string   `json:"sshObfuscatedKey"`
    62  	Capabilities                  []string `json:"capabilities"`
    63  	Region                        string   `json:"region"`
    64  	FrontingProviderID            string   `json:"frontingProviderID"`
    65  	MeekServerPort                int      `json:"meekServerPort"`
    66  	MeekCookieEncryptionPublicKey string   `json:"meekCookieEncryptionPublicKey"`
    67  	MeekObfuscatedKey             string   `json:"meekObfuscatedKey"`
    68  	MeekFrontingHost              string   `json:"meekFrontingHost"`
    69  	MeekFrontingHosts             []string `json:"meekFrontingHosts"`
    70  	MeekFrontingDomain            string   `json:"meekFrontingDomain"`
    71  	MeekFrontingAddresses         []string `json:"meekFrontingAddresses"`
    72  	MeekFrontingAddressesRegex    string   `json:"meekFrontingAddressesRegex"`
    73  	MeekFrontingDisableSNI        bool     `json:"meekFrontingDisableSNI"`
    74  	TacticsRequestPublicKey       string   `json:"tacticsRequestPublicKey"`
    75  	TacticsRequestObfuscatedKey   string   `json:"tacticsRequestObfuscatedKey"`
    76  	ConfigurationVersion          int      `json:"configurationVersion"`
    77  	Signature                     string   `json:"signature"`
    78  
    79  	// These local fields are not expected to be present in downloaded server
    80  	// entries. They are added by the client to record and report stats about
    81  	// how and when server entries are obtained.
    82  	// All local fields should be included the list of fields in RemoveUnsignedFields.
    83  	LocalSource       string `json:"localSource,omitempty"`
    84  	LocalTimestamp    string `json:"localTimestamp,omitempty"`
    85  	IsLocalDerivedTag bool   `json:"isLocalDerivedTag,omitempty"`
    86  }
    87  
    88  // ServerEntryFields is an alternate representation of ServerEntry which
    89  // enables future compatibility when unmarshaling and persisting new server
    90  // entries which may contain new, unrecognized fields not in the ServerEntry
    91  // type for a particular client version.
    92  //
    93  // When new JSON server entries with new fields are unmarshaled to ServerEntry
    94  // types, unrecognized fields are discarded. When unmarshaled to
    95  // ServerEntryFields, unrecognized fields are retained and may be persisted
    96  // and available when the client is upgraded and unmarshals to an updated
    97  // ServerEntry type.
    98  type ServerEntryFields map[string]interface{}
    99  
   100  // GetServerEntry converts a ServerEntryFields into a ServerEntry.
   101  func (fields ServerEntryFields) GetServerEntry() (*ServerEntry, error) {
   102  
   103  	marshaledServerEntry, err := json.Marshal(fields)
   104  	if err != nil {
   105  		return nil, errors.Trace(err)
   106  	}
   107  
   108  	var serverEntry *ServerEntry
   109  	err = json.Unmarshal(marshaledServerEntry, &serverEntry)
   110  	if err != nil {
   111  		return nil, errors.Trace(err)
   112  	}
   113  
   114  	return serverEntry, nil
   115  }
   116  
   117  func (fields ServerEntryFields) GetTag() string {
   118  	tag, ok := fields["tag"]
   119  	if !ok {
   120  		return ""
   121  	}
   122  	tagStr, ok := tag.(string)
   123  	if !ok {
   124  		return ""
   125  	}
   126  	return tagStr
   127  }
   128  
   129  // SetTag sets a local, derived server entry tag. A tag is an identifier used
   130  // in server entry pruning and potentially other use cases. An explict tag,
   131  // set by the Psiphon Network, may be present in a server entry that is
   132  // imported; otherwise, the client will set a derived tag. The tag should be
   133  // generated using GenerateServerEntryTag. When SetTag finds a explicit tag,
   134  // the new, derived tag is ignored. The isLocalTag local field is set to
   135  // distinguish explict and derived tags and is used in signature verification
   136  // to determine if the tag field is part of the signature.
   137  func (fields ServerEntryFields) SetTag(tag string) {
   138  
   139  	// Don't replace explicit tag
   140  	if tag, ok := fields["tag"]; ok {
   141  		tagStr, ok := tag.(string)
   142  		if ok && tagStr != "" {
   143  			isLocalDerivedTag, ok := fields["isLocalDerivedTag"]
   144  			if !ok {
   145  				return
   146  			}
   147  			isLocalDerivedTagBool, ok := isLocalDerivedTag.(bool)
   148  			if ok && !isLocalDerivedTagBool {
   149  				return
   150  			}
   151  		}
   152  	}
   153  
   154  	fields["tag"] = tag
   155  
   156  	// Mark this tag as local
   157  	fields["isLocalDerivedTag"] = true
   158  }
   159  
   160  func (fields ServerEntryFields) GetDiagnosticID() string {
   161  	tag, ok := fields["tag"]
   162  	if !ok {
   163  		return ""
   164  	}
   165  	tagStr, ok := tag.(string)
   166  	if !ok {
   167  		return ""
   168  	}
   169  	return TagToDiagnosticID(tagStr)
   170  }
   171  
   172  func (fields ServerEntryFields) GetIPAddress() string {
   173  	ipAddress, ok := fields["ipAddress"]
   174  	if !ok {
   175  		return ""
   176  	}
   177  	ipAddressStr, ok := ipAddress.(string)
   178  	if !ok {
   179  		return ""
   180  	}
   181  	return ipAddressStr
   182  }
   183  
   184  func (fields ServerEntryFields) GetWebServerPort() string {
   185  	webServerPort, ok := fields["webServerPort"]
   186  	if !ok {
   187  		return ""
   188  	}
   189  	webServerPortStr, ok := webServerPort.(string)
   190  	if !ok {
   191  		return ""
   192  	}
   193  	return webServerPortStr
   194  }
   195  
   196  func (fields ServerEntryFields) GetWebServerSecret() string {
   197  	webServerSecret, ok := fields["webServerSecret"]
   198  	if !ok {
   199  		return ""
   200  	}
   201  	webServerSecretStr, ok := webServerSecret.(string)
   202  	if !ok {
   203  		return ""
   204  	}
   205  	return webServerSecretStr
   206  }
   207  
   208  func (fields ServerEntryFields) GetWebServerCertificate() string {
   209  	webServerCertificate, ok := fields["webServerCertificate"]
   210  	if !ok {
   211  		return ""
   212  	}
   213  	webServerCertificateStr, ok := webServerCertificate.(string)
   214  	if !ok {
   215  		return ""
   216  	}
   217  	return webServerCertificateStr
   218  }
   219  
   220  func (fields ServerEntryFields) GetConfigurationVersion() int {
   221  	configurationVersion, ok := fields["configurationVersion"]
   222  	if !ok {
   223  		return 0
   224  	}
   225  	configurationVersionFloat, ok := configurationVersion.(float64)
   226  	if !ok {
   227  		return 0
   228  	}
   229  	return int(configurationVersionFloat)
   230  }
   231  
   232  func (fields ServerEntryFields) GetLocalSource() string {
   233  	localSource, ok := fields["localSource"]
   234  	if !ok {
   235  		return ""
   236  	}
   237  	localSourceStr, ok := localSource.(string)
   238  	if !ok {
   239  		return ""
   240  	}
   241  	return localSourceStr
   242  }
   243  
   244  func (fields ServerEntryFields) SetLocalSource(source string) {
   245  	fields["localSource"] = source
   246  }
   247  
   248  func (fields ServerEntryFields) GetLocalTimestamp() string {
   249  	localTimestamp, ok := fields["localTimestamp"]
   250  	if !ok {
   251  		return ""
   252  	}
   253  	localTimestampStr, ok := localTimestamp.(string)
   254  	if !ok {
   255  		return ""
   256  	}
   257  	return localTimestampStr
   258  }
   259  
   260  func (fields ServerEntryFields) SetLocalTimestamp(timestamp string) {
   261  	fields["localTimestamp"] = timestamp
   262  }
   263  
   264  func (fields ServerEntryFields) HasSignature() bool {
   265  	signature, ok := fields["signature"]
   266  	if !ok {
   267  		return false
   268  	}
   269  	signatureStr, ok := signature.(string)
   270  	if !ok {
   271  		return false
   272  	}
   273  	return signatureStr != ""
   274  }
   275  
   276  const signaturePublicKeyDigestSize = 8
   277  
   278  // AddSignature signs a server entry and attaches a new field containing the
   279  // signature. Any existing "signature" field will be replaced.
   280  //
   281  // The signature incudes a public key ID that is derived from a digest of the
   282  // public key value. This ID is intended for future use when multiple signing
   283  // keys may be deployed.
   284  func (fields ServerEntryFields) AddSignature(publicKey, privateKey string) error {
   285  
   286  	// Make a copy so that removing unsigned fields will have no side effects
   287  	copyFields := make(ServerEntryFields)
   288  	for k, v := range fields {
   289  		copyFields[k] = v
   290  	}
   291  
   292  	copyFields.RemoveUnsignedFields()
   293  
   294  	delete(copyFields, "signature")
   295  
   296  	// Best practise would be to sign the JSON encoded server entry bytes and
   297  	// append the signature to those bytes. However, due to backwards
   298  	// compatibility requirements, we must retain the outer server entry encoding
   299  	// as-is and insert the signature.
   300  	//
   301  	// Limitation: since the verifyier must remarshal its server entry before
   302  	// verifying, the JSON produced there must be a byte-for-byte match to the
   303  	// JSON signed here. The precise output of the JSON encoder that is used,
   304  	// "encoding/json", with default formatting, as of Go 1.11.5, is therefore
   305  	// part of the signature protocol.
   306  	//
   307  	// TODO: use a standard, canonical encoding, such as JCS:
   308  	// https://tools.ietf.org/id/draft-rundgren-json-canonicalization-scheme-05.html
   309  
   310  	marshaledFields, err := json.Marshal(copyFields)
   311  	if err != nil {
   312  		return errors.Trace(err)
   313  	}
   314  
   315  	decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKey)
   316  	if err != nil {
   317  		return errors.Trace(err)
   318  	}
   319  
   320  	publicKeyDigest := sha256.Sum256(decodedPublicKey)
   321  	publicKeyID := publicKeyDigest[:signaturePublicKeyDigestSize]
   322  
   323  	decodedPrivateKey, err := base64.StdEncoding.DecodeString(privateKey)
   324  	if err != nil {
   325  		return errors.Trace(err)
   326  	}
   327  
   328  	signature := ed25519.Sign(decodedPrivateKey, marshaledFields)
   329  
   330  	fields["signature"] = base64.StdEncoding.EncodeToString(
   331  		append(publicKeyID, signature...))
   332  
   333  	return nil
   334  }
   335  
   336  // VerifySignature verifies the signature set by AddSignature.
   337  //
   338  // VerifySignature must be called before using any server entry that is
   339  // imported from an untrusted source, such as client-to-client exchange.
   340  func (fields ServerEntryFields) VerifySignature(publicKey string) error {
   341  
   342  	if publicKey == "" {
   343  		return errors.TraceNew("missing public key")
   344  	}
   345  
   346  	// Make a copy so that removing unsigned fields will have no side effects
   347  	copyFields := make(ServerEntryFields)
   348  	for k, v := range fields {
   349  		copyFields[k] = v
   350  	}
   351  
   352  	signatureField, ok := copyFields["signature"]
   353  	if !ok {
   354  		return errors.TraceNew("missing signature field")
   355  	}
   356  
   357  	signatureFieldStr, ok := signatureField.(string)
   358  	if !ok {
   359  		return errors.TraceNew("invalid signature field")
   360  	}
   361  
   362  	decodedSignatureField, err := base64.StdEncoding.DecodeString(signatureFieldStr)
   363  	if err != nil {
   364  		return errors.Trace(err)
   365  	}
   366  
   367  	if len(decodedSignatureField) < signaturePublicKeyDigestSize {
   368  		return errors.TraceNew("invalid signature field length")
   369  	}
   370  
   371  	publicKeyID := decodedSignatureField[:signaturePublicKeyDigestSize]
   372  	signature := decodedSignatureField[signaturePublicKeyDigestSize:]
   373  
   374  	if len(signature) != ed25519.SignatureSize {
   375  		return errors.TraceNew("invalid signature length")
   376  	}
   377  
   378  	decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKey)
   379  	if err != nil {
   380  		return errors.Trace(err)
   381  	}
   382  
   383  	publicKeyDigest := sha256.Sum256(decodedPublicKey)
   384  	expectedPublicKeyID := publicKeyDigest[:signaturePublicKeyDigestSize]
   385  
   386  	if !bytes.Equal(expectedPublicKeyID, publicKeyID) {
   387  		return errors.TraceNew("unexpected public key ID")
   388  	}
   389  
   390  	copyFields.RemoveUnsignedFields()
   391  
   392  	delete(copyFields, "signature")
   393  
   394  	marshaledFields, err := json.Marshal(copyFields)
   395  	if err != nil {
   396  		return errors.Trace(err)
   397  	}
   398  
   399  	if !ed25519.Verify(decodedPublicKey, marshaledFields, signature) {
   400  		return errors.TraceNew("invalid signature")
   401  	}
   402  
   403  	return nil
   404  }
   405  
   406  // RemoveUnsignedFields prepares a server entry for signing or signature
   407  // verification by removing unsigned fields. The JSON marshalling of the
   408  // remaining fields is the data that is signed.
   409  func (fields ServerEntryFields) RemoveUnsignedFields() {
   410  	delete(fields, "localSource")
   411  	delete(fields, "localTimestamp")
   412  
   413  	// Only non-local, explicit tags are part of the signature
   414  	isLocalDerivedTag := fields["isLocalDerivedTag"]
   415  	isLocalDerivedTagBool, ok := isLocalDerivedTag.(bool)
   416  	if ok && isLocalDerivedTagBool {
   417  		delete(fields, "tag")
   418  	}
   419  	delete(fields, "isLocalDerivedTag")
   420  }
   421  
   422  // NewServerEntrySignatureKeyPair creates an ed25519 key pair for use in
   423  // server entry signing and verification.
   424  func NewServerEntrySignatureKeyPair() (string, string, error) {
   425  
   426  	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
   427  	if err != nil {
   428  		return "", "", errors.Trace(err)
   429  	}
   430  
   431  	return base64.StdEncoding.EncodeToString(publicKey),
   432  		base64.StdEncoding.EncodeToString(privateKey),
   433  		nil
   434  }
   435  
   436  // GetCapability returns the server capability corresponding
   437  // to the tunnel protocol.
   438  func GetCapability(protocol string) string {
   439  	return strings.TrimSuffix(protocol, "-OSSH")
   440  }
   441  
   442  // GetTacticsCapability returns the server tactics capability
   443  // corresponding to the tunnel protocol.
   444  func GetTacticsCapability(protocol string) string {
   445  	return GetCapability(protocol) + "-TACTICS"
   446  }
   447  
   448  // hasCapability indicates if the server entry has the specified capability.
   449  //
   450  // Any internal "PASSTHROUGH-v2 or "PASSTHROUGH" componant in the server
   451  // entry's capabilities is ignored. These PASSTHROUGH components are used to
   452  // mask protocols which are running the passthrough mechanisms from older
   453  // clients which do not implement the passthrough messages. Older clients
   454  // will treat these capabilities as unknown protocols and skip them.
   455  //
   456  // Any "QUICv1" capability is treated as "QUIC". "QUICv1" is used to mask the
   457  // QUIC-OSSH capability from older clients to ensure that older clients do
   458  // not send gQUIC packets to second generation QUICv1-only QUIC-OSSH servers.
   459  // New clients must check SupportsOnlyQUICv1 before selecting a QUIC version;
   460  // for "QUICv1", this ensures that new clients also do not select gQUIC to
   461  // QUICv1-only servers.
   462  func (serverEntry *ServerEntry) hasCapability(requiredCapability string) bool {
   463  	for _, capability := range serverEntry.Capabilities {
   464  
   465  		capability = strings.ReplaceAll(capability, "-PASSTHROUGH-v2", "")
   466  		capability = strings.ReplaceAll(capability, "-PASSTHROUGH", "")
   467  
   468  		quicCapability := GetCapability(TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH)
   469  		if capability == quicCapability+"v1" {
   470  			capability = quicCapability
   471  		}
   472  
   473  		if capability == requiredCapability {
   474  			return true
   475  		}
   476  	}
   477  	return false
   478  }
   479  
   480  // SupportsProtocol returns true if and only if the ServerEntry has
   481  // the necessary capability to support the specified tunnel protocol.
   482  func (serverEntry *ServerEntry) SupportsProtocol(protocol string) bool {
   483  	requiredCapability := GetCapability(protocol)
   484  	return serverEntry.hasCapability(requiredCapability)
   485  }
   486  
   487  // ProtocolUsesLegacyPassthrough indicates whether the ServerEntry supports
   488  // the specified protocol using legacy passthrough messages.
   489  //
   490  // There is no corresponding check for v2 passthrough, as clients send v2
   491  // passthrough messages unconditionally, by default, for passthrough
   492  // protocols.
   493  func (serverEntry *ServerEntry) ProtocolUsesLegacyPassthrough(protocol string) bool {
   494  	legacyCapability := GetCapability(protocol) + "-PASSTHROUGH"
   495  	for _, capability := range serverEntry.Capabilities {
   496  		if capability == legacyCapability {
   497  			return true
   498  		}
   499  	}
   500  	return false
   501  }
   502  
   503  // SupportsOnlyQUICv1 indicates that the QUIC-OSSH server supports only QUICv1
   504  // and gQUIC versions should not be selected, as they will fail to connect
   505  // while sending atypical traffic to the server.
   506  func (serverEntry *ServerEntry) SupportsOnlyQUICv1() bool {
   507  	quicCapability := GetCapability(TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH)
   508  	return common.Contains(serverEntry.Capabilities, quicCapability+"v1") &&
   509  		!common.Contains(serverEntry.Capabilities, quicCapability)
   510  }
   511  
   512  // ConditionallyEnabledComponents defines an interface which can be queried to
   513  // determine which conditionally compiled protocol components are present.
   514  type ConditionallyEnabledComponents interface {
   515  	QUICEnabled() bool
   516  	RefractionNetworkingEnabled() bool
   517  }
   518  
   519  // TunnelProtocolPortLists is a map from tunnel protocol names (or "All") to a
   520  // list of port number ranges.
   521  type TunnelProtocolPortLists map[string]*common.PortList
   522  
   523  // GetSupportedProtocols returns a list of tunnel protocols supported by the
   524  // ServerEntry's capabilities and allowed by various constraints.
   525  func (serverEntry *ServerEntry) GetSupportedProtocols(
   526  	conditionallyEnabled ConditionallyEnabledComponents,
   527  	useUpstreamProxy bool,
   528  	limitTunnelProtocols TunnelProtocols,
   529  	limitTunnelDialPortNumbers TunnelProtocolPortLists,
   530  	limitQUICVersions QUICVersions,
   531  	excludeIntensive bool) TunnelProtocols {
   532  
   533  	supportedProtocols := make(TunnelProtocols, 0)
   534  
   535  	for _, tunnelProtocol := range SupportedTunnelProtocols {
   536  
   537  		if useUpstreamProxy && !TunnelProtocolSupportsUpstreamProxy(tunnelProtocol) {
   538  			continue
   539  		}
   540  
   541  		if len(limitTunnelProtocols) > 0 {
   542  			if !common.Contains(limitTunnelProtocols, tunnelProtocol) {
   543  				continue
   544  			}
   545  		} else {
   546  			if common.Contains(DefaultDisabledTunnelProtocols, tunnelProtocol) {
   547  				continue
   548  			}
   549  		}
   550  
   551  		if excludeIntensive && TunnelProtocolIsResourceIntensive(tunnelProtocol) {
   552  			continue
   553  		}
   554  
   555  		if (TunnelProtocolUsesQUIC(tunnelProtocol) && !conditionallyEnabled.QUICEnabled()) ||
   556  			(TunnelProtocolUsesRefractionNetworking(tunnelProtocol) &&
   557  				!conditionallyEnabled.RefractionNetworkingEnabled()) {
   558  			continue
   559  		}
   560  
   561  		if !serverEntry.SupportsProtocol(tunnelProtocol) {
   562  			continue
   563  		}
   564  
   565  		// If the server is limiting QUIC versions, at least one must be
   566  		// supported. And if tactics is also limiting QUIC versions, there
   567  		// must be a common version in both limit lists for this server entry
   568  		// to support QUIC-OSSH.
   569  		//
   570  		// Limitation: to avoid additional complexity, we do not consider
   571  		// DisableFrontingProviderQUICVersion here, as fronting providers are
   572  		// expected to support QUICv1 and gQUIC is expected to become
   573  		// obsolete in general.
   574  
   575  		if TunnelProtocolUsesQUIC(tunnelProtocol) && len(serverEntry.LimitQUICVersions) > 0 {
   576  			if !common.ContainsAny(serverEntry.LimitQUICVersions, SupportedQUICVersions) {
   577  				continue
   578  			}
   579  			if len(limitQUICVersions) > 0 &&
   580  				!common.ContainsAny(serverEntry.LimitQUICVersions, limitQUICVersions) {
   581  				continue
   582  			}
   583  		}
   584  
   585  		dialPortNumber, err := serverEntry.GetDialPortNumber(tunnelProtocol)
   586  		if err != nil {
   587  			continue
   588  		}
   589  
   590  		if len(limitTunnelDialPortNumbers) > 0 {
   591  			if portList, ok := limitTunnelDialPortNumbers[tunnelProtocol]; ok {
   592  				if !portList.Lookup(dialPortNumber) {
   593  					continue
   594  				}
   595  			} else if portList, ok := limitTunnelDialPortNumbers[TUNNEL_PROTOCOLS_ALL]; ok {
   596  				if !portList.Lookup(dialPortNumber) {
   597  					continue
   598  				}
   599  			}
   600  		}
   601  
   602  		supportedProtocols = append(supportedProtocols, tunnelProtocol)
   603  
   604  	}
   605  	return supportedProtocols
   606  }
   607  
   608  func (serverEntry *ServerEntry) GetDialPortNumber(tunnelProtocol string) (int, error) {
   609  
   610  	if !serverEntry.SupportsProtocol(tunnelProtocol) {
   611  		return 0, errors.TraceNew("protocol not supported")
   612  	}
   613  
   614  	switch tunnelProtocol {
   615  
   616  	case TUNNEL_PROTOCOL_SSH:
   617  		return serverEntry.SshPort, nil
   618  
   619  	case TUNNEL_PROTOCOL_OBFUSCATED_SSH:
   620  		return serverEntry.SshObfuscatedPort, nil
   621  
   622  	case TUNNEL_PROTOCOL_TAPDANCE_OBFUSCATED_SSH:
   623  		return serverEntry.SshObfuscatedTapDancePort, nil
   624  
   625  	case TUNNEL_PROTOCOL_CONJURE_OBFUSCATED_SSH:
   626  		return serverEntry.SshObfuscatedConjurePort, nil
   627  
   628  	case TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH:
   629  		return serverEntry.SshObfuscatedQUICPort, nil
   630  
   631  	case TUNNEL_PROTOCOL_FRONTED_MEEK,
   632  		TUNNEL_PROTOCOL_FRONTED_MEEK_QUIC_OBFUSCATED_SSH:
   633  		return 443, nil
   634  
   635  	case TUNNEL_PROTOCOL_FRONTED_MEEK_HTTP:
   636  		return 80, nil
   637  
   638  	case TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS,
   639  		TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET,
   640  		TUNNEL_PROTOCOL_UNFRONTED_MEEK:
   641  		return serverEntry.MeekServerPort, nil
   642  	}
   643  
   644  	return 0, errors.TraceNew("unknown protocol")
   645  }
   646  
   647  // GetSupportedTacticsProtocols returns a list of tunnel protocols,
   648  // supported by the ServerEntry's capabilities, that may be used
   649  // for tactics requests.
   650  func (serverEntry *ServerEntry) GetSupportedTacticsProtocols() []string {
   651  
   652  	supportedProtocols := make([]string, 0)
   653  
   654  	for _, protocol := range SupportedTunnelProtocols {
   655  
   656  		if !TunnelProtocolUsesMeek(protocol) {
   657  			continue
   658  		}
   659  
   660  		requiredCapability := GetTacticsCapability(protocol)
   661  		if !serverEntry.hasCapability(requiredCapability) {
   662  			continue
   663  		}
   664  
   665  		supportedProtocols = append(supportedProtocols, protocol)
   666  	}
   667  
   668  	return supportedProtocols
   669  }
   670  
   671  // SupportsSSHAPIRequests returns true when the server supports
   672  // SSH API requests.
   673  func (serverEntry *ServerEntry) SupportsSSHAPIRequests() bool {
   674  	return serverEntry.hasCapability(CAPABILITY_SSH_API_REQUESTS)
   675  }
   676  
   677  func (serverEntry *ServerEntry) GetUntunneledWebRequestPorts() []string {
   678  	ports := make([]string, 0)
   679  	if serverEntry.hasCapability(CAPABILITY_UNTUNNELED_WEB_API_REQUESTS) {
   680  		// Server-side configuration quirk: there's a port forward from
   681  		// port 443 to the web server, which we can try, except on servers
   682  		// running FRONTED_MEEK, which listens on port 443.
   683  		if !serverEntry.SupportsProtocol(TUNNEL_PROTOCOL_FRONTED_MEEK) {
   684  			ports = append(ports, "443")
   685  		}
   686  		ports = append(ports, serverEntry.WebServerPort)
   687  	}
   688  	return ports
   689  }
   690  
   691  func (serverEntry *ServerEntry) HasSignature() bool {
   692  	return serverEntry.Signature != ""
   693  }
   694  
   695  func (serverEntry *ServerEntry) GetDiagnosticID() string {
   696  	return TagToDiagnosticID(serverEntry.Tag)
   697  }
   698  
   699  // GenerateServerEntryTag creates a server entry tag value that is
   700  // cryptographically derived from the IP address and web server secret in a
   701  // way that is difficult to reverse the IP address value from the tag or
   702  // compute the tag without having the web server secret, a 256-bit random
   703  // value which is unique per server, in addition to the IP address. A database
   704  // consisting only of server entry tags should be resistent to an attack that
   705  // attempts to reverse all the server IPs, even given a small IP space (IPv4),
   706  // or some subset of the web server secrets.
   707  func GenerateServerEntryTag(ipAddress, webServerSecret string) string {
   708  	h := hmac.New(sha256.New, []byte(webServerSecret))
   709  	h.Write([]byte(ipAddress))
   710  	return base64.StdEncoding.EncodeToString(h.Sum(nil))
   711  }
   712  
   713  // TagToDiagnosticID returns a prefix of the server entry tag that should be
   714  // sufficient to uniquely identify servers in diagnostics, while also being
   715  // more human readable than emitting the full tag. The tag is used as the base
   716  // of the diagnostic ID as it doesn't leak the server IP address in diagnostic
   717  // output.
   718  func TagToDiagnosticID(tag string) string {
   719  	if len(tag) < 8 {
   720  		return "<unknown>"
   721  	}
   722  	return tag[:8]
   723  }
   724  
   725  // EncodeServerEntry returns a string containing the encoding of
   726  // a ServerEntry following Psiphon conventions.
   727  func EncodeServerEntry(serverEntry *ServerEntry) (string, error) {
   728  	encodedServerEntry, err := encodeServerEntry(
   729  		serverEntry.IpAddress,
   730  		serverEntry.WebServerPort,
   731  		serverEntry.WebServerSecret,
   732  		serverEntry.WebServerCertificate,
   733  		serverEntry)
   734  	if err != nil {
   735  		return "", errors.Trace(err)
   736  	}
   737  	return encodedServerEntry, nil
   738  }
   739  
   740  // EncodeServerEntryFields returns a string containing the encoding of
   741  // ServerEntryFields following Psiphon conventions.
   742  func EncodeServerEntryFields(serverEntryFields ServerEntryFields) (string, error) {
   743  	encodedServerEntry, err := encodeServerEntry(
   744  		serverEntryFields.GetIPAddress(),
   745  		serverEntryFields.GetWebServerPort(),
   746  		serverEntryFields.GetWebServerSecret(),
   747  		serverEntryFields.GetWebServerCertificate(),
   748  		serverEntryFields)
   749  	if err != nil {
   750  		return "", errors.Trace(err)
   751  	}
   752  	return encodedServerEntry, nil
   753  }
   754  
   755  func encodeServerEntry(
   756  	prefixIPAddress string,
   757  	prefixWebServerPort string,
   758  	prefixWebServerSecret string,
   759  	prefixWebServerCertificate string,
   760  	serverEntry interface{}) (string, error) {
   761  
   762  	serverEntryJSON, err := json.Marshal(serverEntry)
   763  	if err != nil {
   764  		return "", errors.Trace(err)
   765  	}
   766  
   767  	// Legacy clients use a space-delimited fields prefix, and all clients expect
   768  	// to at least parse the prefix in order to skip over it.
   769  	//
   770  	// When the server entry has no web API server certificate, the entire prefix
   771  	// can be compacted down to single character placeholders. Clients that can
   772  	// use the ssh API always prefer it over the web API and won't use the prefix
   773  	// values.
   774  	if len(prefixWebServerCertificate) == 0 {
   775  		prefixIPAddress = "0"
   776  		prefixWebServerPort = "0"
   777  		prefixWebServerSecret = "0"
   778  		prefixWebServerCertificate = "0"
   779  	}
   780  
   781  	return hex.EncodeToString([]byte(fmt.Sprintf(
   782  		"%s %s %s %s %s",
   783  		prefixIPAddress,
   784  		prefixWebServerPort,
   785  		prefixWebServerSecret,
   786  		prefixWebServerCertificate,
   787  		serverEntryJSON))), nil
   788  }
   789  
   790  // DecodeServerEntry extracts a server entry from the encoding
   791  // used by remote server lists and Psiphon server handshake requests.
   792  //
   793  // The resulting ServerEntry.LocalSource is populated with serverEntrySource,
   794  // which should be one of SERVER_ENTRY_SOURCE_EMBEDDED, SERVER_ENTRY_SOURCE_REMOTE,
   795  // SERVER_ENTRY_SOURCE_DISCOVERY, SERVER_ENTRY_SOURCE_TARGET,
   796  // SERVER_ENTRY_SOURCE_OBFUSCATED.
   797  // ServerEntry.LocalTimestamp is populated with the provided timestamp, which
   798  // should be a RFC 3339 formatted string. These local fields are stored with the
   799  // server entry and reported to the server as stats (a coarse granularity timestamp
   800  // is reported).
   801  func DecodeServerEntry(
   802  	encodedServerEntry, timestamp, serverEntrySource string) (*ServerEntry, error) {
   803  
   804  	serverEntry := new(ServerEntry)
   805  	err := decodeServerEntry(encodedServerEntry, timestamp, serverEntrySource, serverEntry)
   806  	if err != nil {
   807  		return nil, errors.Trace(err)
   808  	}
   809  
   810  	// NOTE: if the source JSON happens to have values in these fields, they get clobbered.
   811  	serverEntry.LocalSource = serverEntrySource
   812  	serverEntry.LocalTimestamp = timestamp
   813  
   814  	return serverEntry, nil
   815  }
   816  
   817  // DecodeServerEntryFields extracts an encoded server entry into a
   818  // ServerEntryFields type, much like DecodeServerEntry. Unrecognized fields
   819  // not in ServerEntry are retained in the ServerEntryFields.
   820  //
   821  // LocalSource/LocalTimestamp map entries are set only when the corresponding
   822  // inputs are non-blank.
   823  func DecodeServerEntryFields(
   824  	encodedServerEntry, timestamp, serverEntrySource string) (ServerEntryFields, error) {
   825  
   826  	serverEntryFields := make(ServerEntryFields)
   827  	err := decodeServerEntry(encodedServerEntry, timestamp, serverEntrySource, &serverEntryFields)
   828  	if err != nil {
   829  		return nil, errors.Trace(err)
   830  	}
   831  
   832  	// NOTE: if the source JSON happens to have values in these fields, they get clobbered.
   833  	if serverEntrySource != "" {
   834  		serverEntryFields.SetLocalSource(serverEntrySource)
   835  	}
   836  	if timestamp != "" {
   837  		serverEntryFields.SetLocalTimestamp(timestamp)
   838  	}
   839  
   840  	return serverEntryFields, nil
   841  }
   842  
   843  func decodeServerEntry(
   844  	encodedServerEntry, timestamp, serverEntrySource string,
   845  	target interface{}) error {
   846  
   847  	hexDecodedServerEntry, err := hex.DecodeString(encodedServerEntry)
   848  	if err != nil {
   849  		return errors.Trace(err)
   850  	}
   851  
   852  	// Skip past legacy format (4 space delimited fields) and just parse the JSON config
   853  	fields := bytes.SplitN(hexDecodedServerEntry, []byte(" "), 5)
   854  	if len(fields) != 5 {
   855  		return errors.TraceNew("invalid encoded server entry")
   856  	}
   857  
   858  	err = json.Unmarshal(fields[4], target)
   859  	if err != nil {
   860  		return errors.Trace(err)
   861  	}
   862  
   863  	return nil
   864  }
   865  
   866  // ValidateServerEntryFields checks for malformed server entries.
   867  func ValidateServerEntryFields(serverEntryFields ServerEntryFields) error {
   868  
   869  	// Checks for a valid ipAddress. This is important since the IP
   870  	// address is the key used to store/lookup the server entry.
   871  
   872  	ipAddress := serverEntryFields.GetIPAddress()
   873  	if net.ParseIP(ipAddress) == nil {
   874  		return errors.Tracef("server entry has invalid ipAddress: %s", ipAddress)
   875  	}
   876  
   877  	// TODO: validate more fields?
   878  
   879  	// Ensure locally initialized fields have been set.
   880  
   881  	source := serverEntryFields.GetLocalSource()
   882  	if !common.Contains(
   883  		SupportedServerEntrySources, source) {
   884  		return errors.Tracef("server entry has invalid source: %s", source)
   885  	}
   886  
   887  	timestamp := serverEntryFields.GetLocalTimestamp()
   888  	_, err := time.Parse(time.RFC3339, timestamp)
   889  	if err != nil {
   890  		return errors.Tracef("server entry has invalid timestamp: %s", err)
   891  	}
   892  
   893  	return nil
   894  }
   895  
   896  // DecodeServerEntryList extracts server entries from the list encoding
   897  // used by remote server lists and Psiphon server handshake requests.
   898  // Each server entry is validated and invalid entries are skipped.
   899  // See DecodeServerEntry for note on serverEntrySource/timestamp.
   900  func DecodeServerEntryList(
   901  	encodedServerEntryList, timestamp,
   902  	serverEntrySource string) ([]ServerEntryFields, error) {
   903  
   904  	serverEntries := make([]ServerEntryFields, 0)
   905  	for _, encodedServerEntry := range strings.Split(encodedServerEntryList, "\n") {
   906  		if len(encodedServerEntry) == 0 {
   907  			continue
   908  		}
   909  
   910  		// TODO: skip this entry and continue if can't decode?
   911  		serverEntryFields, err := DecodeServerEntryFields(encodedServerEntry, timestamp, serverEntrySource)
   912  		if err != nil {
   913  			return nil, errors.Trace(err)
   914  		}
   915  
   916  		if ValidateServerEntryFields(serverEntryFields) != nil {
   917  			// Skip this entry and continue with the next one
   918  			// TODO: invoke a logging callback
   919  			continue
   920  		}
   921  
   922  		serverEntries = append(serverEntries, serverEntryFields)
   923  	}
   924  	return serverEntries, nil
   925  }
   926  
   927  // StreamingServerEntryDecoder performs the DecodeServerEntryList
   928  // operation, loading only one server entry into memory at a time.
   929  type StreamingServerEntryDecoder struct {
   930  	scanner           *bufio.Scanner
   931  	timestamp         string
   932  	serverEntrySource string
   933  }
   934  
   935  // NewStreamingServerEntryDecoder creates a new StreamingServerEntryDecoder.
   936  func NewStreamingServerEntryDecoder(
   937  	encodedServerEntryListReader io.Reader,
   938  	timestamp, serverEntrySource string) *StreamingServerEntryDecoder {
   939  
   940  	return &StreamingServerEntryDecoder{
   941  		scanner:           bufio.NewScanner(encodedServerEntryListReader),
   942  		timestamp:         timestamp,
   943  		serverEntrySource: serverEntrySource,
   944  	}
   945  }
   946  
   947  // Next reads and decodes, and validates the next server entry from the
   948  // input stream, returning a nil server entry when the stream is complete.
   949  //
   950  // Limitations:
   951  //   - Each encoded server entry line cannot exceed bufio.MaxScanTokenSize,
   952  //     the default buffer size which this decoder uses. This is 64K.
   953  //   - DecodeServerEntry is called on each encoded server entry line, which
   954  //     will allocate memory to hex decode and JSON deserialze the server
   955  //     entry. As this is not presently reusing a fixed buffer, each call
   956  //     will allocate additional memory; garbage collection is necessary to
   957  //     reclaim that memory for reuse for the next server entry.
   958  func (decoder *StreamingServerEntryDecoder) Next() (ServerEntryFields, error) {
   959  
   960  	for {
   961  		if !decoder.scanner.Scan() {
   962  			return nil, errors.Trace(decoder.scanner.Err())
   963  		}
   964  
   965  		// TODO: use scanner.Bytes which doesn't allocate, instead of scanner.Text
   966  
   967  		// TODO: skip this entry and continue if can't decode?
   968  		serverEntryFields, err := DecodeServerEntryFields(
   969  			decoder.scanner.Text(), decoder.timestamp, decoder.serverEntrySource)
   970  		if err != nil {
   971  			return nil, errors.Trace(err)
   972  		}
   973  
   974  		if ValidateServerEntryFields(serverEntryFields) != nil {
   975  			// Skip this entry and continue with the next one
   976  			// TODO: invoke a logging callback
   977  			continue
   978  		}
   979  
   980  		return serverEntryFields, nil
   981  	}
   982  }