diff --git a/pkg/vpn/bitmask.go b/pkg/vpn/bitmask.go
index 701379ebb64fdd29046efbd8b5f1ac81e45564fa..d40a601346e4732e60d502cbbd2263c847d9a546 100644
--- a/pkg/vpn/bitmask.go
+++ b/pkg/vpn/bitmask.go
@@ -33,44 +33,59 @@ import (
 )
 
 type Bitmask struct {
-	tempdir          string
-	onGateway        bonafide.Gateway
-	ptGateway        bonafide.Gateway
-	statusCh         chan string
-	managementClient *management.MgmtClient
-	bonafide         *bonafide.Bonafide
-	launch           *launcher.Launcher
-	transport        string
-	obfsvpnProxy     *obfsvpn.Client
-	certPemPath      string
-	openvpnArgs      []string
-	useUDP           bool
-	useSnowflake     bool
-	canUpgrade       bool
-	motd             []motd.Message
-	provider         string
+	api              apiInterface           // handles backend API communication, implemented in bonafide (v3) or menshen (v5)
+	onGateway        bonafide.Gateway       // gateway we are connected
+	ptGateway        bonafide.Gateway       // public transport gateway we are connected with
+	launch           *launcher.Launcher     // launcher manages the firewall and starts/stops openvpn
+	canUpgrade       bool                   // is there an update available?
+	motd             []motd.Message         // cached message of the day (ony fetched once during startup)
+	statusCh         chan string            // channel used to get current OpenVPN state (remote ip, connection state, ...)
+	managementClient *management.MgmtClient // used to speak with our own management backend (OpenVPN process connects to it)
+	transport        string                 // used transport, e.g. OpenVPN (plain) or obfuscated protocols (obfs4)
+	openvpnArgs      []string               // arguments used for invoking the OpenVPN process
+	useUDP           bool                   // should we use UDP?
+	obfsvpnProxy     *obfsvpn.Client        // handles OpenVPN obfuscation, e.g. starts/stops obfs4 bridge
+	useSnowflake     bool                   // should we use Snowflake?
+	provider         string                 // currently not used, get fixed if we get to the provider agnostic client
+	tempdir          string                 // random base temp dir. Used for OpenVPN CA (cacert.pem),
+	// client certificate (openvpn.pem, holds key and certificate) and management communication
+	// authentication (key file prefixed with leap-vpn-...). Directory gets deleted during teardown
+	certPemPath string // path of OpenVPN client certificate. Normally this is $tempdir/openvpn.pem,
+	// but it also can be $config/$provider.pem (if snowflake is used or supplied out-of-band in a censored network)
 }
 
 // Init the connection to bitmask
 func Init() (*Bitmask, error) {
-	statusCh := make(chan string, 10)
 	tempdir, err := ioutil.TempDir("", "leap-")
 	if err != nil {
 		return nil, err
 	}
-	bf := bonafide.New()
+
+	api := bonafide.New()
 	launch, err := launcher.NewLauncher()
 	if err != nil {
 		return nil, err
 	}
 
 	b := Bitmask{
-		tempdir,
-		bonafide.Gateway{},
-		bonafide.Gateway{}, statusCh, nil, bf, launch,
-		"", nil, "", []string{},
-		false, false, isUpgradeAvailable(),
-		[]motd.Message{}, ""}
+		tempdir:          tempdir,
+		onGateway:        bonafide.Gateway{},
+		ptGateway:        bonafide.Gateway{},
+		statusCh:         make(chan string, 10),
+		managementClient: nil,
+		api:              api,
+		launch:           launch,
+		transport:        "",
+		obfsvpnProxy:     nil,
+		certPemPath:      "",
+		openvpnArgs:      []string{},
+		useUDP:           false,
+		useSnowflake:     false,
+		canUpgrade:       isUpgradeAvailable(),
+		motd:             motd.FetchLatest(),
+		provider:         "",
+	}
+
 	// FIXME multiprovider: need to pass provider name early on
 	// XXX we want to block on these, but they can timeout if we're blocked.
 	b.checkForMOTD()
@@ -111,7 +126,7 @@ func (b *Bitmask) GetStatusCh() <-chan string {
 }
 
 func (b *Bitmask) GetSnowflakeCh() <-chan *snowflake.StatusEvent {
-	return b.bonafide.GetSnowflakeCh()
+	return b.api.GetSnowflakeCh()
 }
 
 // Close the connection to bitmask, and does cleanup of temporal files
@@ -145,11 +160,11 @@ func (b *Bitmask) Version() (string, error) {
 }
 
 func (b *Bitmask) NeedsCredentials() bool {
-	return b.bonafide.NeedsCredentials()
+	return b.api.NeedsCredentials()
 }
 
 func (b *Bitmask) DoLogin(username, password string) (bool, error) {
-	return b.bonafide.DoLogin(username, password)
+	return b.api.DoLogin(username, password)
 }
 
 func (b *Bitmask) UseUDP(udp bool) {
@@ -162,7 +177,7 @@ func (b *Bitmask) UseSnowflake(s bool) error {
 }
 
 func (b *Bitmask) OffersUDP() bool {
-	return b.bonafide.IsUDPAvailable()
+	return b.api.IsUDPAvailable()
 }
 
 func (b *Bitmask) GetMotd() string {
diff --git a/pkg/vpn/interface.go b/pkg/vpn/interface.go
new file mode 100644
index 0000000000000000000000000000000000000000..91575e6fcbd64f5b4c9a4114abb2093fbf7901dc
--- /dev/null
+++ b/pkg/vpn/interface.go
@@ -0,0 +1,24 @@
+package vpn
+
+import (
+	"0xacab.org/leap/bitmask-vpn/pkg/snowflake"
+	"0xacab.org/leap/bitmask-vpn/pkg/vpn/bonafide"
+)
+
+type apiInterface interface {
+	NeedsCredentials() bool
+	DoLogin(username, password string) (bool, error)
+	GetLocationQualityMap(transport string) map[string]float64
+	GetLocationLabels(transport string) map[string][]string
+	SetManualGateway(label string)
+	SetAutomaticGateway()
+	IsManualLocation() bool
+	IsUDPAvailable() bool
+	GetBestLocation(transport string) (string, error)
+	GetPemCertificate() ([]byte, error)
+	GetOpenvpnArgs() ([]string, error)
+	GetGatewayByIP(ip string) (bonafide.Gateway, error)
+	GetBestGateways(transport string) ([]bonafide.Gateway, error)
+	GetAllGateways(transport string) ([]bonafide.Gateway, error)
+	GetSnowflakeCh() chan *snowflake.StatusEvent
+}
diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go
index 47b3933abde78dff77feb4c406f7ad3bd996fabb..0f90770e87020fb2b0a54d37481f5ba2a19b98dc 100644
--- a/pkg/vpn/openvpn.go
+++ b/pkg/vpn/openvpn.go
@@ -49,7 +49,7 @@ func (b *Bitmask) StartVPN(provider string) error {
 	if err != nil {
 		return err
 	}
-	b.openvpnArgs, err = b.bonafide.GetOpenvpnArgs()
+	b.openvpnArgs, err = b.api.GetOpenvpnArgs()
 	if err != nil {
 		return err
 	}
@@ -62,7 +62,7 @@ func (b *Bitmask) CanStartVPN() bool {
 	/* FIXME this is not enough. We should check, if provider needs
 	* credentials, if we have a valid token, otherwise remove it and
 	make sure that we're asking for the credentials input */
-	return !b.bonafide.NeedsCredentials()
+	return !b.api.NeedsCredentials()
 }
 
 func (b *Bitmask) startTransportForPrivateBridge(ctx context.Context, gw bonafide.Gateway) (proxy string, err error) {
@@ -98,7 +98,7 @@ func (b *Bitmask) startTransport(ctx context.Context, host string) (proxy string
 		return proxyAddr, nil
 	}
 
-	gateways, err := b.bonafide.GetBestGateways(b.transport)
+	gateways, err := b.api.GetBestGateways(b.transport)
 	if err != nil {
 		return "", err
 	}
@@ -226,7 +226,7 @@ func (b *Bitmask) startOpenVPN(ctx context.Context) error {
 
 			log.Debug().Msg("Getting a gateway with obfs4 transport...")
 
-			gateways, err := b.bonafide.GetBestGateways("obfs4")
+			gateways, err := b.api.GetBestGateways("obfs4")
 			if err != nil {
 				return err
 			}
@@ -261,7 +261,7 @@ func (b *Bitmask) startOpenVPN(ctx context.Context) error {
 		log.Info().
 			Str("args", strings.Join(arg, " ")).
 			Msg("args passed to bitmask-root")
-		gateways, err := b.bonafide.GetBestGateways("openvpn")
+		gateways, err := b.api.GetBestGateways("openvpn")
 		if err != nil {
 			return err
 		}
@@ -349,7 +349,7 @@ func (b *Bitmask) getCert() (certPath string, err error) {
 			log.Info().
 				Str("certPath", certPath).
 				Msg("Fetching certificate")
-			cert, err := b.bonafide.GetPemCertificate()
+			cert, err := b.api.GetPemCertificate()
 			if err != nil {
 				log.Warn().
 					Err(err).
@@ -373,7 +373,7 @@ func (b *Bitmask) getCert() (certPath string, err error) {
 // Explicit call to GetGateways, to be able to fetch them all before starting the vpn
 func (b *Bitmask) fetchGateways() {
 	log.Info().Msg("Fetching gateways...")
-	_, err := b.bonafide.GetAllGateways(b.transport)
+	_, err := b.api.GetAllGateways(b.transport)
 	if err != nil {
 		log.Warn().
 			Err(err).
@@ -447,7 +447,7 @@ func (b *Bitmask) ReloadFirewall() error {
 	}
 
 	if status != Off {
-		gateways, err := b.bonafide.GetAllGateways("any")
+		gateways, err := b.api.GetAllGateways("any")
 		if err != nil {
 			return err
 		}
@@ -479,22 +479,22 @@ func (b *Bitmask) VPNCheck() (helpers bool, privilege bool, err error) {
 }
 
 func (b *Bitmask) GetLocationQualityMap(transport string) map[string]float64 {
-	return b.bonafide.GetLocationQualityMap(transport)
+	return b.api.GetLocationQualityMap(transport)
 }
 
 func (b *Bitmask) GetLocationLabels(transport string) map[string][]string {
-	return b.bonafide.GetLocationLabels(transport)
+	return b.api.GetLocationLabels(transport)
 }
 
 // UseGateway selects a gateway, by label, as the default gateway
 func (b *Bitmask) UseGateway(label string) {
-	b.bonafide.SetManualGateway(label)
+	b.api.SetManualGateway(label)
 }
 
 // UseAutomaticGateway sets the gateway to be selected automatically
 // best gateway will be used
 func (b *Bitmask) UseAutomaticGateway() {
-	b.bonafide.SetAutomaticGateway()
+	b.api.SetAutomaticGateway()
 }
 
 // SetTransport selects an obfuscation transport to use
diff --git a/pkg/vpn/status.go b/pkg/vpn/status.go
index aa12437508435b01900d66e7743bfd47e88b8552..ef81b8c9ddc199000edbbc8ff773d7448a57491b 100644
--- a/pkg/vpn/status.go
+++ b/pkg/vpn/status.go
@@ -88,7 +88,7 @@ func (b *Bitmask) eventHandler(eventCh <-chan management.Event) {
 				// we're using pluggable transports
 				b.onGateway = b.ptGateway
 			} else {
-				gw, err := b.bonafide.GetGatewayByIP(ip)
+				gw, err := b.api.GetGatewayByIP(ip)
 				if err == nil {
 					b.onGateway = gw
 					log.Info().
@@ -118,7 +118,7 @@ func (b *Bitmask) GetCurrentCountry() string {
 }
 
 func (b *Bitmask) GetBestLocation(transport string) string {
-	location, err := b.bonafide.GetBestLocation(transport)
+	location, err := b.api.GetBestLocation(transport)
 	if err != nil {
 		log.Warn().
 			Err(err).
@@ -129,7 +129,7 @@ func (b *Bitmask) GetBestLocation(transport string) string {
 }
 
 func (b *Bitmask) IsManualLocation() bool {
-	return b.bonafide.IsManualLocation()
+	return b.api.IsManualLocation()
 }
 
 func (b *Bitmask) getOpenvpnState() (string, error) {