├── .travis.yml ├── .gitattributes ├── .editorconfig ├── .gitignore ├── src ├── test │ └── java │ │ ├── SSLPokeIgnoreRevocationTest.java │ │ ├── SSLPokeClientProtocolTest.java │ │ └── SSLPokeTest.java └── main │ └── java │ └── SSLPoke.java ├── .github └── workflows │ ├── maven-ci.yml │ └── maven-release.yml ├── doc └── java11systemPropertyNames.txt ├── pom.xml ├── README.md └── LICENSE /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: oraclejdk8 3 | after_success: 4 | - mvn coveralls:report 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # When shell scripts end in CRLF, bash gives a cryptic error message 2 | *.sh text eol=lf 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | 15 | [*.yml] 16 | indent_size = 2 17 | 18 | [*.sh] 19 | end_of_line = lf 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # Standard Maven .gitignore 3 | # 4 | target/ 5 | pom.xml.tag 6 | pom.xml.releaseBackup 7 | pom.xml.versionsBackup 8 | pom.xml.next 9 | release.properties 10 | dependency-reduced-pom.xml 11 | buildNumber.properties 12 | .mvn/timing.properties 13 | 14 | # 15 | # IntelliJ 16 | # 17 | *.iml 18 | .idea/* 19 | !.idea/runConfigurations/ 20 | 21 | # 22 | # Visual Studio Code 23 | # 24 | .settings/ 25 | .classpath 26 | .project 27 | .vscode/ 28 | 29 | # secrets 30 | *.p12 31 | *.jks 32 | -------------------------------------------------------------------------------- /src/test/java/SSLPokeIgnoreRevocationTest.java: -------------------------------------------------------------------------------- 1 | import static org.junit.jupiter.api.Assertions.assertNotNull; 2 | 3 | import java.io.IOException; 4 | import java.net.UnknownHostException; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import org.junitpioneer.jupiter.ClearSystemProperty; 8 | 9 | /** 10 | * Unit test. 11 | */ 12 | @ClearSystemProperty(key = "com.sun.net.ssl.checkRevocation") 13 | @ClearSystemProperty(key = "com.sun.security.enableCRLDP") 14 | public class SSLPokeIgnoreRevocationTest { 15 | 16 | @Test 17 | public void ignoreRevocation() throws UnknownHostException, IOException { 18 | assertNotNull(SSLPoke.connect("revoked-rsa-dv.ssl.com", 443)); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/SSLPokeClientProtocolTest.java: -------------------------------------------------------------------------------- 1 | import static org.junit.jupiter.api.Assertions.assertThrows; 2 | 3 | import java.io.IOException; 4 | import java.net.UnknownHostException; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import org.junitpioneer.jupiter.ClearSystemProperty; 8 | import org.junitpioneer.jupiter.SetSystemProperty; 9 | 10 | /** 11 | * Unit test. 12 | */ 13 | @ClearSystemProperty(key = "com.sun.net.ssl.checkRevocation") 14 | @ClearSystemProperty(key = "com.sun.security.enableCRLDP") 15 | public class SSLPokeClientProtocolTest { 16 | 17 | @Test 18 | @SetSystemProperty(key = "jdk.tls.client.protocols", value = "SSLv3") 19 | public void sslV3() throws UnknownHostException, IOException { 20 | assertThrows(javax.net.ssl.SSLHandshakeException.class, 21 | () -> SSLPoke.connect("www.badssl.com", 443)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/maven-ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v5 18 | 19 | - name: Set up JDK 8 20 | uses: actions/setup-java@v5 21 | with: 22 | java-version: "8" 23 | distribution: "zulu" 24 | cache: maven 25 | 26 | - name: Build with Maven 27 | run: mvn --batch-mode package 28 | 29 | - name: Upload artifacts 30 | uses: actions/upload-artifact@v5 31 | with: 32 | name: package 33 | path: target/*.jar 34 | -------------------------------------------------------------------------------- /.github/workflows/maven-release.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Publish package on new release 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Set up JDK 8 18 | uses: actions/setup-java@v3 19 | with: 20 | java-version: '8' 21 | distribution: 'zulu' 22 | cache: 'maven' 23 | 24 | - name: Publish package 25 | run: mvn --batch-mode deploy 26 | env: 27 | GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password 28 | 29 | - name: Upload binaries to release 30 | uses: svenstaro/upload-release-action@v2 31 | with: 32 | file: target/*.jar 33 | overwrite: true 34 | file_glob: true 35 | -------------------------------------------------------------------------------- /doc/java11systemPropertyNames.txt: -------------------------------------------------------------------------------- 1 | "com.sun.net.ssl.checkRevocation", 2 | "https.cipherSuites", 3 | "https.protocols", 4 | "https.proxyHost", 5 | "https.proxyPort", 6 | "java.protocol.handler.pkgs", 7 | "javax.net.ssl.keyStore", 8 | "javax.net.ssl.keyStorePassword", 9 | "javax.net.ssl.keyStoreProvider", 10 | "javax.net.ssl.keyStoreType", 11 | "javax.net.ssl.sessionCacheSize", 12 | "javax.net.ssl.trustStore", 13 | "javax.net.ssl.trustStorePassword", 14 | "javax.net.ssl.trustStoreProvider", 15 | "javax.net.ssl.trustStoreType", 16 | "jdk.tls.acknowledgeCloseNotify", 17 | "jdk.tls.allowUnsafeServerCertChange", 18 | "jdk.tls.client.cipherSuites", 19 | "jdk.tls.client.disableExtensions", 20 | "jdk.tls.client.protocols", 21 | "jdk.tls.client.SignatureSchemes", 22 | "jdk.tls.ephemeralDHKeySize", 23 | "jdk.tls.maxCertificateChainLength", 24 | "jdk.tls.maxHandshakeMessageSize", 25 | "jdk.tls.namedGroups", 26 | "jdk.tls.server.cipherSuites", 27 | "jdk.tls.server.disableExtensions", 28 | "jdk.tls.server.protocols", 29 | "jdk.tls.server.SignatureSchemes", 30 | "jsse.enableFFDHE", 31 | "jsse.enableMFLNExtension", 32 | "jsse.enableSNIExtension", 33 | "jsse.SSLEngine.acceptLargeFragments", 34 | "sun.security.ssl.allowLegacyHelloMessages", 35 | "sun.security.ssl.allowUnsafeRenegotiation", 36 | -------------------------------------------------------------------------------- /src/test/java/SSLPokeTest.java: -------------------------------------------------------------------------------- 1 | import static org.junit.jupiter.api.Assertions.assertEquals; 2 | import static org.junit.jupiter.api.Assertions.assertNotNull; 3 | import static org.junit.jupiter.api.Assertions.assertThrows; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.io.IOException; 7 | import java.net.UnknownHostException; 8 | 9 | import org.junit.jupiter.api.Test; 10 | import org.junitpioneer.jupiter.SetSystemProperty; 11 | 12 | /** 13 | * Unit test. 14 | */ 15 | @SetSystemProperty(key = "com.sun.net.ssl.checkRevocation", value = "true") 16 | @SetSystemProperty(key = "com.sun.security.enableCRLDP", value = "true") 17 | public class SSLPokeTest { 18 | @Test 19 | public void certificateWithCrlDp() throws UnknownHostException, IOException { 20 | Object result = SSLPoke.connect("www.microsoft.com", 443); 21 | assertNotNull(result); 22 | } 23 | 24 | @Test 25 | public void unknownHost() throws UnknownHostException, IOException { 26 | assertThrows(java.net.UnknownHostException.class, 27 | () -> SSLPoke.connect("host.invalid", 443)); 28 | } 29 | 30 | @Test 31 | public void expired() throws UnknownHostException, IOException { 32 | assertThrows(javax.net.ssl.SSLHandshakeException.class, 33 | () -> SSLPoke.connect("expired.badssl.com", 443)); 34 | 35 | } 36 | 37 | @Test 38 | public void wrongHost() throws UnknownHostException, IOException { 39 | assertThrows(javax.net.ssl.SSLHandshakeException.class, 40 | () -> SSLPoke.connect("wrong.host.badssl.com", 443)); 41 | } 42 | 43 | @Test 44 | public void selfSigned() throws UnknownHostException, IOException { 45 | assertThrows(javax.net.ssl.SSLHandshakeException.class, 46 | () -> SSLPoke.connect("self-signed.badssl.com", 443)); 47 | } 48 | 49 | @Test 50 | public void untrustedRoot() throws UnknownHostException, IOException { 51 | assertThrows(javax.net.ssl.SSLHandshakeException.class, 52 | () -> SSLPoke.connect("untrusted-root.badssl.com", 443)); 53 | } 54 | 55 | @Test 56 | public void revoked() throws UnknownHostException, IOException { 57 | assertEquals("true", System.getProperty("com.sun.net.ssl.checkRevocation")); 58 | assertEquals("true", System.getProperty("com.sun.security.enableCRLDP")); 59 | Exception exception = assertThrows(javax.net.ssl.SSLHandshakeException.class, 60 | () -> SSLPoke.connect("revoked-rsa-dv.ssl.com", 443)); 61 | assertTrue(exception.getMessage().contains("Certificate has been revoked")); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | de.norbertklasen.security 6 | sslpoke 7 | 1.1.1 8 | 9 | 1.8 10 | 1.8 11 | UTF-8 12 | 13 | 14 | 15 | org.junit.jupiter 16 | junit-jupiter-api 17 | 5.6.2 18 | test 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter-engine 23 | 5.6.2 24 | test 25 | 26 | 27 | org.junit-pioneer 28 | junit-pioneer 29 | 0.5.6 30 | test 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-checkstyle-plugin 39 | 3.0.0 40 | 41 | 42 | com.puppycrawl.tools 43 | checkstyle 44 | 8.29 45 | 46 | 47 | com.github.ngeor 48 | checkstyle-rules 49 | 1.1.0 50 | 51 | 52 | 53 | com/github/ngeor/checkstyle.xml 54 | true 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-checkstyle-plugin 63 | 64 | 65 | 69 | 70 | org.jacoco 71 | jacoco-maven-plugin 72 | 0.8.1 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-jar-plugin 77 | 3.2.0 78 | 79 | 80 | 81 | true 82 | SSLPoke 83 | 84 | 85 | 86 | 87 | 88 | maven-surefire-plugin 89 | 2.22.2 90 | 91 | false 92 | 4 93 | 94 | 95 | 96 | maven-failsafe-plugin 97 | 2.22.2 98 | 99 | 100 | 101 | 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-javadoc-plugin 106 | 3.0.0 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-checkstyle-plugin 111 | 112 | com/github/ngeor/checkstyle.xml 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 120 | 125 | 126 | jacoco 127 | 128 | 129 | env.TRAVIS 130 | 131 | 132 | 133 | 134 | 135 | org.jacoco 136 | jacoco-maven-plugin 137 | 138 | 139 | prepare-agent 140 | validate 141 | 142 | prepare-agent 143 | 144 | 145 | 146 | report 147 | test 148 | 149 | report 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 163 | 164 | travis 165 | 166 | 167 | env.TRAVIS 168 | 169 | 170 | 171 | 172 | 173 | org.apache.maven.plugins 174 | maven-checkstyle-plugin 175 | 176 | 177 | checkstyle 178 | test 179 | 180 | check 181 | 182 | 183 | 184 | 185 | 186 | org.eluder.coveralls 187 | coveralls-maven-plugin 188 | 4.3.0 189 | 190 | 191 | 192 | 193 | 194 | 195 | https://github.com/klasen/sslpoke 196 | 197 | 198 | 199 | https://github.com/klasen/sslpoke/issues 200 | GitHub 201 | 202 | 203 | 204 | 205 | github 206 | https://maven.pkg.github.com/klasen/sslpoke 207 | 208 | true 209 | 210 | 211 | true 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SSLPoke 2 | 3 | ![Java CI with Maven](https://github.com/klasen/sslpoke/workflows/Java%20CI%20with%20Maven/badge.svg) 4 | 5 | Test establishment of a TLS connection to a host with Java. 6 | 7 | This version has been enhanced to print all known system and security properties relevant to TLS and HTTPS. 8 | 9 | ## Usage 10 | 11 | Positive test: 12 | 13 | ```sh 14 | java -jar sslpoke.jar www.github.com 443 15 | ``` 16 | 17 | You should get this: 18 | 19 | ```log 20 | connecting to www.github.com:443 with the following system and security properties: 21 | java.version: System: 1.8.0_251 22 | java.vendor: System: Oracle Corporation 23 | policy.allowSystemProperty: Security: true 24 | java.security.policy: 25 | CertPathValidator.PKIX: 26 | cert.provider.x509v1: 27 | java.protocol.handler.pkgs: 28 | security.provider.1: Security: sun.security.provider.Sun 29 | ssl.ServerSocketFactory.provider: 30 | ssl.SocketFactory.provider: 31 | jdk.tls.client.protocols: 32 | jdk.tls.disabledAlgorithms: Security: SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL 33 | jdk.tls.legacyAlgorithms: Security: K_NULL, C_NULL, M_NULL, DH_anon, ECDH_anon, RC4_128, RC4_40, DES_CBC, DES40_CBC, 3DES_EDE_CBC 34 | jdk.tls.ephemeralDHKeySize: 35 | jsse.enableSNIExtension: 36 | https.cipherSuites: 37 | https.protocols: 38 | sun.security.ssl.allowUnsafeRenegotiation: 39 | sun.security.ssl.allowLegacyHelloMessages: 40 | keystore.type: Security: jks 41 | keystore.type.compat: Security: true 42 | javax.net.ssl.trustStore: 43 | javax.net.ssl.trustStorePassword: 44 | javax.net.ssl.trustStoreType: 45 | javax.net.ssl.keyStore: 46 | javax.net.ssl.keyStorePassword: 47 | javax.net.ssl.keyStoreType: 48 | CertPathValidator.PKIX: 49 | jdk.certpath.disabledAlgorithms: Security: MD2, MD5, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224 50 | com.sun.net.ssl.checkRevocation: 51 | com.sun.security.enableCRLDP: 52 | com.sun.security.crl.timeout: 53 | sun.security.certpath.ldap.cache.lifetime: 54 | com.sun.security.enableAIAcaIssuers: 55 | ocsp.enable: 56 | ocsp.responderURL: 57 | ocsp.responderCertSubjectName: 58 | ocsp.responderCertIssuerName: 59 | ocsp.responderCertSerialNumber: 60 | http.nonProxyHosts: 61 | https.protocols: 62 | https.proxyHost: 63 | https.proxyPort: 64 | java.security.debug: 65 | javax.net.debug: 66 | 67 | Successfully connected. 68 | Protocol: TLSv1.2 69 | Cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 70 | ``` 71 | 72 | Negative tests (courtesy of [badssl.com](https://badssl.com)): 73 | 74 | ``` 75 | java -jar sslpoke.jar expired.badssl.com 443 76 | java -jar sslpoke.jar wrong.host.badssl.com 443 77 | java -jar sslpoke.jar self-signed.badssl.com 443 78 | java -jar sslpoke.jar untrusted-root.badssl.com 443 79 | java -jar sslpoke.jar revoked.badssl.com 443 80 | java -jar sslpoke.jar cbc.badssl.com 443 81 | java -jar sslpoke.jar rc4-md5.badssl.com 443 82 | java -jar sslpoke.jar rc4.badssl.com 443 83 | java -jar sslpoke.jar 3des.badssl.com 443 84 | java -jar sslpoke.jar null.badssl.com 443 85 | java -jar sslpoke.jar tls-v1-0.badssl.com 1010 86 | java -jar sslpoke.jar tls-v1-1.badssl.com 1011 87 | java -jar sslpoke.jar tls-v1-2.badssl.com 1012 88 | ``` 89 | 90 | Which should get you an error like this: 91 | 92 | ```log 93 | [...] 94 | Connection failed. 95 | javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed 96 | at sun.security.ssl.Alerts.getSSLException(Unknown Source) 97 | at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) 98 | at sun.security.ssl.Handshaker.fatalSE(Unknown Source) 99 | at sun.security.ssl.Handshaker.fatalSE(Unknown Source) 100 | at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source) 101 | at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source) 102 | at sun.security.ssl.Handshaker.processLoop(Unknown Source) 103 | at sun.security.ssl.Handshaker.process_record(Unknown Source) 104 | at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source) 105 | at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) 106 | at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source) 107 | at sun.security.ssl.AppOutputStream.write(Unknown Source) 108 | at sun.security.ssl.AppOutputStream.write(Unknown Source) 109 | at SSLPoke.connect(SSLPoke.java:51) 110 | at SSLPoke.main(SSLPoke.java:84) 111 | Caused by: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed 112 | at sun.security.validator.PKIXValidator.doValidate(Unknown Source) 113 | at sun.security.validator.PKIXValidator.engineValidate(Unknown Source) 114 | at sun.security.validator.Validator.validate(Unknown Source) 115 | at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source) 116 | at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source) 117 | at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) 118 | ... 11 more 119 | Caused by: java.security.cert.CertPathValidatorException: validity check failed 120 | at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(Unknown Source) 121 | at sun.security.provider.certpath.PKIXCertPathValidator.validate(Unknown Source) 122 | at sun.security.provider.certpath.PKIXCertPathValidator.validate(Unknown Source) 123 | at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(Unknown Source) 124 | at java.security.cert.CertPathValidator.validate(Unknown Source) 125 | ... 17 more 126 | Caused by: java.security.cert.CertificateExpiredException: NotAfter: Mon Apr 13 01:59:59 CEST 2015 127 | at sun.security.x509.CertificateValidity.valid(Unknown Source) 128 | at sun.security.x509.X509CertImpl.checkValidity(Unknown Source) 129 | at sun.security.provider.certpath.BasicChecker.verifyValidity(Unknown Source) 130 | at sun.security.provider.certpath.BasicChecker.check(Unknown Source) 131 | ... 22 more 132 | ``` 133 | 134 | ## Java Properties 135 | 136 | The properties that influence the network, TLS protocol, certificate verification and debugging behavior of a JVM are described in: 137 | 138 | - Java Secure Socket Extension (JSSE) Reference Guide ([Java 8](https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#InstallationAndCustomization), [Java 11](https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-93DEEE16-0B70-40E5-BBE7-55C3FD432345)) 139 | - [Java PKI Programmer's Guide](https://docs.oracle.com/javase/8/docs/technotes/guides/security/certpath/CertPathProgGuide.html) 140 | - [Networking Properties](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html) 141 | - [Additional information on Oracle's JDK and JRE Cryptographic Algorithms](https://www.java.com/en/configure_crypto.html) 142 | - [Oracle JRE and JDK Cryptographic Roadmap](https://www.java.com/en/jre-jdk-cryptoroadmap.html) 143 | 144 | So far, I've come across the following parameters that seem relevant: 145 | 146 | - Policy 147 | - policy.allowSystemProperty 148 | - java.security.policy 149 | - Implementation 150 | - cert.provider.x509v1 151 | - java.protocol.handler.pkgs 152 | - security.provider.1 153 | - ssl.ServerSocketFactory.provider 154 | - ssl.SocketFactory.provider 155 | - Protocol 156 | - jdk.tls.client.protocols 157 | - jdk.tls.disabledAlgorithms 158 | - jdk.tls.legacyAlgorithms 159 | - jdk.tls.ephemeralDHKeySize 160 | - jsse.enableSNIExtension 161 | - https.cipherSuites 162 | - https.protocols 163 | - sun.security.ssl.allowUnsafeRenegotiation 164 | - sun.security.ssl.allowLegacyHelloMessages 165 | - Stores 166 | - keystore.type () 167 | - keystore.type.compat () 168 | - javax.net.ssl.trustStore 169 | - javax.net.ssl.trustStorePassword 170 | - javax.net.ssl.trustStoreType 171 | - javax.net.ssl.keyStore 172 | - javax.net.ssl.keyStorePassword 173 | - javax.net.ssl.keyStoreType 174 | - Certificate path validation 175 | - CertPathValidator.PKIX 176 | - jdk.certpath.disabledAlgorithms 177 | - jdk.security.caDistrustPolicies 178 | - com.sun.net.ssl.checkRevocation 179 | - com.sun.security.enableCRLDP 180 | - com.sun.security.crl.timeout 181 | - sun.security.certpath.ldap.cache.lifetime 182 | - com.sun.security.enableAIAcaIssuers 183 | - ocsp.enable 184 | - ocsp.responderURL 185 | - ocsp.responderCertSubjectName 186 | - ocsp.responderCertIssuerName 187 | - ocsp.responderCertSerialNumber 188 | 189 | - Proxy 190 | - http.nonProxyHosts 191 | - https.protocols 192 | - https.proxyHost 193 | - https.proxyPort 194 | 195 | ## Troubleshooting 196 | 197 | To get more detailed logs, set the following properties: 198 | 199 | - showSettings 200 | - 201 | - suggested option: `-XshowSettings:security:all` 202 | - java.security.debug 203 | - 204 | - 205 | - suggested option: `-Djavax.net.debug=ssl,trustmanager,handshake` 206 | - javax.net.debug 207 | - 208 | - suggested option: `-Djava.security.debug=properties,certpath` 209 | 210 | Combined: 211 | ```sh 212 | -XshowSettings:security:all -Djavax.net.debug=ssl,trustmanager,handshake -Djava.security.debug=properties,certpath 213 | ``` 214 | 215 | ## Servers 216 | 217 | To see the protocols and ciphers supported by the server you are trying to connect to you can use tools such as [Qualys SSL Labs](https://www.ssllabs.com/ssltest/) if the server is publicly available or [sslscan](https://www.ssllabs.com/ssltest/) if you are in a private network. 218 | 219 | ## Credits 220 | 221 | - Atlassian for the [base code](https://confluence.atlassian.com/display/JIRA052/Connecting+to+SSL+services) 222 | - @4ndrej for 223 | -------------------------------------------------------------------------------- /src/main/java/SSLPoke.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.io.InputStream; 3 | import java.io.OutputStream; 4 | import java.net.UnknownHostException; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import javax.net.ssl.SNIHostName; 9 | import javax.net.ssl.SNIServerName; 10 | import javax.net.ssl.SSLParameters; 11 | import javax.net.ssl.SSLSession; 12 | import javax.net.ssl.SSLSocket; 13 | import javax.net.ssl.SSLSocketFactory; 14 | 15 | /** 16 | * Test establishment of a HTTPS (TLS) connection to a host and port 17 | * 18 | * @see https://gist.github.com/4ndrej/4547029 19 | */ 20 | public class SSLPoke { 21 | // https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-A41282C3-19A3-400A-A40F-86F4DA22ABA9 22 | final static String[] securityPropertyNames = { 23 | "cert.provider.x509v1", 24 | "com.sun.CORBA.ORBIorTypeCheckRegistryFilter", 25 | "crypto.policy", 26 | "fips.keystore.type", 27 | "fips.provider.1", 28 | "fips.provider.2", 29 | "fips.provider.3", 30 | "fips.provider.4", 31 | "jceks.key.serialFilter", 32 | "jdk.certpath.disabledAlgorithms", 33 | "jdk.disabled.namedCurves", 34 | "jdk.includeInExceptions", 35 | "jdk.io.permissionsUseCanonicalPath", 36 | "jdk.jar.disabledAlgorithms", 37 | "jdk.jceks.iterationCount", 38 | "jdk.jndi.object.factoriesFilter", 39 | "jdk.sasl.disabledMechanisms", 40 | "jdk.security.allowNonCaAnchor", 41 | "jdk.security.caDistrustPolicies", 42 | "jdk.security.krb5.default.initiate.credential", 43 | "jdk.security.legacyAlgorithms", 44 | "jdk.security.provider.preferred", 45 | "jdk.serialFilter", 46 | "jdk.tls.alpnCharset", 47 | "jdk.tls.disabledAlgorithms", 48 | "jdk.tls.keyLimits", 49 | "jdk.tls.legacyAlgorithms", 50 | "jdk.tls.server.defaultDHEParameters", 51 | "jdk.xml.dsig.secureValidationPolicy", 52 | "keystore.pkcs12.certPbeIterationCount", 53 | "keystore.pkcs12.certProtectionAlgorithm", 54 | "keystore.pkcs12.keyPbeIterationCount", 55 | "keystore.pkcs12.keyProtectionAlgorithm", 56 | "keystore.pkcs12.macAlgorithm", 57 | "keystore.pkcs12.macIterationCount", 58 | "keystore.type", 59 | "keystore.type.compat", 60 | "krb5.kdc.bad.policy", 61 | "login.config.url.1", 62 | "login.configuration.provider", 63 | "networkaddress.cache.negative.ttl", 64 | "networkaddress.cache.ttl", 65 | "ocsp.enable", 66 | "package.access", 67 | "package.definition", 68 | "policy.allowSystemProperty", 69 | "policy.expandProperties", 70 | "policy.ignoreIdentityScope", 71 | "policy.provider", 72 | "policy.url.1", 73 | "policy.url.2", 74 | "securerandom.drbg.config", 75 | "securerandom.source", 76 | "securerandom.strongAlgorithms", 77 | "security.overridePropertiesFile", 78 | "security.provider.1", 79 | "security.provider.10", 80 | "security.provider.11", 81 | "security.provider.12", 82 | "security.provider.2", 83 | "security.provider.3", 84 | "security.provider.4", 85 | "security.provider.5", 86 | "security.provider.6", 87 | "security.provider.7", 88 | "security.provider.8", 89 | "security.provider.9", 90 | "security.useSystemPropertiesFile", 91 | "ssl.KeyManagerFactory.algorithm", 92 | "ssl.ServerSocketFactory.provider", 93 | "ssl.SocketFactory.provider", 94 | "ssl.TrustManagerFactory.algorithm", 95 | "sun.rmi.registry.registryFilter", 96 | "sun.rmi.transport.dgcFilter", 97 | "sun.security.krb5.disableReferrals", 98 | "sun.security.krb5.maxReferrals", 99 | }; 100 | 101 | final static String[] systemPropertyNames = { 102 | "java.vendor", 103 | "java.version", 104 | "java.security.debug", 105 | "javax.net.debug", 106 | // https://docs.oracle.com/en/java/javase/11/security/permissions-jdk1.html#GUID-BFF84712-05CF-4C1E-926F-411FDF83AE32 107 | "java.security.policy", 108 | // system proxy 109 | "http_proxy", 110 | "https_proxy", 111 | "no_proxy", 112 | // https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-A41282C3-19A3-400A-A40F-86F4DA22ABA9 113 | "com.sun.net.ssl.checkRevocation", 114 | "https.cipherSuites", 115 | "https.protocols", 116 | "https.proxyHost", 117 | "https.proxyPort", 118 | "http.nonProxyHosts", // https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html 119 | "java.protocol.handler.pkgs", 120 | "javax.net.ssl.keyStore", 121 | "javax.net.ssl.keyStorePassword", 122 | "javax.net.ssl.keyStoreProvider", 123 | "javax.net.ssl.keyStoreType", 124 | "javax.net.ssl.sessionCacheSize", 125 | "javax.net.ssl.trustStore", 126 | "javax.net.ssl.trustStorePassword", 127 | "javax.net.ssl.trustStoreProvider", 128 | "javax.net.ssl.trustStoreType", 129 | "jdk.tls.acknowledgeCloseNotify", 130 | "jdk.tls.allowUnsafeServerCertChange", 131 | "jdk.tls.client.cipherSuites", 132 | "jdk.tls.client.disableExtensions", 133 | "jdk.tls.client.protocols", 134 | "jdk.tls.client.SignatureSchemes", 135 | "jdk.tls.ephemeralDHKeySize", 136 | "jdk.tls.maxCertificateChainLength", 137 | "jdk.tls.maxHandshakeMessageSize", 138 | "jdk.tls.namedGroups", 139 | "jdk.tls.server.cipherSuites", 140 | "jdk.tls.server.disableExtensions", 141 | "jdk.tls.server.protocols", 142 | "jdk.tls.server.SignatureSchemes", 143 | "jsse.enableFFDHE", 144 | "jsse.enableMFLNExtension", 145 | "jsse.enableSNIExtension", 146 | "jsse.SSLEngine.acceptLargeFragments", 147 | "sun.security.ssl.allowLegacyHelloMessages", 148 | "sun.security.ssl.allowUnsafeRenegotiation", 149 | // https://docs.oracle.com/en/java/javase/11/security/java-pki-programmers-guide.html#GUID-FF62B0E3-E57A-4F40-970A-0481AF750CCD 150 | "sun.security.certpath.ldap.cache.lifetime", 151 | // https://docs.oracle.com/en/java/javase/11/security/java-pki-programmers-guide.html#GUID-EB250086-0AC1-4D60-AE2A-FC7461374746 152 | "com.sun.security.crl.timeout", 153 | "com.sun.security.enableAIAcaIssuers", 154 | "com.sun.security.enableCRLDP", 155 | // https://www.oracle.com/java/technologies/javase/8u271-relnotes.html#JDK-8237990 156 | "jdk.jndi.ldap.mechsAllowedToSendCredentials", 157 | // https://www.oracle.com/java/technologies/javase/8u181-relnotes.html 158 | "com.sun.jndi.ldap.object.disableEndpointIdentification", 159 | }; 160 | 161 | static SSLSession connect(final String host, final int port) throws UnknownHostException, IOException { 162 | SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 163 | SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port); 164 | 165 | SSLParameters sslparams = new SSLParameters(); 166 | sslsocket.setSSLParameters(sslparams); 167 | 168 | sslparams.setEndpointIdentificationAlgorithm("HTTPS"); 169 | 170 | // Sets Server Name Indication (SNI) parameter. 171 | final SNIHostName serverName = new SNIHostName(host); 172 | final List serverNames = new ArrayList<>(1); 173 | serverNames.add(serverName); 174 | sslparams.setServerNames(serverNames); 175 | 176 | InputStream in = sslsocket.getInputStream(); 177 | OutputStream out = sslsocket.getOutputStream(); 178 | 179 | // Write a test byte to get a reaction :) 180 | out.write(1); 181 | 182 | while (in.available() > 0) { 183 | System.out.print(in.read()); 184 | } 185 | 186 | return sslsocket.getSession(); 187 | } 188 | 189 | public static void main(final String[] args) { 190 | if (args.length != 2) { 191 | System.out.println("Usage: " + SSLPoke.class.getName() + " "); 192 | System.exit(1); 193 | } 194 | final String host = args[0]; 195 | final Integer port = Integer.parseInt(args[1]); 196 | 197 | // System.setProperty("java.security.debug", "certpath"); 198 | // System.setProperty("javax.net.debug", "ssl"); 199 | // System.setProperty("com.sun.net.ssl.checkRevocation", "true"); 200 | // System.setProperty("com.sun.security.enableCRLDP", "true"); 201 | 202 | System.out.println("connecting to " + host + ":" + port); 203 | 204 | System.out.println("System properties:"); 205 | for (int i = 0; i < systemPropertyNames.length; i++) { 206 | final String value = System.getProperty(systemPropertyNames[i]); 207 | if (value != null) { 208 | System.out.println(systemPropertyNames[i] + ": " + value); 209 | } 210 | } 211 | 212 | // dump all system properties 213 | // Properties systemProperties = System.getProperties(); 214 | // for (Entry property : systemProperties.entrySet()) { 215 | // System.out.println(property.getKey() + ":" + property.getValue()); 216 | // } 217 | 218 | System.out.println(); 219 | 220 | System.out.println("security properties:"); 221 | for (int i = 0; i < securityPropertyNames.length; i++) { 222 | final String value = java.security.Security.getProperty(securityPropertyNames[i]); 223 | if (value != null) { 224 | System.out.println(securityPropertyNames[i] + ": " + value); 225 | } 226 | } 227 | 228 | System.out.println(); 229 | 230 | try { 231 | SSLSession sslSession = connect(host, port); 232 | System.out.println("Successfully connected."); 233 | System.out.println("Protocol: " + sslSession.getProtocol()); 234 | System.out.println("Cipher suite: " + sslSession.getCipherSuite()); 235 | } catch (final Exception exception) { 236 | System.out.println("Connection failed."); 237 | exception.printStackTrace(); 238 | System.exit(1); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons 2 | Creative Commons Legal Code 3 | 4 | Attribution 2.5 Australia 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENCE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. 6 | 7 | Licence 8 | 9 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENCE ("CCPL" OR "LICENCE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORISED UNDER THIS LICENCE AND/OR APPLICABLE LAW IS PROHIBITED. 10 | 11 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENCE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 12 | 13 | 1. Definitions 14 | 15 | "Collective Work" means a work, such as a periodical issue, anthology or encyclopaedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this Licence. 16 | "Derivative Work" means a work that reproduces a substantial part of the Work, or of the Work and other pre-existing works protected by copyright, or that is an adaptation of a Work that is a literary, dramatic, musical or artistic work. Derivative Works include a translation, musical arrangement, dramatisation, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which a work may be adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this Licence. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this Licence. 17 | "Licensor" means the individual or entity that offers the Work under the terms of this Licence. 18 | "Moral rights law" means laws under which an individual who creates a work protected by copyright has rights of integrity of authorship of the work, rights of attribution of authorship of the work, rights not to have authorship of the work falsely attributed, or rights of a similar or analogous nature in the work anywhere in the world. 19 | "Original Author" means the individual or entity who created the Work. 20 | "Work" means the work or other subject-matter protected by copyright that is offered under the terms of this Licence, which may include (without limitation) a literary, dramatic, musical or artistic work, a sound recording or cinematograph film, a published edition of a literary, dramatic, musical or artistic work or a television or sound broadcast. 21 | "You" means an individual or entity exercising rights under this Licence who has not previously violated the terms of this Licence with respect to the Work, or who has received express permission from the Licensor to exercise rights under this Licence despite a previous violation. 22 | "Licence Elements" means the following high-level licence attributes as selected by Licensor and indicated in the title of this Licence: Attribution, NonCommercial, NoDerivatives, ShareAlike. 23 | 24 | 2. Fair Dealing and Other Rights. Nothing in this Licence excludes or modifies, or is intended to exclude or modify, (including by reducing, limiting, or restricting) the rights of You or others to use the Work arising from fair dealings or other limitations on the rights of the copyright owner or the Original Author under copyright law, moral rights law or other applicable laws. 25 | 26 | 3. Licence Grant. Subject to the terms and conditions of this Licence, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) licence to exercise the rights in the Work as stated below: 27 | 28 | to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works; 29 | to create and reproduce Derivative Works; 30 | to publish, communicate to the public, distribute copies or records of, exhibit or display publicly, perform publicly and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works; 31 | to publish, communicate to the public, distribute copies or records of, exhibit or display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works; 32 | For the avoidance of doubt, where the Work is a musical composition: 33 | Performance Royalties Under Blanket Licences. Licensor will not collect, whether individually or via a performance rights society, royalties for Your communication to the public, broadcast, public performance or public digital performance (e.g. webcast) of the Work. 34 | Mechanical Rights and Statutory Royalties. Licensor will not collect, whether individually or via a music rights agency, designated agent or a music publisher, royalties for any record You create from the Work ("cover version") and distribute, subject to the compulsory licence created by 17 USC Section 115 of the US Copyright Act (or an equivalent statutory licence under the Australian Copyright Act or in other jurisdictions). 35 | Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor will not collect, whether individually or via a performance-rights society, royalties for Your public digital performance (e.g. webcast) of the Work, subject to the compulsory licence created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions). 36 | 37 | The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor under this Licence are hereby reserved. 38 | 39 | 4. Restrictions. The licence granted in Section 3 above is expressly made subject to and limited by the following restrictions: 40 | 41 | You may publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work only under the terms of this Licence, and You must include a copy of, or the Uniform Resource Identifier for, this Licence with every copy or record of the Work You publish, communicate to the public, distribute, publicly exhibit or display, publicly perform or publicly digitally perform. You may not offer or impose any terms on the Work that exclude, alter or restrict the terms of this Licence or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this Licence and to the disclaimer of representations and warranties. You may not publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this Licence. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this Licence. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by Section 4(b), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by Section 4(b), as requested. 42 | If you publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work. You must also give clear and reasonably prominent credit to (i) the Original Author (by name or pseudonym if applicable), if the name or pseudonym is supplied; and (ii) if another party or parties (eg a sponsor institute, publishing entity or journal) is designated for attribution in the copyright notice, terms of service or other reasonable means associated with the Work, such party or parties. If applicable, that credit must be given in the particular way made known by the Original Author and otherwise as reasonable to the medium or means You are utilizing, by conveying the identity of the Original Author and the other designated party or parties (if applicable); the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit. 43 | False attribution prohibited. Except as otherwise agreed in writing by the Licensor, if You publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works in accordance with this Licence, You must not falsely attribute the Work to someone other than the Original Author. 44 | Prejudice to honour or reputation prohibited. Except as otherwise agreed in writing by the Licensor, if you publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must not do anything that results in a material distortion of, the mutilation of, or a material alteration to, the Work that is prejudicial to the Original Author's honour or reputation, and You must not do anything else in relation to the Work that is prejudicial to the Original Author's honour or reputation. 45 | 46 | 5. Disclaimer. 47 | 48 | EXCEPT AS EXPRESSLY STATED IN THIS LICENCE OR OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, AND TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK "AS-IS" AND MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS OR ACCURACY OF THE WORK, OR OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. 49 | 50 | 6. Limitation on Liability. 51 | 52 | TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, AND EXCEPT FOR ANY LIABILITY ARISING FROM CONTRARY MUTUAL AGREEMENT AS REFERRED TO IN SECTION 5, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 53 | 54 | If applicable legislation implies warranties or conditions, or imposes obligations or liability on the Licensor in respect of this Licence that cannot be wholly or partly excluded, restricted or modified, the Licensor's liability is limited, to the full extent permitted by the applicable legislation, at its option, to: 55 | 56 | in the case of goods, any one or more of the following: 57 | the replacement of the goods or the supply of equivalent goods; 58 | the repair of the goods; 59 | the payment of the cost of replacing the goods or of acquiring equivalent goods; 60 | the payment of the cost of having the goods repaired; or 61 | in the case of services: 62 | the supplying of the services again; or 63 | the payment of the cost of having the services supplied again. 64 | 65 | 7. Termination. 66 | 67 | This Licence and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this Licence. Individuals or entities who have received Derivative Works or Collective Works from You under this Licence, however, will not have their licences terminated provided such individuals or entities remain in full compliance with those licences. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this Licence. 68 | Subject to the above terms and conditions, the licence granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different licence terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this Licence (or any other licence that has been, or is required to be, granted under the terms of this Licence), and this Licence will continue in full force and effect unless terminated as stated above. 69 | 70 | 8. Miscellaneous. 71 | 72 | Each time You publish, communicate to the public, distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a licence to the Work on the same terms and conditions as the licence granted to You under this Licence. 73 | Each time You publish, communicate to the public, distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a licence to the original Work on the same terms and conditions as the licence granted to You under this Licence. 74 | If any provision of this Licence is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Licence, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. 75 | No term or provision of this Licence shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. 76 | This Licence constitutes the entire agreement between the parties with respect to the Work licensed here. To the full extent permitted by applicable law, there are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This Licence may not be modified without the mutual written agreement of the Licensor and You. 77 | The construction, validity and performance of this Licence shall be governed by the laws in force in New South Wales, Australia. 78 | 79 | Creative Commons is not a party to this Licence, and, to the full extent permitted by applicable law, makes no representation or warranty whatsoever in connection with the Work. To the full extent permitted by applicable law, Creative Commons will not be liable to You or any party on any legal theory (including, without limitation, negligence) for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this licence. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. 80 | 81 | Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. 82 | 83 | Creative Commons may be contacted at https://creativecommons.org/. 84 | --------------------------------------------------------------------------------