Browse Source

Merge pull request #671 from csmith/master

Add a KeyStoreLocator.
pull/672/head
Greg Holmes 8 years ago
parent
commit
a68b9b7f13
1 changed files with 129 additions and 0 deletions
  1. 129
    0
      src/com/dmdirc/tls/KeyStoreLocator.java

+ 129
- 0
src/com/dmdirc/tls/KeyStoreLocator.java View File

@@ -0,0 +1,129 @@
1
+/*
2
+ * Copyright (c) 2006-2015 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.tls;
24
+
25
+import java.io.File;
26
+import java.io.FileInputStream;
27
+import java.io.IOException;
28
+import java.security.GeneralSecurityException;
29
+import java.security.KeyStore;
30
+import java.security.KeyStoreException;
31
+import java.security.NoSuchAlgorithmException;
32
+import java.security.NoSuchProviderException;
33
+import java.security.cert.CertificateException;
34
+
35
+import javax.annotation.Nullable;
36
+
37
+/**
38
+ * Locates a platform-appropriate {@link KeyStore} to read trusted root certificates from.
39
+ */
40
+public class KeyStoreLocator {
41
+
42
+    private static final String WINDOWS_PROVIDER = "SunMSCAPI";
43
+    private static final String WINDOWS_TYPE = "Windows-ROOT";
44
+    private static final String MAC_PROVIDER = "Apple";
45
+    private static final String MAC_TYPE = "KeychainStore";
46
+    private static final String LINUX_CACERTS_PATH = "/etc/ssl/certs/java/cacerts";
47
+
48
+    /**
49
+     * Attempts to locate an appropriate system-wide source of trusted certificates. If a system
50
+     * store cannot be located or read, the bundled Java cacerts list will be use. If that also
51
+     * fails, {@code null} will be returned.
52
+     *
53
+     * @return The best available KeyStore to use, or {@code null} if no working store was found.
54
+     */
55
+    @Nullable
56
+    public KeyStore getKeyStore() {
57
+        try {
58
+            final String osName = System.getProperty("os.name");
59
+            if (osName.startsWith("Mac OS")) {
60
+                return getMacKeyStore();
61
+            } else if (osName.startsWith("Windows")) {
62
+                return getWindowsKeyStore();
63
+            } else {
64
+                return getLinuxKeyStore();
65
+            }
66
+        } catch (IOException | GeneralSecurityException ex1) {
67
+            // Couldn't load a system KeyStore, try to load the Java one.
68
+            try {
69
+                return getJavaKeyStore();
70
+            } catch (IOException | GeneralSecurityException ex2) {
71
+                // Couldn't even load the Java one...
72
+                return null;
73
+            }
74
+        }
75
+    }
76
+
77
+    /**
78
+     * Returns the root (system-wide) keystore on Windows operating systems.
79
+     */
80
+    private KeyStore getWindowsKeyStore() throws NoSuchProviderException, KeyStoreException,
81
+            CertificateException, NoSuchAlgorithmException, IOException {
82
+        final KeyStore keyStore = KeyStore.getInstance(WINDOWS_TYPE, WINDOWS_PROVIDER);
83
+        keyStore.load(null, null);
84
+        return keyStore;
85
+    }
86
+
87
+    /**
88
+     * Returns the root (system-wide) keystore on Mac operating systems.
89
+     */
90
+    private KeyStore getMacKeyStore() throws NoSuchProviderException, KeyStoreException,
91
+            CertificateException, NoSuchAlgorithmException, IOException {
92
+        final KeyStore keyStore = KeyStore.getInstance(MAC_TYPE, MAC_PROVIDER);
93
+        keyStore.load(null, null);
94
+        return keyStore;
95
+    }
96
+
97
+    /**
98
+     * Returns a KeyStore that reads system-wide trusted certificates on Linux. These are found in
99
+     * {@code /etc/ssl/certs}, and the Java version is provided by the {@code ca-certificates-java}
100
+     * package.
101
+     */
102
+    private KeyStore getLinuxKeyStore() throws IOException, KeyStoreException,
103
+            CertificateException, NoSuchAlgorithmException {
104
+        try (FileInputStream is = new FileInputStream(LINUX_CACERTS_PATH)) {
105
+            final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
106
+            keystore.load(is, null);
107
+            return keystore;
108
+        }
109
+    }
110
+
111
+    /**
112
+     * Returns a KeyStore that reads from the {@code cacerts} file bundled with the in-use
113
+     * Java Runtime Environment. This is less preferable to using a system-provided KeyStore,
114
+     * as it will not include any user/admin-defined certificates.
115
+     */
116
+    private KeyStore getJavaKeyStore() throws IOException, KeyStoreException,
117
+            CertificateException, NoSuchAlgorithmException {
118
+        final String filename = System.getProperty("java.home")
119
+                + File.separatorChar + "lib"
120
+                + File.separatorChar + "security"
121
+                + File .separatorChar + "cacerts";
122
+        try (FileInputStream is = new FileInputStream(filename)) {
123
+            final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
124
+            keystore.load(is, null);
125
+            return keystore;
126
+        }
127
+    }
128
+
129
+}

Loading…
Cancel
Save