diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index 5c96b41c25..56ba0799d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -38,6 +38,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.jar.JarEntry; @@ -46,7 +51,9 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; -import static net.runelite.client.rs.ClientUpdateCheckMode.*; +import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO; +import static net.runelite.client.rs.ClientUpdateCheckMode.NONE; +import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Request; import okhttp3.Response; @@ -81,6 +88,7 @@ public class ClientLoader Map zipFile = new HashMap<>(); { + Certificate[] jagexCertificateChain = getJagexCertificateChain(); String codebase = config.getCodeBase(); String initialJar = config.getInitialJar(); URL url = new URL(codebase + initialJar); @@ -113,6 +121,20 @@ public class ClientLoader buffer.write(tmp, 0, n); } + if (!Arrays.equals(metadata.getCertificates(), jagexCertificateChain)) + { + if (metadata.getName().startsWith("META-INF/")) + { + // META-INF/JAGEXLTD.SF and META-INF/JAGEXLTD.RSA are not signed, but we don't need + // anything in META-INF anyway. + continue; + } + else + { + throw new VerificationException("Unable to verify jar entry: " + metadata.getName()); + } + } + zipFile.put(metadata.getName(), buffer.toByteArray()); } } @@ -201,7 +223,8 @@ public class ClientLoader return rs; } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException - | CompressorException | InvalidHeaderException e) + | CompressorException | InvalidHeaderException | CertificateException | VerificationException + | SecurityException e) { if (e instanceof ClassNotFoundException) { @@ -214,4 +237,11 @@ public class ClientLoader return null; } } + + private static Certificate[] getJagexCertificateChain() throws CertificateException + { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + Collection certificates = certificateFactory.generateCertificates(ClientLoader.class.getResourceAsStream("jagex.crt")); + return certificates.toArray(new Certificate[certificates.size()]); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/rs/VerificationException.java b/runelite-client/src/main/java/net/runelite/client/rs/VerificationException.java new file mode 100644 index 0000000000..040370e8f0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/rs/VerificationException.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.rs; + +class VerificationException extends Exception +{ + public VerificationException(String message) + { + super(message); + } + + public VerificationException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/runelite-client/src/main/resources/net/runelite/client/rs/jagex.crt b/runelite-client/src/main/resources/net/runelite/client/rs/jagex.crt new file mode 100644 index 0000000000..06777e1b5e --- /dev/null +++ b/runelite-client/src/main/resources/net/runelite/client/rs/jagex.crt @@ -0,0 +1,79 @@ +-----BEGIN CERTIFICATE----- +MIIEozCCA4ugAwIBAgIPG66Q8BYiduuCbyAdmzRTMA0GCSqGSIb3DQEBCwUAMEwx +CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xJjAkBgNVBAMTHXRo +YXd0ZSBTSEEyNTYgQ29kZSBTaWduaW5nIENBMB4XDTE4MDgxNDAwMDAwMFoXDTIx +MTEwMzIzNTk1OVowYjELMAkGA1UEBhMCR0IxFzAVBgNVBAgMDkNhbWJyaWRnZXNo +aXJlMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCUphZ2V4IEx0ZDESMBAG +A1UEAwwJSmFnZXggTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +idEgJi0xj7hhEyCMdXHxN31gyHS9Iwmzrda2a10BljKl6DGiSia1UWJ/zaJ88hcU +CjIFeUu0B5WZTXOjtLyxhpSSfVFjjNucCMFZLJ0NPSU554ZircHanCxj+rDxaHid +GBasfyrEujhhrcm9H4p1gyhZoMs5KGbxcdwJoCyNv9rIHiQnJhgzZLqG/rRE4JH7 +pjaijU519ZL8iZpz7oRSYIM1LzwMZcBsO4N71cHLvZpEi9B6wExS2W7/o1CEIqXv +tEHtxEFP5XWaWI/toLUBMdXYoKsVEhHs/zkNrjjMGXXQAcS6KOHHg0S+tZEGms30 +SY/69mtefjQceb5YwPjGuwIDAQABo4IBajCCAWYwCQYDVR0TBAIwADAfBgNVHSME +GDAWgBRXhptUuL6mKYrk9sLiExiJhc3ctzAdBgNVHQ4EFgQU7aoWtfnySWo/xlH3 +pkcMyJ9cLdwwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3RsLnN5bWNiLmNvbS90 +bC5jcmwwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMG4GA1Ud +IARnMGUwYwYGZ4EMAQQBMFkwJgYIKwYBBQUHAgEWGmh0dHBzOi8vd3d3LnRoYXd0 +ZS5jb20vY3BzMC8GCCsGAQUFBwICMCMMIWh0dHBzOi8vd3d3LnRoYXd0ZS5jb20v +cmVwb3NpdG9yeTBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly90 +bC5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly90bC5zeW1jYi5jb20vdGwu +Y3J0MA0GCSqGSIb3DQEBCwUAA4IBAQCWhdlN3dalo14zBJURh3CtITGakbBF6N/T +4xSEVNUtIaJSMHWHVXCMnCEazRKX8C/AaroTuJ1ceUdXJc1CINjIABXz5rVpkWPQ +lPul1PfWyEYIIIEq0PjIEyapnWIDHsZu+HtDIHtRoya3e9p3Ac9+57MsiXLSX9D3 +jueMLakZ20Sy0JLWp2l7WkMjU27Wi3QxpZ3sw7reUzGBPLhGjcbABkqGCHXm+LqT +IrL6j3Co1fSeTGi43siPdP+JI6XK1+mcmTFX6Zktx15UDkYJzn0gqXmzgNQAYNss +iQR8TmbXjlvehDwcVmy/uRW8mWKjlqkMWRJVLoHc+jdUhosApE/5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEmTCCA4GgAwIBAgIQcaC3NpXdsa/COyuaGO5UyzANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTMxMjEwMDAwMDAwWhcNMjMx +MjA5MjM1OTU5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MSYwJAYDVQQDEx10aGF3dGUgU0hBMjU2IENvZGUgU2lnbmluZyBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJtVAkwXBenQZsP8KK3TwP7v4Ol+1B72 +qhuRRv31Fu2YB1P6uocbfZ4fASerudJnyrcQJVP0476bkLjtI1xC72QlWOWIIhq+ +9ceu9b6KsRERkxoiqXRpwXS2aIengzD5ZPGx4zg+9NbB/BL+c1cXNVeK3VCNA/hm +zcp2gxPI1w5xHeRjyboX+NG55IjSLCjIISANQbcL4i/CgOaIe1Nsw0RjgX9oR4wr +Ks9b9IxJYbpphf1rAHgFJmkTMIA4TvFaVcnFUNaqOIlHQ1z+TXOlScWTaf53lpqv +84wOV7oz2Q7GQtMDd8S7Oa2R+fP3llw6ZKbtJ1fB6EDzU/K+KTT+X/kCAwEAAaOC +ARcwggETMC8GCCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL3QyLnN5 +bWNiLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0 +dHA6Ly90MS5zeW1jYi5jb20vVGhhd3RlUENBLmNybDAdBgNVHSUEFjAUBggrBgEF +BQcDAgYIKwYBBQUHAwMwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRow +GAYDVQQDExFTeW1hbnRlY1BLSS0xLTU2ODAdBgNVHQ4EFgQUV4abVLi+pimK5PbC +4hMYiYXN3LcwHwYDVR0jBBgwFoAUe1tFz6/Oy3r9MZIaarbzRutXSFAwDQYJKoZI +hvcNAQELBQADggEBACQ79degNhPHQ/7wCYdo0ZgxbhLkPx4flntrTB6HnovFbKOx +DHtQktWBnLGPLCm37vmRBbmOQfEs9tBZLZjgueqAAUdAlbg9nQO9ebs1tq2cTCf2 +Z0UQycW8h05Ve9KHu93cMO/G1GzMmTVtHOBg081ojylZS4mWCEbJjvx1T8XcCcxO +J4tEzQe8rATgtTOlh5/03XMMkeoSgW/jdfAetZNsRBfVPpfJvQcsVncfhd1G6L/e +LIGUo/flt6fBN591ylV3TV42KcqF2EVBcld1wHlb+jQQBm1kIEK3OsgfHUZkAl/G +R77wxDooVNr2Hk+aohlDpG9J+PxeQiAohItHIG4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- \ No newline at end of file