From 7f32b4389512c85b86b82ea6227193a4bb3065ff Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Thu, 9 Jun 2022 17:11:08 +0000 Subject: [PATCH] fix(pia): load custom PIA certificate for API --- .../privateinternetaccess/httpclient.go | 22 +++++++++++++++++-- .../privateinternetaccess/httpclient_test.go | 22 ++++++++++++++++++- .../privateinternetaccess/portforward.go | 10 +++++++-- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/internal/provider/privateinternetaccess/httpclient.go b/internal/provider/privateinternetaccess/httpclient.go index 97a42be0..22613796 100644 --- a/internal/provider/privateinternetaccess/httpclient.go +++ b/internal/provider/privateinternetaccess/httpclient.go @@ -2,12 +2,29 @@ package privateinternetaccess import ( "crypto/tls" + "crypto/x509" + "fmt" "net" "net/http" + "strings" "time" + + "github.com/qdm12/gluetun/internal/provider/utils" ) -func newHTTPClient(serverName string) (client *http.Client) { +func newHTTPClient(serverName string) (client *http.Client, err error) { + rootCAs, err := x509.SystemCertPool() + if err != nil { + return nil, fmt.Errorf("cannot load system certificates: %w", err) + } + + const piaCertificate = "MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQwMzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVkhjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULNDe4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9KV2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SNDfCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZylp7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7pKwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzjtRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wijSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNzmeGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNVHQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRtyWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCtpXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dvEm89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1GtF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZuLfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj35xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnXJUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJiyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ=" //nolint:lll + pemPIACertificate := strings.Join(utils.WrapOpenvpnCA(piaCertificate), "\n") + ok := rootCAs.AppendCertsFromPEM([]byte(pemPIACertificate)) + if !ok { + panic("cannot load custom PIA certificate") + } + //nolint:gomnd return &http.Client{ Transport: &http.Transport{ @@ -23,10 +40,11 @@ func newHTTPClient(serverName string) (client *http.Client) { TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, TLSClientConfig: &tls.Config{ + RootCAs: rootCAs, MinVersion: tls.VersionTLS12, ServerName: serverName, }, }, Timeout: 30 * time.Second, - } + }, nil } diff --git a/internal/provider/privateinternetaccess/httpclient_test.go b/internal/provider/privateinternetaccess/httpclient_test.go index f764a492..4ee2daca 100644 --- a/internal/provider/privateinternetaccess/httpclient_test.go +++ b/internal/provider/privateinternetaccess/httpclient_test.go @@ -2,6 +2,8 @@ package privateinternetaccess import ( "crypto/tls" + "crypto/x509/pkix" + "encoding/asn1" "net/http" "testing" @@ -21,11 +23,29 @@ func Test_newHTTPClient(t *testing.T) { ServerName: serverName, } - piaClient := newHTTPClient(serverName) + piaClient, err := newHTTPClient(serverName) + require.NoError(t, err) // Verify pia transport TLS config is set piaTransport, ok := piaClient.Transport.(*http.Transport) require.True(t, ok) + + subjects := piaTransport.TLSClientConfig.RootCAs.Subjects() + assert.NotEmpty(t, subjects) + piaCertFound := false + for _, subject := range subjects { + var rdnSequence pkix.RDNSequence + _, err := asn1.Unmarshal(subject, &rdnSequence) + require.NoError(t, err) + var name pkix.Name + name.FillFromRDNSequence(&rdnSequence) + if name.CommonName == "Private Internet Access" { + piaCertFound = true + break + } + } + assert.True(t, piaCertFound) + piaTransport.TLSClientConfig.RootCAs = nil assert.Equal(t, expectedPIATransportTLSConfig, piaTransport.TLSClientConfig) } diff --git a/internal/provider/privateinternetaccess/portforward.go b/internal/provider/privateinternetaccess/portforward.go index c0ca75e0..d7cd419d 100644 --- a/internal/provider/privateinternetaccess/portforward.go +++ b/internal/provider/privateinternetaccess/portforward.go @@ -46,7 +46,10 @@ func (p *Provider) PortForward(ctx context.Context, client *http.Client, return 0, ErrServerNameEmpty } - privateIPClient := newHTTPClient(serverName) + privateIPClient, err := newHTTPClient(serverName) + if err != nil { + return 0, fmt.Errorf("cannot create custom HTTP client: %w", err) + } data, err := readPIAPortForwardData(p.portForwardPath) if err != nil { @@ -89,7 +92,10 @@ var ( func (p *Provider) KeepPortForward(ctx context.Context, client *http.Client, port uint16, gateway net.IP, serverName string) (err error) { - privateIPClient := newHTTPClient(serverName) + privateIPClient, err := newHTTPClient(serverName) + if err != nil { + return fmt.Errorf("cannot create custom HTTP client: %w", err) + } data, err := readPIAPortForwardData(p.portForwardPath) if err != nil {