source: josm/trunk/src/org/openstreetmap/josm/io/CertificateAmendment.java@ 11100

Last change on this file since 11100 was 10235, checked in by Don-vip, 8 years ago

sonar - squid:S00112 - Generic exceptions should never be thrown

  • Property svn:eol-style set to native
File size: 5.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.ByteArrayInputStream;
7import java.io.File;
8import java.io.IOException;
9import java.io.InputStream;
10import java.nio.file.Files;
11import java.nio.file.Path;
12import java.nio.file.Paths;
13import java.security.GeneralSecurityException;
14import java.security.InvalidAlgorithmParameterException;
15import java.security.KeyStore;
16import java.security.KeyStoreException;
17import java.security.MessageDigest;
18import java.security.cert.CertificateFactory;
19import java.security.cert.PKIXParameters;
20import java.security.cert.TrustAnchor;
21import java.security.cert.X509Certificate;
22import java.util.Objects;
23
24import javax.net.ssl.SSLContext;
25import javax.net.ssl.TrustManagerFactory;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.tools.Utils;
29
30/**
31 * Class to add missing root certificates to the list of trusted certificates
32 * for TLS connections.
33 *
34 * The added certificates are deemed trustworthy by the main web browsers and
35 * operating systems, but not included in some distributions of Java.
36 *
37 * The certificates are added in-memory at each start, nothing is written to disk.
38 * @since 9995
39 */
40public final class CertificateAmendment {
41
42 private static final String[] CERT_AMEND = {
43 "resource://data/security/DST_Root_CA_X3.pem",
44 "resource://data/security/StartCom_Certification_Authority.pem"
45 };
46
47 private static final String[] SHA_HASHES = {
48 "0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739",
49 "c766a9bef2d4071c863a31aa4920e813b2d198608cb7b7cfe21143b836df09ea"
50 };
51
52 private CertificateAmendment() {
53 // Hide default constructor for utility classes
54 }
55
56 /**
57 * Add missing root certificates to the list of trusted certificates for TLS connections.
58 * @throws IOException if an I/O error occurs
59 * @throws GeneralSecurityException if a security error occurs
60 */
61 public static void addMissingCertificates() throws IOException, GeneralSecurityException {
62 if (!Main.pref.getBoolean("tls.add-missing-certificates", true))
63 return;
64 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
65 Path cacertsPath = Paths.get(System.getProperty("java.home"), "lib", "security", "cacerts");
66 try (InputStream is = Files.newInputStream(cacertsPath)) {
67 keyStore.load(is, "changeit".toCharArray());
68 }
69
70 CertificateFactory cf = CertificateFactory.getInstance("X.509");
71 boolean certificateAdded = false;
72 for (int i = 0; i < CERT_AMEND.length; i++) {
73 try (CachedFile certCF = new CachedFile(CERT_AMEND[i])) {
74 byte[] certBytes = certCF.getByteContent();
75 ByteArrayInputStream certIS = new ByteArrayInputStream(certBytes);
76 X509Certificate cert = (X509Certificate) cf.generateCertificate(certIS);
77 MessageDigest md = MessageDigest.getInstance("SHA-256");
78 String sha1 = Utils.toHexString(md.digest(cert.getEncoded()));
79 if (!SHA_HASHES[i].equals(sha1)) {
80 throw new IllegalStateException(
81 tr("Error adding certificate {0} - certificate fingerprint mismatch. Expected {1}, was {2}",
82 CERT_AMEND[i],
83 SHA_HASHES[i],
84 sha1
85 ));
86 }
87 if (certificateIsMissing(keyStore, cert)) {
88 if (Main.isDebugEnabled()) {
89 Main.debug(tr("Adding certificate for TLS connections: {0}", cert.getSubjectX500Principal().getName()));
90 }
91 String alias = "josm:" + new File(CERT_AMEND[i]).getName();
92 keyStore.setCertificateEntry(alias, cert);
93 certificateAdded = true;
94 }
95 }
96 }
97
98 if (certificateAdded) {
99 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
100 tmf.init(keyStore);
101 SSLContext sslContext = SSLContext.getInstance("TLS");
102 sslContext.init(null, tmf.getTrustManagers(), null);
103 SSLContext.setDefault(sslContext);
104 }
105 }
106
107 /**
108 * Check if the certificate is missing and needs to be added to the keystore.
109 * @param keyStore the keystore
110 * @param crt the certificate
111 * @return true, if the certificate is not contained in the keystore
112 * @throws InvalidAlgorithmParameterException if the keystore does not contain at least one trusted certificate entry
113 * @throws KeyStoreException if the keystore has not been initialized
114 */
115 private static boolean certificateIsMissing(KeyStore keyStore, X509Certificate crt)
116 throws KeyStoreException, InvalidAlgorithmParameterException {
117 PKIXParameters params = new PKIXParameters(keyStore);
118 String id = crt.getSubjectX500Principal().getName();
119 for (TrustAnchor ta : params.getTrustAnchors()) {
120 X509Certificate cert = ta.getTrustedCert();
121 if (Objects.equals(id, cert.getSubjectX500Principal().getName()))
122 return false;
123 }
124 return true;
125 }
126}
Note: See TracBrowser for help on using the repository browser.