// Copyright (c) 2020 Proton Technologies AG // // This file is part of ProtonMail Bridge. // // ProtonMail Bridge is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ProtonMail Bridge is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . package pmapi import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" ) const liveAPI = "api.protonmail.ch" var testLiveConfig = &ClientConfig{ AppVersion: "Bridge_1.2.4-test", ClientID: "Bridge", } func createAndSetPinningDialer(cm *ClientManager) (*int, *PinningTLSDialer) { called := 0 dialer := NewPinningTLSDialer(NewBasicTLSDialer()) dialer.SetTLSIssueNotifier(func() { called++ }) cm.SetRoundTripper(CreateTransportWithDialer(dialer)) return &called, dialer } func TestTLSPinValid(t *testing.T) { cm := newTestClientManager(testLiveConfig) cm.host = liveAPI rootScheme = "https" called, _ := createAndSetPinningDialer(cm) client := cm.GetClient("pmapi" + t.Name()) _, err := client.AuthInfo("this.address.is.disabled") Ok(t, err) Equals(t, 0, *called) } func TestTLSPinBackup(t *testing.T) { cm := newTestClientManager(testLiveConfig) cm.host = liveAPI called, p := createAndSetPinningDialer(cm) p.pinChecker.trustedPins[1] = p.pinChecker.trustedPins[0] p.pinChecker.trustedPins[0] = "" client := cm.GetClient("pmapi" + t.Name()) _, err := client.AuthInfo("this.address.is.disabled") Ok(t, err) Equals(t, 0, *called) } func _TestTLSPinNoMatch(t *testing.T) { // nolint[unused] cm := newTestClientManager(testLiveConfig) cm.host = liveAPI called, p := createAndSetPinningDialer(cm) for i := 0; i < len(p.pinChecker.trustedPins); i++ { p.pinChecker.trustedPins[i] = "testing" } client := cm.GetClient("pmapi" + t.Name()) _, err := client.AuthInfo("this.address.is.disabled") Ok(t, err) // check that it will be called only once per session client = cm.GetClient("pmapi" + t.Name()) _, err = client.AuthInfo("this.address.is.disabled") Ok(t, err) Equals(t, 1, *called) } func _TestTLSPinInvalid(t *testing.T) { // nolint[unused] cm := newTestClientManager(testLiveConfig) ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { writeJSONResponsefromFile(t, w, "/auth/info/post_response.json", 0) })) defer ts.Close() called, _ := createAndSetPinningDialer(cm) client := cm.GetClient("pmapi" + t.Name()) cm.host = liveAPI _, err := client.AuthInfo("this.address.is.disabled") Ok(t, err) cm.host = ts.URL _, err = client.AuthInfo("this.address.is.disabled") Assert(t, err != nil, "error is expected but have %v", err) Equals(t, 1, *called) } // The tests below should pass but cannot run in CI due to proxy issues. func _TestTLSSignedCertWrongPublicKey(t *testing.T) { // nolint[unused] cm := newTestClientManager(testLiveConfig) _, dialer := createAndSetPinningDialer(cm) _, err := dialer.DialTLS("tcp", "rsa4096.badssl.com:443") assert.Error(t, err, "expected dial to fail because of wrong public key") } func _TestTLSSignedCertTrustedPublicKey(t *testing.T) { // nolint[unused] cm := newTestClientManager(testLiveConfig) _, dialer := createAndSetPinningDialer(cm) dialer.pinChecker.trustedPins = append(dialer.pinChecker.trustedPins, `pin-sha256="W8/42Z0ffufwnHIOSndT+eVzBJSC0E8uTIC8O6mEliQ="`) _, err := dialer.DialTLS("tcp", "rsa4096.badssl.com:443") assert.NoError(t, err, "expected dial to succeed because public key is known and cert is signed by CA") } func _TestTLSSelfSignedCertTrustedPublicKey(t *testing.T) { // nolint[unused] cm := newTestClientManager(testLiveConfig) _, dialer := createAndSetPinningDialer(cm) dialer.pinChecker.trustedPins = append(dialer.pinChecker.trustedPins, `pin-sha256="9SLklscvzMYj8f+52lp5ze/hY0CFHyLSPQzSpYYIBm8="`) _, err := dialer.DialTLS("tcp", "self-signed.badssl.com:443") assert.NoError(t, err, "expected dial to succeed because public key is known despite cert being self-signed") }