github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/protocol/serverEntry_test.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 "bytes" 24 "encoding/hex" 25 "encoding/json" 26 "strconv" 27 "testing" 28 29 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 30 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 31 ) 32 33 const ( 34 _VALID_NORMAL_SERVER_ENTRY = `192.168.0.1 80 <webServerSecret> <webServerCertificate> {"ipAddress":"192.168.0.1","webServerPort":"80","webServerSecret":"<webServerSecret>","webServerCertificate":"<webServerCertificate>","sshPort":22,"sshUsername":"<sshUsername>","sshPassword":"<sshPassword>","sshHostKey":"<sshHostKey>","sshObfuscatedPort":443,"sshObfuscatedKey":"<sshObfuscatedKey>","capabilities":["handshake","SSH","OSSH","VPN"],"region":"CA","meekServerPort":8080,"meekCookieEncryptionPublicKey":"<meekCookieEncryptionPublicKey>","meekObfuscatedKey":"<meekObfuscatedKey>","meekFrontingDomain":"<meekFrontingDomain>","meekFrontingHost":"<meekFrontingHost>"}` 35 _VALID_BLANK_LEGACY_SERVER_ENTRY = ` {"ipAddress":"192.168.0.1","webServerPort":"80","webServerSecret":"<webServerSecret>","webServerCertificate":"<webServerCertificate>","sshPort":22,"sshUsername":"<sshUsername>","sshPassword":"<sshPassword>","sshHostKey":"<sshHostKey>","sshObfuscatedPort":443,"sshObfuscatedKey":"<sshObfuscatedKey>","capabilities":["handshake","SSH","OSSH","VPN"],"region":"CA","meekServerPort":8080,"meekCookieEncryptionPublicKey":"<meekCookieEncryptionPublicKey>","meekObfuscatedKey":"<meekObfuscatedKey>","meekFrontingDomain":"<meekFrontingDomain>","meekFrontingHost":"<meekFrontingHost>"}` 36 _VALID_FUTURE_SERVER_ENTRY = `192.168.0.1 80 <webServerSecret> <webServerCertificate> {"ipAddress":"192.168.0.1","webServerPort":"80","webServerSecret":"<webServerSecret>","webServerCertificate":"<webServerCertificate>","sshPort":22,"sshUsername":"<sshUsername>","sshPassword":"<sshPassword>","sshHostKey":"<sshHostKey>","sshObfuscatedPort":443,"sshObfuscatedKey":"<sshObfuscatedKey>","capabilities":["handshake","SSH","OSSH","VPN"],"region":"CA","meekServerPort":8080,"meekCookieEncryptionPublicKey":"<meekCookieEncryptionPublicKey>","meekObfuscatedKey":"<meekObfuscatedKey>","meekFrontingDomain":"<meekFrontingDomain>","meekFrontingHost":"<meekFrontingHost>","dummyFutureField":"dummyFutureField"}` 37 _INVALID_WINDOWS_REGISTRY_LEGACY_SERVER_ENTRY = `192.168.0.1 80 <webServerSecret> <webServerCertificate> {"sshPort":22,"sshUsername":"<sshUsername>","sshPassword":"<sshPassword>","sshHostKey":"<sshHostKey>","sshObfuscatedPort":443,"sshObfuscatedKey":"<sshObfuscatedKey>","capabilities":["handshake","SSH","OSSH","VPN"],"region":"CA","meekServerPort":8080,"meekCookieEncryptionPublicKey":"<meekCookieEncryptionPublicKey>","meekObfuscatedKey":"<meekObfuscatedKey>","meekFrontingDomain":"<meekFrontingDomain>","meekFrontingHost":"<meekFrontingHost>"}` 38 _INVALID_MALFORMED_IP_ADDRESS_SERVER_ENTRY = `192.168.0.1 80 <webServerSecret> <webServerCertificate> {"ipAddress":"192.168.0.","webServerPort":"80","webServerSecret":"<webServerSecret>","webServerCertificate":"<webServerCertificate>","sshPort":22,"sshUsername":"<sshUsername>","sshPassword":"<sshPassword>","sshHostKey":"<sshHostKey>","sshObfuscatedPort":443,"sshObfuscatedKey":"<sshObfuscatedKey>","capabilities":["handshake","SSH","OSSH","VPN"],"region":"CA","meekServerPort":8080,"meekCookieEncryptionPublicKey":"<meekCookieEncryptionPublicKey>","meekObfuscatedKey":"<meekObfuscatedKey>","meekFrontingDomain":"<meekFrontingDomain>","meekFrontingHost":"<meekFrontingHost>"}` 39 _EXPECTED_IP_ADDRESS = `192.168.0.1` 40 _EXPECTED_DUMMY_FUTURE_FIELD = `dummyFutureField` 41 ) 42 43 var testEncodedServerEntryList = hex.EncodeToString([]byte(_VALID_NORMAL_SERVER_ENTRY)) + "\n" + 44 hex.EncodeToString([]byte(_VALID_BLANK_LEGACY_SERVER_ENTRY)) + "\n" + 45 hex.EncodeToString([]byte(_VALID_FUTURE_SERVER_ENTRY)) + "\n" + 46 hex.EncodeToString([]byte(_INVALID_WINDOWS_REGISTRY_LEGACY_SERVER_ENTRY)) + "\n" + 47 hex.EncodeToString([]byte(_INVALID_MALFORMED_IP_ADDRESS_SERVER_ENTRY)) 48 49 // DecodeServerEntryList should return 3 valid decoded entries from the input list of 5 50 func TestDecodeServerEntryList(t *testing.T) { 51 52 serverEntries, err := DecodeServerEntryList( 53 testEncodedServerEntryList, common.GetCurrentTimestamp(), SERVER_ENTRY_SOURCE_EMBEDDED) 54 if err != nil { 55 t.Error(err.Error()) 56 t.FailNow() 57 } 58 59 if len(serverEntries) != 3 { 60 t.Error("unexpected number of valid server entries") 61 } 62 63 numFutureFields := 0 64 65 for _, serverEntryFields := range serverEntries { 66 if serverEntryFields.GetIPAddress() != _EXPECTED_IP_ADDRESS { 67 t.Errorf("unexpected IP address in decoded server entry: %s", serverEntryFields.GetIPAddress()) 68 } 69 if futureField, ok := serverEntryFields[_EXPECTED_DUMMY_FUTURE_FIELD]; ok { 70 if futureFieldStr, ok := futureField.(string); ok && futureFieldStr == _EXPECTED_DUMMY_FUTURE_FIELD { 71 numFutureFields += 1 72 } 73 } 74 } 75 76 if numFutureFields != 1 { 77 t.Error("unexpected number of retained future fields") 78 } 79 } 80 81 func TestStreamingServerEntryDecoder(t *testing.T) { 82 83 decoder := NewStreamingServerEntryDecoder( 84 bytes.NewReader([]byte(testEncodedServerEntryList)), 85 common.GetCurrentTimestamp(), SERVER_ENTRY_SOURCE_EMBEDDED) 86 87 serverEntries := make([]ServerEntryFields, 0) 88 89 for { 90 serverEntryFields, err := decoder.Next() 91 if err != nil { 92 t.Error(err.Error()) 93 t.FailNow() 94 } 95 96 if serverEntryFields == nil { 97 break 98 } 99 100 serverEntries = append(serverEntries, serverEntryFields) 101 } 102 103 if len(serverEntries) != 3 { 104 t.Error("unexpected number of valid server entries") 105 } 106 107 numFutureFields := 0 108 109 for _, serverEntryFields := range serverEntries { 110 if serverEntryFields.GetIPAddress() != _EXPECTED_IP_ADDRESS { 111 t.Errorf("unexpected IP address in decoded server entry: %s", serverEntryFields.GetIPAddress()) 112 } 113 if futureField, ok := serverEntryFields[_EXPECTED_DUMMY_FUTURE_FIELD]; ok { 114 if futureFieldStr, ok := futureField.(string); ok && futureFieldStr == _EXPECTED_DUMMY_FUTURE_FIELD { 115 numFutureFields += 1 116 } 117 } 118 } 119 120 if numFutureFields != 1 { 121 t.Error("unexpected number of retained future fields") 122 } 123 } 124 125 // Directly call DecodeServerEntryFields and ValidateServerEntry with invalid inputs 126 func TestInvalidServerEntries(t *testing.T) { 127 128 testCases := [2]string{_INVALID_WINDOWS_REGISTRY_LEGACY_SERVER_ENTRY, _INVALID_MALFORMED_IP_ADDRESS_SERVER_ENTRY} 129 130 for _, testCase := range testCases { 131 encodedServerEntry := hex.EncodeToString([]byte(testCase)) 132 serverEntryFields, err := DecodeServerEntryFields( 133 encodedServerEntry, common.GetCurrentTimestamp(), SERVER_ENTRY_SOURCE_EMBEDDED) 134 if err != nil { 135 t.Error(err.Error()) 136 } 137 err = ValidateServerEntryFields(serverEntryFields) 138 if err == nil { 139 t.Errorf("server entry should not validate: %s", testCase) 140 } 141 } 142 } 143 144 // Directly call DecodeServerEntry 145 func TestDecodeServerEntryStruct(t *testing.T) { 146 147 serverEntry, err := DecodeServerEntry( 148 hex.EncodeToString([]byte(_VALID_NORMAL_SERVER_ENTRY)), 149 common.GetCurrentTimestamp(), SERVER_ENTRY_SOURCE_EMBEDDED) 150 if err != nil { 151 t.Error(err.Error()) 152 t.FailNow() 153 } 154 if serverEntry.IpAddress != _EXPECTED_IP_ADDRESS { 155 t.Errorf("unexpected IP address in decoded server entry: %s", serverEntry.IpAddress) 156 } 157 } 158 159 func TestServerEntryListSignatures(t *testing.T) { 160 testServerEntryListSignatures(t, true) 161 testServerEntryListSignatures(t, false) 162 } 163 164 func testServerEntryListSignatures(t *testing.T, setExplicitTag bool) { 165 166 publicKey, privateKey, err := NewServerEntrySignatureKeyPair() 167 if err != nil { 168 t.Fatalf("NewServerEntrySignatureKeyPair failed: %s", err) 169 } 170 171 n := 16 172 serverEntry := &ServerEntry{ 173 IpAddress: prng.HexString(n), 174 WebServerPort: strconv.Itoa(prng.Intn(n)), 175 WebServerSecret: prng.HexString(n), 176 WebServerCertificate: prng.HexString(n), 177 SshPort: prng.Intn(n), 178 SshUsername: prng.HexString(n), 179 SshPassword: prng.HexString(n), 180 SshHostKey: prng.HexString(n), 181 SshObfuscatedPort: prng.Intn(n), 182 SshObfuscatedQUICPort: prng.Intn(n), 183 SshObfuscatedTapDancePort: prng.Intn(n), 184 SshObfuscatedConjurePort: prng.Intn(n), 185 SshObfuscatedKey: prng.HexString(n), 186 Capabilities: []string{prng.HexString(n)}, 187 Region: prng.HexString(n), 188 MeekServerPort: prng.Intn(n), 189 MeekCookieEncryptionPublicKey: prng.HexString(n), 190 MeekObfuscatedKey: prng.HexString(n), 191 MeekFrontingHost: prng.HexString(n), 192 MeekFrontingHosts: []string{prng.HexString(n)}, 193 MeekFrontingDomain: prng.HexString(n), 194 MeekFrontingAddresses: []string{prng.HexString(n)}, 195 MeekFrontingAddressesRegex: prng.HexString(n), 196 MeekFrontingDisableSNI: false, 197 TacticsRequestPublicKey: prng.HexString(n), 198 TacticsRequestObfuscatedKey: prng.HexString(n), 199 ConfigurationVersion: 1, 200 } 201 202 if setExplicitTag { 203 serverEntry.Tag = prng.HexString(n) 204 } 205 206 // Convert ServerEntry to ServerEntryFields 207 208 marshaledServerEntry, err := json.Marshal(serverEntry) 209 if err != nil { 210 t.Fatalf("Marshal failed: %s", err) 211 } 212 213 var serverEntryFields ServerEntryFields 214 215 err = json.Unmarshal(marshaledServerEntry, &serverEntryFields) 216 if err != nil { 217 t.Fatalf("Unmarshal failed: %s", err) 218 } 219 220 // Check that local fields are ignored in the signature 221 222 if !setExplicitTag { 223 serverEntryFields.SetTag(prng.HexString(n)) 224 } 225 serverEntryFields.SetLocalSource(prng.HexString(n)) 226 serverEntryFields.SetLocalTimestamp(prng.HexString(n)) 227 228 // Set dummy signature to check that its overwritten 229 230 serverEntryFields["signature"] = prng.HexString(n) 231 232 err = serverEntryFields.AddSignature(publicKey, privateKey) 233 if err != nil { 234 t.Fatalf("AddSignature failed: %s", err) 235 } 236 237 err = serverEntryFields.VerifySignature(publicKey) 238 if err != nil { 239 t.Fatalf("VerifySignature failed: %s", err) 240 } 241 242 // A 2nd VerifySignature call checks that the first VerifySignature 243 // call leaves the server entry fields intact 244 245 err = serverEntryFields.VerifySignature(publicKey) 246 if err != nil { 247 t.Fatalf("VerifySignature failed: %s", err) 248 } 249 250 // Modify local local fields and check that signature remains valid 251 252 if !setExplicitTag { 253 serverEntryFields.SetTag(prng.HexString(n)) 254 } 255 serverEntryFields.SetLocalSource(prng.HexString(n)) 256 serverEntryFields.SetLocalTimestamp(prng.HexString(n)) 257 258 err = serverEntryFields.VerifySignature(publicKey) 259 if err != nil { 260 t.Fatalf("VerifySignature failed: %s", err) 261 } 262 263 // Check that verification fails when using the wrong public key 264 265 incorrectPublicKey, _, err := NewServerEntrySignatureKeyPair() 266 if err != nil { 267 t.Fatalf("NewServerEntrySignatureKeyPair failed: %s", err) 268 } 269 270 err = serverEntryFields.VerifySignature(incorrectPublicKey) 271 if err == nil { 272 t.Fatalf("VerifySignature unexpectedly succeeded") 273 } 274 275 // Check that an expected, non-local field causes verification to fail 276 277 serverEntryFields[prng.HexString(n)] = prng.HexString(n) 278 279 err = serverEntryFields.VerifySignature(publicKey) 280 if err == nil { 281 t.Fatalf("AddSignature unexpectedly succeeded") 282 } 283 284 // Check that modifying a signed field causes verification to fail 285 286 fieldName := "sshObfuscatedKey" 287 if setExplicitTag { 288 fieldName = "tag" 289 } 290 291 serverEntryFields[fieldName] = prng.HexString(n) 292 293 err = serverEntryFields.VerifySignature(publicKey) 294 if err == nil { 295 t.Fatalf("AddSignature unexpectedly succeeded") 296 } 297 }