mirror of
https://gitlab.com/yawning/obfs4.git
synced 2024-11-15 12:12:53 +00:00
Change the bridge line format to be more compact.
Instead of "node-id" and "public-key" that are Base16 encoded, use "cert" which contains the "node-id" and "public-key" in Base64 encoded form. This is more compact and cuts the length down by 49 characters.
This commit is contained in:
parent
213495d3b9
commit
6cd81ec42f
@ -1,3 +1,10 @@
|
||||
Changes in version 0.0.3 - UNRELEASED
|
||||
- Change the obfs4 bridge line format to use a "cert" argument instead of the
|
||||
previous "node-id" and "public-key" arguments. The "cert" consists of the
|
||||
Base64 encoded concatenation of the node ID and public key, with the
|
||||
trailing padding removed. Old style separated bridge lines are still valid,
|
||||
but the newer representation is slightly more compact.
|
||||
|
||||
Changes in version 0.0.2 - 2014-09-26
|
||||
- Write an example client bridge line suitable for use with the running obfs4
|
||||
server instance to "obfs4_bridgeline.txt" for the convenience of bridge
|
||||
|
@ -82,8 +82,8 @@ ServerTransportPlugin obfs4 exec /usr/local/bin/obfs4proxy
|
||||
appropriate.
|
||||
|
||||
* The autogenerated obfs4 bridge parameters are placed in
|
||||
`DataDir/pt_state/obfs4_state.json`. An obfs4 bridge line requires the
|
||||
`node-id`, `public-key` and `iat-mode` arguments.
|
||||
`DataDir/pt_state/obfs4_state.json`. To ease deployment, the client side
|
||||
bridge line is written to `DataDir/pt_state/obfs4_bridgeline.txt`.
|
||||
|
||||
### Thanks
|
||||
|
||||
|
@ -57,6 +57,7 @@ const (
|
||||
privateKeyArg = "private-key"
|
||||
seedArg = "drbg-seed"
|
||||
iatArg = "iat-mode"
|
||||
certArg = "cert"
|
||||
|
||||
biasCmdArg = "obfs4-distBias"
|
||||
|
||||
@ -122,8 +123,7 @@ func (t *Transport) ServerFactory(stateDir string, args *pt.Args) (base.ServerFa
|
||||
|
||||
// Store the arguments that should appear in our descriptor for the clients.
|
||||
ptArgs := pt.Args{}
|
||||
ptArgs.Add(nodeIDArg, st.nodeID.Hex())
|
||||
ptArgs.Add(publicKeyArg, st.identityKey.Public().Hex())
|
||||
ptArgs.Add(certArg, st.cert.String())
|
||||
ptArgs.Add(iatArg, strconv.Itoa(st.iatMode))
|
||||
|
||||
// Initialize the replay filter.
|
||||
@ -154,15 +154,39 @@ func (cf *obfs4ClientFactory) Transport() base.Transport {
|
||||
func (cf *obfs4ClientFactory) ParseArgs(args *pt.Args) (interface{}, error) {
|
||||
var err error
|
||||
|
||||
// Handle the arguments.
|
||||
nodeIDStr, ok := args.Get(nodeIDArg)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing argument '%s'", nodeIDArg)
|
||||
}
|
||||
var nodeID *ntor.NodeID
|
||||
if nodeID, err = ntor.NodeIDFromHex(nodeIDStr); err != nil {
|
||||
return nil, err
|
||||
var publicKey *ntor.PublicKey
|
||||
|
||||
// The "new" (version >= 0.0.3) bridge lines use a unified "cert" argument
|
||||
// for the Node ID and Public Key.
|
||||
certStr, ok := args.Get(certArg)
|
||||
if ok {
|
||||
var cert *obfs4ServerCert
|
||||
if cert, err = serverCertFromString(certStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeID, publicKey = cert.unpack()
|
||||
} else {
|
||||
// The "old" style (version <= 0.0.2) bridge lines use separate Node ID
|
||||
// and Public Key arguments in Base16 encoding and are a UX disaster.
|
||||
nodeIDStr, ok := args.Get(nodeIDArg)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing argument '%s'", nodeIDArg)
|
||||
}
|
||||
if nodeID, err = ntor.NodeIDFromHex(nodeIDStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
publicKeyStr, ok := args.Get(publicKeyArg)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing argument '%s'", publicKeyArg)
|
||||
}
|
||||
if publicKey, err = ntor.PublicKeyFromHex(publicKeyStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// IAT config is common across the two bridge line formats.
|
||||
iatStr, ok := args.Get(iatArg)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing argument '%s'", iatArg)
|
||||
@ -173,15 +197,6 @@ func (cf *obfs4ClientFactory) ParseArgs(args *pt.Args) (interface{}, error) {
|
||||
return nil, fmt.Errorf("invalid iat-mode '%d'", iatMode)
|
||||
}
|
||||
|
||||
publicKeyStr, ok := args.Get(publicKeyArg)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing argument '%s'", publicKeyArg)
|
||||
}
|
||||
var publicKey *ntor.PublicKey
|
||||
if publicKey, err = ntor.PublicKeyFromHex(publicKeyStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Generate the session key pair before connectiong to hide the Elligator2
|
||||
// rejection sampling from network observers.
|
||||
sessionKey, err := ntor.NewKeypair(true)
|
||||
|
@ -28,12 +28,14 @@
|
||||
package obfs4
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.torproject.org/pluggable-transports/goptlib.git"
|
||||
"git.torproject.org/pluggable-transports/obfs4.git/common/csrand"
|
||||
@ -44,6 +46,9 @@ import (
|
||||
const (
|
||||
stateFile = "obfs4_state.json"
|
||||
bridgeFile = "obfs4_bridgeline.txt"
|
||||
|
||||
certSuffix = "=="
|
||||
certLength = ntor.NodeIDLength + ntor.PublicKeyLength
|
||||
)
|
||||
|
||||
type jsonServerState struct {
|
||||
@ -54,11 +59,55 @@ type jsonServerState struct {
|
||||
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) {
|
||||
@ -112,6 +161,7 @@ func serverStateFromJSONServerState(stateDir string, js *jsonServerState) (*obfs
|
||||
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 {
|
||||
@ -190,10 +240,8 @@ func newBridgeFile(stateDir string, st *obfs4ServerState) (err error) {
|
||||
"# <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> node-id=%s public-key=%s iat-mode=%d\n",
|
||||
st.nodeID.Hex(),
|
||||
st.identityKey.Public().Hex(),
|
||||
st.iatMode)
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user