osl

package
v0.0.12-alpha Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2016 License: GPL-3.0 Imports: 22 Imported by: 0

Documentation

Overview

Package osl implements the Obfuscated Server List (OSL) mechanism. This mechanism is a method of distributing server lists only to clients that demonstrate certain behavioral traits. Clients are seeded with Server List Obfuscation Keys (SLOKs) as they meet the configured criteria. These keys are stored and later combined to assemble keys to decrypt out-of-band distributed OSL files that contain server lists.

This package contains the core routines used in psiphond (to track client traits and issue SLOKs), clients (to manage SLOKs and decrypt OSLs), and automation (to create OSLs for distribution).

Index

Constants

View Source
const (
	KEY_LENGTH_BYTES    = 32
	REGISTRY_FILENAME   = "osl-registry"
	OSL_FILENAME_FORMAT = "osl-%s"
)

Variables

This section is empty.

Functions

func GetOSLFileURL

func GetOSLFileURL(baseURL string, oslID []byte) string

GetOSLFileURL returns the URL for an OSL file. Once the client has determined, from GetSeededOSLIDs, which OSLs it has sufficiently seeded, it calls this to fetch the OSLs for download and decryption. Clients are responsible for tracking whether the remote file has changed or not before downloading.

func GetOSLFilename

func GetOSLFilename(baseDirectory string, oslID []byte) string

GetOSLFilename returns an appropriate filename for the resumable download destination for the OSL file.

func GetOSLRegistryFilename

func GetOSLRegistryFilename(baseDirectory string) string

GetOSLRegistryFilename returns an appropriate filename for the resumable download destination for the OSL registry.

func GetOSLRegistryURL

func GetOSLRegistryURL(baseURL string) string

GetOSLRegistryURL returns the URL for an OSL registry. Clients call this when fetching the registry from out-of-band distribution sites. Clients are responsible for tracking whether the remote file has changed or not before downloading.

Types

type ClientSeedPortForward

type ClientSeedPortForward struct {
	// contains filtered or unexported fields
}

ClientSeedPortForward map a client port forward, which is relaying traffic to a specific upstream address, to all seed state progress counters for SeedSpecs with subnets containing the upstream address. As traffic is relayed through the port forwards, the bytes transferred and duration count towards the progress of these SeedSpecs and associated SLOKs.

func (*ClientSeedPortForward) UpdateProgress

func (portForward *ClientSeedPortForward) UpdateProgress(
	bytesRead, bytesWritten int64, durationNanoseconds int64)

UpdateProgress adds port forward bytes transfered and duration to all seed spec progresses associated with the port forward. If UpdateProgress is invoked after the SLOK time period has rolled over, any pending seeded SLOKs are issued and all progress is reset. UpdateProgress may be invoked concurrently by many psiphond port relay goroutines. The implementation of UpdateProgress prioritizes not blocking port forward relaying; a consequence of this lock-free design is that progress reported at the exact time of SLOK time period rollover may be dropped.

type ClientSeedState

type ClientSeedState struct {
	// contains filtered or unexported fields
}

ClientSeedState tracks the progress of a client towards seeding SLOKs.

func (*ClientSeedState) ClearSeedPayload

func (state *ClientSeedState) ClearSeedPayload()

ClearSeedPayload resets the accumulated SLOK payload (but not SLOK progress). psiphond calls this after the client has acknowledged receipt of a payload.

func (*ClientSeedState) GetSeedPayload

func (state *ClientSeedState) GetSeedPayload() *SeedPayload

GetSeedPayload issues any pending SLOKs and returns the accumulated SLOKs for a given client. psiphond will calls this when it receives signalIssueSLOKs which is the trigger to check for new SLOKs. Note: caller must not modify the SLOKs in SeedPayload.SLOKs as these are shared data.

func (*ClientSeedState) NewClientSeedPortForward

func (state *ClientSeedState) NewClientSeedPortForward(
	upstreamIPAddress net.IP) *ClientSeedPortForward

NewClientSeedPortForwardState creates a new client port forward traffic progress tracker. Port forward progress reported to the ClientSeedPortForward is added to seed state progress for all seed specs containing upstreamIPAddress in their subnets. The return value will be nil when activity for upstreamIPAddress does not count towards any progress. NewClientSeedPortForward may be invoked concurrently by many psiphond port forward establishment goroutines.

type Config

type Config struct {
	common.ReloadableFile

	Schemes []*Scheme
}

Config is an OSL configuration, which consists of a list of schemes. The Reload function supports hot reloading of rules data while the process is running.

func LoadConfig

func LoadConfig(configJSON []byte) (*Config, error)

LoadConfig loads, vaildates, and initializes a JSON encoded OSL configuration.

func NewConfig

func NewConfig(filename string) (*Config, error)

NewConfig initializes a Config with the settings in the specified file.

func (*Config) NewClientSeedState

func (config *Config) NewClientSeedState(
	clientRegion, propagationChannelID string,
	signalIssueSLOKs chan struct{}) *ClientSeedState

NewClientSeedState creates a new client seed state to track client progress towards seeding SLOKs. psiphond maintains one ClientSeedState for each connected client.

A signal is sent on signalIssueSLOKs when sufficient progress has been made that a new SLOK *may* be issued. psiphond will receive the signal and then call GetClientSeedPayload/IssueSLOKs to issue SLOKs, generate payload, and send to the client. The sender will not block sending to signalIssueSLOKs; the channel should be appropriately buffered.

func (*Config) Pave

func (config *Config) Pave(
	endTime time.Time,
	propagationChannelID string,
	signingPublicKey string,
	signingPrivateKey string,
	paveServerEntries []map[time.Time]string) ([]*PaveFile, error)

Pave creates the full set of OSL files, for all schemes in the configuration, to be dropped in an out-of-band distribution site. Only OSLs for the propagation channel ID associated with the distribution site are paved. This function is used by automation.

The Name component of each file relates to the values returned by the client functions GetRegistryURL and GetOSLFileURL.

Pave returns a pave file for the entire registry of all OSLs from epoch. It only returns pave files for OSLs referenced in paveServerEntries. paveServerEntries is a list of maps, one for each scheme, from the first SLOK time period identifying an OSL to a payload to encrypt and pave. The registry file spec MD5 checksum values are populated only for OSLs referenced in paveServerEntries. To ensure a registry is fully populated with hashes for skipping redownloading, all OSLs should be paved.

Automation is responsible for consistently distributing server entries to OSLs in the case where OSLs are repaved in subsequent calls.

type KeyShares

type KeyShares struct {
	Threshold   int
	BoxedShares [][]byte
	SLOKIDs     [][]byte
	KeyShares   []*KeyShares
}

KeyShares is a tree data structure which describes the key splits used to divide a secret key. BoxedShares are encrypted shares of the key, and #Threshold amount of decrypted BoxedShares are required to reconstruct the secret key. The keys for BoxedShares are either SLOKs (referenced by SLOK ID) or random keys that are themselves split as described in child KeyShares.

type KeySplit

type KeySplit struct {
	Total     int
	Threshold int
}

KeySplit defines a secret key splitting scheme where the secret is split into n (total) shares and any K (threshold) of N shares must be known to recostruct the split secret.

type OSLFileSpec

type OSLFileSpec struct {
	ID        []byte
	KeyShares *KeyShares
	MD5Sum    []byte
}

An OSLFileSpec includes an ID which is used to reference the OSL file and describes the key splits used to divide the OSL file key along with the SLOKs required to reassemble those keys.

The MD5Sum field is a checksum of the contents of the OSL file to be used to skip redownloading previously downloaded files. MD5 is not cryptogrpahically secure and this checksum is not relied upon for OSL verification. MD5 is used for compatibility with out-of-band distribution hosts.

type PaveFile

type PaveFile struct {
	Name     string
	Contents []byte
}

PaveFile describes an OSL data file to be paved to an out-of-band distribution drop site. There are two types of files: a registry, which describes how to assemble keys for OSLs, and the encrypted OSL files.

type Registry

type Registry struct {
	FileSpecs []*OSLFileSpec
	// contains filtered or unexported fields
}

Registry describes a set of OSL files.

func LoadRegistry

func LoadRegistry(registryJSON []byte) (*Registry, error)

LoadRegistry loads a JSON encoded OSL registry. Clients call this to process downloaded registry files.

func UnpackRegistry

func UnpackRegistry(
	compressedRegistry []byte, signingPublicKey string) (*Registry, []byte, error)

UnpackRegistry decompresses, validates, and loads a JSON encoded OSL registry.

func (*Registry) GetOSLMD5Sum

func (registry *Registry) GetOSLMD5Sum(oslID []byte) ([]byte, error)

GetOSLMD5Sum returns the MD5 checksum for the specified OSL.

func (*Registry) GetSeededOSLIDs

func (registry *Registry) GetSeededOSLIDs(lookup SLOKLookup, errorLogger func(error)) [][]byte

GetSeededOSLIDs examines each OSL in the registry and returns a list for which the client has sufficient SLOKs to reassemble the OSL key and decrypt. This function simply does SLOK ID lookups and threshold counting and does not derive keys for every OSL. The client is responsible for using the resulting list of OSL IDs to fetch the OSL files and process.

The client's propagation channel ID is used implicitly: it determines the base URL used to download the registry and OSL files. If the client has seeded SLOKs from a propagation channel ID different than the one associated with its present base URL, they will not appear in the registry and not be used.

SLOKLookup is called to determine which SLOKs are seeded with the client. errorLogger is a callback to log errors; GetSeededOSLIDs will continue to process each candidate OSL even in the case of an error processing a particular one.

func (*Registry) UnpackOSL

func (registry *Registry) UnpackOSL(
	lookup SLOKLookup,
	oslID []byte,
	oslFileContents []byte,
	signingPublicKey string) (string, error)

UnpackOSL reassembles the key for the OSL specified by oslID and uses that key to decrypt oslFileContents, uncompress the contents, validate the authenticated package, and extract the payload. Clients will call UnpackOSL for OSLs indicated by GetSeededOSLIDs along with their downloaded content. SLOKLookup is called to determine which SLOKs are seeded with the client.

type SLOK

type SLOK struct {
	ID  []byte
	Key []byte
}

SLOK is a seeded SLOK issued to a client. The client will store the SLOK in its local database; look it up by ID when checking which OSLs it can reassemble keys for; and use the key material to reassemble OSL file keys.

type SLOKLookup

type SLOKLookup func([]byte) []byte

SLOKLookup is a callback to lookup SLOK keys by ID.

type Scheme

type Scheme struct {

	// Epoch is the start time of the scheme, the start time of the
	// first OSL and when SLOKs will first be issued. It must be
	// specified in UTC and must be a multiple of SeedPeriodNanoseconds.
	Epoch string

	// Regions is a list of client country codes this scheme applies to.
	// If empty, the scheme applies to all regions.
	Regions []string

	// PropagationChannelIDs is a list of client propagtion channel IDs
	// this scheme applies to. Propagation channel IDs are an input
	// to SLOK key derivation.
	PropagationChannelIDs []string

	// MasterKey is the base random key used for SLOK key derivation. It
	// must be unique for each scheme. It must be 32 random bytes, base64
	// encoded.
	MasterKey []byte

	// SeedSpecs is the set of different client network activity patterns
	// that will result in issuing SLOKs. For a given time period, a distinct
	// SLOK is issued for each SeedLevel in each SeedSpec.
	// Duplicate subnets may appear in multiple SeedSpecs.
	SeedSpecs []*SeedSpec

	// SeedSpecThreshold is the threshold scheme for combining SLOKs to
	// decrypt an OSL. For any fixed time period, at least K (threshold) of
	// N (total) SLOKs from the N SeedSpecs must be seeded for a client to be
	// able to reassemble the OSL key.
	// Limitation: thresholds must be at least 2.
	SeedSpecThreshold int

	// SeedPeriodNanoseconds is the time period granularity of SLOKs.
	// New SLOKs are issued every SeedPeriodNanoseconds. Client progress
	// towards activity levels is reset at the end of each period.
	SeedPeriodNanoseconds int64

	// KeySplits is the time period threshold scheme layered on top of the
	// SeedSpecThreshold scheme for combining SLOKs to decrypt an OSL.
	// There must be at least one level. For one level, any K (threshold) of
	// N (total) SeedSpec SLOK groups must be sufficiently seeded for a client
	// to be able to reassemble the OSL key. When an additional level is
	// specified, then K' of N' groups of N of K SeedSpec SLOK groups must be
	// sufficiently seeded. And so on. The first level in the list is the
	// lowest level. The time period for OSLs is determined by the totals in
	// the KeySplits.
	// Limitation: thresholds must be at least 2.
	//
	// Example:
	//
	//   SeedSpecs = <3 specs>
	//   SeedSpecThreshold = 2
	//   SeedPeriodNanoseconds = 100,000,000 = 100 milliseconds
	//   SeedPeriodKeySplits = [{10, 7}, {60, 5}]
	//
	//   In these scheme, up to 3 distinct SLOKs, one per spec, are issued
	//   every 100 milliseconds.
	//
	//   Distinct OSLs are paved for every minute (60 seconds). Each OSL
	//   key is split such that, for those 60 seconds, a client must seed
	//   2/3 spec SLOKs for 7 of 10 consecutive 100 ms. time periods within
	//   a second, for any 5 of 60 seconds within the minute.
	//
	SeedPeriodKeySplits []KeySplit
	// contains filtered or unexported fields
}

Scheme defines a OSL seeding and distribution strategy. SLOKs to decrypt OSLs are issued based on client network activity -- defined in the SeedSpecs -- and time. OSLs are created for periods of time and can be decrypted by clients that are seeded with a sufficient selection of SLOKs for that time period. Distribution of server entries to OSLs is delegated to automation.

type SeedPayload

type SeedPayload struct {
	SLOKs []*SLOK
}

SeedPayload is the list of seeded SLOKs sent to a client.

type SeedSpec

type SeedSpec struct {
	Description     string
	ID              []byte
	UpstreamSubnets []string
	Targets         TrafficValues
}

SeedSpec defines a client traffic pattern that results in a seeded SLOK. For each time period, a unique SLOK is issued to a client that meets the traffic levels specified in Targets. All upstream port forward traffic to UpstreamSubnets is counted towards the targets.

ID is a SLOK key derivation component and must be 32 random bytes, base64 encoded. UpstreamSubnets is a list of CIDRs. Description is not used; it's for JSON config file comments.

type TrafficValues

type TrafficValues struct {
	BytesRead                      int64
	BytesWritten                   int64
	PortForwardDurationNanoseconds int64
}

TrafficValues defines a client traffic level that seeds a SLOK. BytesRead and BytesWritten are the minimum bytes transferred counts to seed a SLOK. Both UDP and TCP data will be counted towards these totals. PortForwardDurationNanoseconds is the duration that a TCP or UDP port forward is active (not connected, in the UDP case). All threshold settings must be met to seed a SLOK; any threshold may be set to 0 to be trivially satisfied.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL