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

Last change on this file since 11096 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
RevLine 
[9995]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;
[10235]13import java.security.GeneralSecurityException;
[9995]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.
[9997]38 * @since 9995
[9995]39 */
[9997]40public final class CertificateAmendment {
[9995]41
[9997]42 private static final String[] CERT_AMEND = {
[9995]43 "resource://data/security/DST_Root_CA_X3.pem",
[10088]44 "resource://data/security/StartCom_Certification_Authority.pem"
[9995]45 };
[9997]46
47 private static final String[] SHA_HASHES = {
[10083]48 "0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739",
[10088]49 "c766a9bef2d4071c863a31aa4920e813b2d198608cb7b7cfe21143b836df09ea"
[9995]50 };
51
[9997]52 private CertificateAmendment() {
53 // Hide default constructor for utility classes
54 }
55
[9995]56 /**
57 * Add missing root certificates to the list of trusted certificates for TLS connections.
58 * @throws IOException if an I/O error occurs
[10235]59 * @throws GeneralSecurityException if a security error occurs
[9995]60 */
[10235]61 public static void addMissingCertificates() throws IOException, GeneralSecurityException {
[9995]62 if (!Main.pref.getBoolean("tls.add-missing-certificates", true))
63 return;
[10235]64 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
[9995]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
[10235]70 CertificateFactory cf = CertificateFactory.getInstance("X.509");
[9995]71 boolean certificateAdded = false;
72 for (int i = 0; i < CERT_AMEND.length; i++) {
[10235]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);
[10083]77 MessageDigest md = MessageDigest.getInstance("SHA-256");
78 String sha1 = Utils.toHexString(md.digest(cert.getEncoded()));
79 if (!SHA_HASHES[i].equals(sha1)) {
[10235]80 throw new IllegalStateException(
81 tr("Error adding certificate {0} - certificate fingerprint mismatch. Expected {1}, was {2}",
[10083]82 CERT_AMEND[i],
83 SHA_HASHES[i],
84 sha1
85 ));
86 }
[10235]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();
[9995]92 keyStore.setCertificateEntry(alias, cert);
[10235]93 certificateAdded = true;
[9995]94 }
95 }
96 }
97
98 if (certificateAdded) {
[10235]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);
[9995]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
[10235]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
[9995]114 */
[10235]115 private static boolean certificateIsMissing(KeyStore keyStore, X509Certificate crt)
116 throws KeyStoreException, InvalidAlgorithmParameterException {
117 PKIXParameters params = new PKIXParameters(keyStore);
[9997]118 String id = crt.getSubjectX500Principal().getName();
[9995]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.