summaryrefslogtreecommitdiff
path: root/transports/obfs4/statefile.go
diff options
context:
space:
mode:
Diffstat (limited to 'transports/obfs4/statefile.go')
-rw-r--r--transports/obfs4/statefile.go252
1 files changed, 0 insertions, 252 deletions
diff --git a/transports/obfs4/statefile.go b/transports/obfs4/statefile.go
deleted file mode 100644
index 6f89c6c..0000000
--- a/transports/obfs4/statefile.go
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (c) 2014, Yawning Angel <yawning at torproject dot org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package obfs4
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "strconv"
- "strings"
-
- "git.torproject.org/pluggable-transports/goptlib.git"
- "github.com/OperatorFoundation/obfs4/common/csrand"
- "github.com/OperatorFoundation/obfs4/common/drbg"
- "github.com/OperatorFoundation/obfs4/common/ntor"
-)
-
-const (
- stateFile = "obfs4_state.json"
- bridgeFile = "obfs4_bridgeline.txt"
-
- certSuffix = "=="
- certLength = ntor.NodeIDLength + ntor.PublicKeyLength
-)
-
-type jsonServerState struct {
- NodeID string `json:"node-id"`
- PrivateKey string `json:"private-key"`
- PublicKey string `json:"public-key"`
- DrbgSeed string `json:"drbg-seed"`
- IATMode int `json:"iat-mode"`
-}
-
-type obfs4ServerCert struct {
- raw []byte
-}
-
-func (cert *obfs4ServerCert) String() string {
- return strings.TrimSuffix(base64.StdEncoding.EncodeToString(cert.raw), certSuffix)
-}
-
-func (cert *obfs4ServerCert) unpack() (*ntor.NodeID, *ntor.PublicKey) {
- if len(cert.raw) != certLength {
- panic(fmt.Sprintf("cert length %d is invalid", len(cert.raw)))
- }
-
- nodeID, _ := ntor.NewNodeID(cert.raw[:ntor.NodeIDLength])
- pubKey, _ := ntor.NewPublicKey(cert.raw[ntor.NodeIDLength:])
-
- return nodeID, pubKey
-}
-
-func serverCertFromString(encoded string) (*obfs4ServerCert, error) {
- decoded, err := base64.StdEncoding.DecodeString(encoded + certSuffix)
- if err != nil {
- return nil, fmt.Errorf("failed to decode cert: %s", err)
- }
-
- if len(decoded) != certLength {
- return nil, fmt.Errorf("cert length %d is invalid", len(decoded))
- }
-
- return &obfs4ServerCert{raw: decoded}, nil
-}
-
-func serverCertFromState(st *obfs4ServerState) *obfs4ServerCert {
- cert := new(obfs4ServerCert)
- cert.raw = append(st.nodeID.Bytes()[:], st.identityKey.Public().Bytes()[:]...)
- return cert
-}
-
-type obfs4ServerState struct {
- nodeID *ntor.NodeID
- identityKey *ntor.Keypair
- drbgSeed *drbg.Seed
- iatMode int
-
- cert *obfs4ServerCert
-}
-
-func (st *obfs4ServerState) clientString() string {
- return fmt.Sprintf("%s=%s %s=%d", certArg, st.cert, iatArg, st.iatMode)
-}
-
-func serverStateFromArgs(stateDir string, args *pt.Args) (*obfs4ServerState, error) {
- var js jsonServerState
- var nodeIDOk, privKeyOk, seedOk bool
-
- js.NodeID, nodeIDOk = args.Get(nodeIDArg)
- js.PrivateKey, privKeyOk = args.Get(privateKeyArg)
- js.DrbgSeed, seedOk = args.Get(seedArg)
- iatStr, iatOk := args.Get(iatArg)
-
- if !privKeyOk && !nodeIDOk && !seedOk && !iatOk {
- if err := jsonServerStateFromFile(stateDir, &js); err != nil {
- return nil, err
- }
- } else if !privKeyOk {
- return nil, fmt.Errorf("missing argument '%s'", privateKeyArg)
- } else if !nodeIDOk {
- return nil, fmt.Errorf("missing argument '%s'", nodeIDArg)
- } else if !seedOk {
- return nil, fmt.Errorf("missing argument '%s'", seedArg)
- } else if !iatOk {
- // Disable IAT if not specified.
- return nil, fmt.Errorf("missing argument '%s'", iatArg)
- } else {
- // Parse and validate the iat-mode argument.
- iatMode, err := strconv.Atoi(iatStr)
- if err != nil {
- return nil, fmt.Errorf("malformed iat-mode '%s'", iatStr)
- }
- js.IATMode = iatMode
- }
-
- return serverStateFromJSONServerState(stateDir, &js)
-}
-
-func serverStateFromJSONServerState(stateDir string, js *jsonServerState) (*obfs4ServerState, error) {
- var err error
-
- st := new(obfs4ServerState)
- if st.nodeID, err = ntor.NodeIDFromHex(js.NodeID); err != nil {
- return nil, err
- }
- if st.identityKey, err = ntor.KeypairFromHex(js.PrivateKey); err != nil {
- return nil, err
- }
- if st.drbgSeed, err = drbg.SeedFromHex(js.DrbgSeed); err != nil {
- return nil, err
- }
- if js.IATMode < iatNone || js.IATMode > iatParanoid {
- return nil, fmt.Errorf("invalid iat-mode '%d'", js.IATMode)
- }
- st.iatMode = js.IATMode
- st.cert = serverCertFromState(st)
-
- // Generate a human readable summary of the configured endpoint.
- if err = newBridgeFile(stateDir, st); err != nil {
- return nil, err
- }
-
- return st, nil
-}
-
-func jsonServerStateFromFile(stateDir string, js *jsonServerState) error {
- fPath := path.Join(stateDir, stateFile)
- f, err := ioutil.ReadFile(fPath)
- if err != nil {
- if os.IsNotExist(err) {
- if err = newJSONServerState(stateDir, js); err == nil {
- return nil
- }
- }
- return err
- }
-
- if err := json.Unmarshal(f, js); err != nil {
- return fmt.Errorf("failed to load statefile '%s': %s", fPath, err)
- }
-
- return nil
-}
-
-func newJSONServerState(stateDir string, js *jsonServerState) (err error) {
- // Generate everything a server needs, using the cryptographic PRNG.
- var st obfs4ServerState
- rawID := make([]byte, ntor.NodeIDLength)
- if err = csrand.Bytes(rawID); err != nil {
- return
- }
- if st.nodeID, err = ntor.NewNodeID(rawID); err != nil {
- return
- }
- if st.identityKey, err = ntor.NewKeypair(false); err != nil {
- return
- }
- if st.drbgSeed, err = drbg.NewSeed(); err != nil {
- return
- }
- st.iatMode = iatNone
-
- // Encode it into JSON format and write the state file.
- js.NodeID = st.nodeID.Hex()
- js.PrivateKey = st.identityKey.Private().Hex()
- js.PublicKey = st.identityKey.Public().Hex()
- js.DrbgSeed = st.drbgSeed.Hex()
- js.IATMode = st.iatMode
-
- var encoded []byte
- if encoded, err = json.Marshal(js); err != nil {
- return
- }
-
- if err = ioutil.WriteFile(path.Join(stateDir, stateFile), encoded, 0600); err != nil {
- return err
- }
-
- return nil
-}
-
-func newBridgeFile(stateDir string, st *obfs4ServerState) error {
- const prefix = "# obfs4 torrc client bridge line\n" +
- "#\n" +
- "# This file is an automatically generated bridge line based on\n" +
- "# the current obfs4proxy configuration. EDITING IT WILL HAVE\n" +
- "# NO EFFECT.\n" +
- "#\n" +
- "# Before distributing this Bridge, edit the placeholder fields\n" +
- "# to contain the actual values:\n" +
- "# <IP ADDRESS> - The public IP address of your obfs4 bridge.\n" +
- "# <PORT> - The TCP/IP port of your obfs4 bridge.\n" +
- "# <FINGERPRINT> - The bridge's fingerprint.\n\n"
-
- bridgeLine := fmt.Sprintf("Bridge obfs4 <IP ADDRESS>:<PORT> <FINGERPRINT> %s\n",
- st.clientString())
-
- tmp := []byte(prefix + bridgeLine)
- if err := ioutil.WriteFile(path.Join(stateDir, bridgeFile), tmp, 0600); err != nil {
- return err
- }
-
- return nil
-}