Index: trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 7342)
+++ trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 7343)
@@ -445,5 +445,5 @@
                 // Check for insecure certificates to remove.
                 // This is Windows-dependant code but it can't go to preStartupHook (need i18n) neither startupHook (need to be called before remote control)
-                ((PlatformHookWindows)Main.platform).removeInsecureCertificates();
+                PlatformHookWindows.removeInsecureCertificates();
             } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) {
                 error(e);
Index: trunk/src/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreference.java	(revision 7342)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreference.java	(revision 7343)
@@ -9,4 +9,10 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -15,6 +21,8 @@
 import javax.swing.BorderFactory;
 import javax.swing.Box;
+import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JLabel;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JSeparator;
@@ -31,4 +39,5 @@
 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.PlatformHookWindows;
 
 /**
@@ -61,6 +70,10 @@
     private JCheckBox enableRemoteControl;
     private JCheckBox enableHttpsSupport;
-    private JCheckBox loadInNewLayer = new JCheckBox(tr("Download objects to new layer"));
-    private JCheckBox alwaysAskUserConfirm = new JCheckBox(tr("Confirm all Remote Control actions manually"));
+
+    private JButton installCertificate;
+    private JButton uninstallCertificate;
+
+    private final JCheckBox loadInNewLayer = new JCheckBox(tr("Download objects to new layer"));
+    private final JCheckBox alwaysAskUserConfirm = new JCheckBox(tr("Confirm all Remote Control actions manually"));
 
     @Override
@@ -91,6 +104,63 @@
         remote.add(wrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 5));
 
-        enableHttpsSupport = new JCheckBox(tr("Enable HTTPS support"), RemoteControl.PROP_REMOTECONTROL_HTTPS_ENABLED.get());
+        boolean https = RemoteControl.PROP_REMOTECONTROL_HTTPS_ENABLED.get();
+
+        enableHttpsSupport = new JCheckBox(tr("Enable HTTPS support"), https);
         wrapper.add(enableHttpsSupport, GBC.eol().fill(GBC.HORIZONTAL));
+
+        // Certificate installation only available on Windows for now, see #10033
+        if (Main.isPlatformWindows()) {
+            installCertificate = new JButton(tr("Install..."));
+            uninstallCertificate = new JButton(tr("Uninstall..."));
+            installCertificate.setToolTipText(tr("Install JOSM localhost certificate to system/browser root keystores"));
+            uninstallCertificate.setToolTipText(tr("Uninstall JOSM localhost certificate from system/browser root keystores"));
+            wrapper.add(new JLabel(tr("Certificate:")), GBC.std().insets(15, 5, 0, 0));
+            wrapper.add(installCertificate, GBC.std().insets(5, 5, 0, 0));
+            wrapper.add(uninstallCertificate, GBC.eol().insets(5, 5, 0, 0));
+            enableHttpsSupport.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    installCertificate.setEnabled(enableHttpsSupport.isSelected());
+                }
+            });
+            installCertificate.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    try {
+                        boolean changed = RemoteControlHttpsServer.setupPlatform(
+                                RemoteControlHttpsServer.loadJosmKeystore());
+                        String msg = changed ?
+                                tr("Certificate has been successfully installed.") :
+                                tr("Certificate is already installed. Nothing to do.");
+                        Main.info(msg);
+                        JOptionPane.showMessageDialog(wrapper, msg);
+                    } catch (IOException | GeneralSecurityException ex) {
+                        Main.error(ex);
+                    }
+                }
+            });
+            uninstallCertificate.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    try {
+                        String msg;
+                        KeyStore ks = PlatformHookWindows.getRootKeystore();
+                        if (ks.containsAlias(RemoteControlHttpsServer.ENTRY_ALIAS)) {
+                            Main.info(tr("Removing certificate {0} from root keystore.", RemoteControlHttpsServer.ENTRY_ALIAS));
+                            ks.deleteEntry(RemoteControlHttpsServer.ENTRY_ALIAS);
+                            msg = tr("Certificate has been successfully uninstalled.");
+                        } else {
+                            msg = tr("Certificate is not installed. Nothing to do.");
+                        }
+                        Main.info(msg);
+                        JOptionPane.showMessageDialog(wrapper, msg);
+                    } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException ex) {
+                        Main.error(ex);
+                    }
+                }
+            });
+            installCertificate.setEnabled(https);
+        }
+
         wrapper.add(new JSeparator(), GBC.eop().fill(GBC.HORIZONTAL).insets(15, 5, 15, 5));
 
@@ -116,4 +186,10 @@
                 // 'setEnabled(false)' does not work for JLabel with html text, so do it manually
                 // FIXME: use QuadStateCheckBox to make checkboxes unset when disabled
+                if (installCertificate != null && uninstallCertificate != null) {
+                    // Install certificate button is enabled if HTTPS is also enabled
+                    installCertificate.setEnabled(enableRemoteControl.isSelected() && enableHttpsSupport.isSelected());
+                    // Uninstall certificate button is always enabled
+                    uninstallCertificate.setEnabled(true);
+                }
             }
         };
Index: trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpsServer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpsServer.java	(revision 7342)
+++ trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpsServer.java	(revision 7343)
@@ -21,8 +21,10 @@
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
@@ -91,5 +93,5 @@
      * @since 7335
      */
-    public StringProperty KEYSTORE_PASSWORD = new StringProperty("remotecontrol.https.keystore.password", "");
+    public static final StringProperty KEYSTORE_PASSWORD = new StringProperty("remotecontrol.https.keystore.password", "");
 
     /**
@@ -97,5 +99,11 @@
      * @since 7335
      */
-    public StringProperty KEYENTRY_PASSWORD = new StringProperty("remotecontrol.https.keyentry.password", "");
+    public static final StringProperty KEYENTRY_PASSWORD = new StringProperty("remotecontrol.https.keyentry.password", "");
+
+    /**
+     * Unique alias used to store JOSM localhost entry, both in JOSM keystore and system/browser keystores.
+     * @since 7343
+     */
+    public static final String ENTRY_ALIAS = "josm_localhost";
 
     /**
@@ -194,79 +202,117 @@
     }
 
+    /**
+     * Setup the JOSM internal keystore, used to store HTTPS certificate and private key.
+     * @return Path to the (initialized) JOSM keystore
+     * @throws IOException if an I/O error occurs
+     * @throws GeneralSecurityException if a security error occurs
+     * @since 7343
+     */
+    public static Path setupJosmKeystore() throws IOException, GeneralSecurityException {
+
+        char[] storePassword = KEYSTORE_PASSWORD.get().toCharArray();
+        char[] entryPassword = KEYENTRY_PASSWORD.get().toCharArray();
+
+        Path dir = Paths.get(RemoteControl.getRemoteControlDir());
+        Path path = dir.resolve(KEYSTORE_FILENAME);
+        Files.createDirectories(dir);
+
+        if (!Files.exists(path)) {
+            Main.debug("No keystore found, creating a new one");
+
+            // Create new keystore like previous one generated with JDK keytool as follows:
+            // keytool -genkeypair -storepass josm_ssl -keypass josm_ssl -alias josm_localhost -dname "CN=localhost, OU=JOSM, O=OpenStreetMap"
+            // -ext san=ip:127.0.0.1 -keyalg RSA -validity 1825
+
+            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+            generator.initialize(2048);
+            KeyPair pair = generator.generateKeyPair();
+
+            X509Certificate cert = generateCertificate("CN=localhost, OU=JOSM, O=OpenStreetMap", pair, 1825, "SHA256withRSA",
+                    "dns:localhost,ip:127.0.0.1,ip:::1,uri:https://127.0.0.1:"+HTTPS_PORT+",uri:https://::1:"+HTTPS_PORT);
+
+            KeyStore ks = KeyStore.getInstance("JKS");
+            ks.load(null, null);
+
+            // Generate new passwords. See https://stackoverflow.com/a/41156/2257172
+            SecureRandom random = new SecureRandom();
+            KEYSTORE_PASSWORD.put(new BigInteger(130, random).toString(32));
+            KEYENTRY_PASSWORD.put(new BigInteger(130, random).toString(32));
+
+            storePassword = KEYSTORE_PASSWORD.get().toCharArray();
+            entryPassword = KEYENTRY_PASSWORD.get().toCharArray();
+
+            ks.setKeyEntry(ENTRY_ALIAS, pair.getPrivate(), entryPassword, new Certificate[]{cert});
+            ks.store(Files.newOutputStream(path, StandardOpenOption.CREATE), storePassword);
+        }
+        return path;
+    }
+
+    /**
+     * Loads the JOSM keystore.
+     * @return the (initialized) JOSM keystore
+     * @throws IOException if an I/O error occurs
+     * @throws GeneralSecurityException if a security error occurs
+     * @since 7343
+     */
+    public static KeyStore loadJosmKeystore() throws IOException, GeneralSecurityException {
+        try (InputStream in = Files.newInputStream(setupJosmKeystore())) {
+            KeyStore ks = KeyStore.getInstance("JKS");
+            ks.load(in, KEYSTORE_PASSWORD.get().toCharArray());
+
+            if (Main.isDebugEnabled()) {
+                for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements();) {
+                    Main.debug("Alias in JOSM keystore: "+aliases.nextElement());
+                }
+            }
+            return ks;
+        }
+    }
+
     private void initialize() {
         if (!initOK) {
             try {
-                char[] storePassword = KEYSTORE_PASSWORD.get().toCharArray();
-                char[] entryPassword = KEYENTRY_PASSWORD.get().toCharArray();
-
-                Path dir = Paths.get(RemoteControl.getRemoteControlDir());
-                Path path = dir.resolve(KEYSTORE_FILENAME);
-                Files.createDirectories(dir);
-
-                if (!Files.exists(path)) {
-                    Main.debug("No keystore found, creating a new one");
-
-                    // Create new keystore like previous one generated with JDK keytool as follows:
-                    // keytool -genkeypair -storepass josm_ssl -keypass josm_ssl -alias josm_localhost -dname "CN=localhost, OU=JOSM, O=OpenStreetMap"
-                    // -ext san=ip:127.0.0.1 -keyalg RSA -validity 1825
-
-                    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
-                    generator.initialize(2048);
-                    KeyPair pair = generator.generateKeyPair();
-
-                    X509Certificate cert = generateCertificate("CN=localhost, OU=JOSM, O=OpenStreetMap", pair, 1825, "SHA256withRSA",
-                            "dns:localhost,ip:127.0.0.1,ip:::1,uri:https://127.0.0.1:"+HTTPS_PORT+",uri:https://::1:"+HTTPS_PORT);
-
-                    KeyStore ks = KeyStore.getInstance("JKS");
-                    ks.load(null, null);
-
-                    // Generate new passwords. See https://stackoverflow.com/a/41156/2257172
-                    SecureRandom random = new SecureRandom();
-                    KEYSTORE_PASSWORD.put(new BigInteger(130, random).toString(32));
-                    KEYENTRY_PASSWORD.put(new BigInteger(130, random).toString(32));
-
-                    storePassword = KEYSTORE_PASSWORD.get().toCharArray();
-                    entryPassword = KEYENTRY_PASSWORD.get().toCharArray();
-
-                    ks.setKeyEntry("josm_localhost", pair.getPrivate(), entryPassword, new Certificate[]{cert});
-                    ks.store(Files.newOutputStream(path, StandardOpenOption.CREATE), storePassword);
-                }
-
-                try (InputStream in = Files.newInputStream(path)) {
-                    // Load keystore
-                    KeyStore ks = KeyStore.getInstance("JKS");
-                    ks.load(in, storePassword);
-
-                    if (Main.isDebugEnabled()) {
-                        for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements();) {
-                            Main.debug("Alias in keystore: "+aliases.nextElement());
-                        }
-                    }
-
-                    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
-                    kmf.init(ks, entryPassword);
-
-                    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
-                    tmf.init(ks);
-
-                    sslContext = SSLContext.getInstance("TLS");
-                    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
-
-                    if (Main.isTraceEnabled()) {
-                        Main.trace("SSL Context protocol: " + sslContext.getProtocol());
-                        Main.trace("SSL Context provider: " + sslContext.getProvider());
-                    }
-
-                    Enumeration<String> aliases = ks.aliases();
-                    if (aliases.hasMoreElements()) {
-                        Main.platform.setupHttpsCertificate(new KeyStore.TrustedCertificateEntry(ks.getCertificate(aliases.nextElement())));
-                    }
-
-                    initOK = true;
-                }
+                KeyStore ks = loadJosmKeystore();
+
+                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+                kmf.init(ks, KEYENTRY_PASSWORD.get().toCharArray());
+
+                TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+                tmf.init(ks);
+
+                sslContext = SSLContext.getInstance("TLS");
+                sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+                if (Main.isTraceEnabled()) {
+                    Main.trace("SSL Context protocol: " + sslContext.getProtocol());
+                    Main.trace("SSL Context provider: " + sslContext.getProvider());
+                }
+
+                setupPlatform(ks);
+
+                initOK = true;
             } catch (IOException | GeneralSecurityException e) {
                 Main.error(e);
             }
         }
+    }
+
+    /**
+     * Setup the platform-dependant certificate stuff.
+     * @param josmKs The JOSM keystore, containing localhost certificate and private key.
+     * @return {@code true} if something has changed as a result of the call (certificate installation, etc.)
+     * @throws KeyStoreException if the keystore has not been initialized (loaded)
+     * @throws NoSuchAlgorithmException in case of error
+     * @throws CertificateException in case of error
+     * @throws IOException in case of error
+     * @since 7343
+     */
+    public static boolean setupPlatform(KeyStore josmKs) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
+        Enumeration<String> aliases = josmKs.aliases();
+        if (aliases.hasMoreElements()) {
+            return Main.platform.setupHttpsCertificate(ENTRY_ALIAS,
+                    new KeyStore.TrustedCertificateEntry(josmKs.getCertificate(aliases.nextElement())));
+        }
+        return false;
     }
 
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHook.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 7342)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 7343)
@@ -109,12 +109,14 @@
     /**
      * Setup system keystore to add JOSM HTTPS certificate (for remote control).
+     * @param entryAlias The entry alias to use
      * @param trustedCert the JOSM certificate for localhost
+     * @return {@code true} if something has changed as a result of the call (certificate installation, etc.)
      * @throws KeyStoreException in case of error
      * @throws IOException in case of error
      * @throws CertificateException in case of error
      * @throws NoSuchAlgorithmException in case of error
-     * @since 7206
+     * @since 7343
      */
-    public void setupHttpsCertificate(KeyStore.TrustedCertificateEntry trustedCert)
+    public boolean setupHttpsCertificate(String entryAlias, KeyStore.TrustedCertificateEntry trustedCert)
             throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException;
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 7342)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 7343)
@@ -358,7 +358,8 @@
 
     @Override
-    public void setupHttpsCertificate(KeyStore.TrustedCertificateEntry trustedCert)
+    public boolean setupHttpsCertificate(String entryAlias, KeyStore.TrustedCertificateEntry trustedCert)
             throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
         // TODO setup HTTPS certificate on Unix systems
+        return false;
     }
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 7342)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 7343)
@@ -181,6 +181,7 @@
      * @throws IOException if there is an I/O or format problem with the keystore data, if a password is required but not given
      * @throws KeyStoreException if no Provider supports a KeyStore implementation for the type "Windows-ROOT"
+     * @since 7343
      */
-    private KeyStore getWindowsKeystore() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
+    public static KeyStore getRootKeystore() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
         KeyStore ks = KeyStore.getInstance(WINDOWS_ROOT);
         ks.load(null, null);
@@ -196,5 +197,5 @@
      * @since 7335
      */
-    public void removeInsecureCertificates() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
+    public static void removeInsecureCertificates() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
         // We offered before a public private key we need now to remove from Windows PCs as it might be a huge security risk (see #10230)
         PublicKey insecurePubKey = null;
@@ -205,5 +206,5 @@
             return;
         }
-        KeyStore ks = getWindowsKeystore();
+        KeyStore ks = getRootKeystore();
         Enumeration<String> en = ks.aliases();
         Collection<String> insecureCertificates = new ArrayList<>();
@@ -249,21 +250,18 @@
 
     @Override
-    public void setupHttpsCertificate(KeyStore.TrustedCertificateEntry trustedCert)
+    public boolean setupHttpsCertificate(String entryAlias, KeyStore.TrustedCertificateEntry trustedCert)
             throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
-        KeyStore ks = getWindowsKeystore();
-        Enumeration<String> en = ks.aliases();
-
-        while (en.hasMoreElements()) {
-            String alias = en.nextElement();
-            // Look for certificate to install
-            if (ks.getCertificate(alias).equals(trustedCert.getTrustedCertificate())) {
-                // JOSM certificate found, return
-                Main.debug("JOSM certificate found: "+alias);
-                return;
-            }
+        KeyStore ks = getRootKeystore();
+        // Look for certificate to install
+        String alias = ks.getCertificateAlias(trustedCert.getTrustedCertificate());
+        if (alias != null) {
+            // JOSM certificate found, return
+            Main.debug(tr("JOSM localhost certificate found in {0} keystore: {1}", WINDOWS_ROOT, alias));
+            return false;
         }
         // JOSM certificate not found, install it to Windows-ROOT keystore, used by IE, Chrome and Safari, but not by Firefox
         Main.info(tr("Adding JOSM localhost certificate to {0} keystore", WINDOWS_ROOT));
-        ks.setEntry("josm_localhost", trustedCert, null);
+        ks.setEntry(entryAlias, trustedCert, null);
+        return true;
     }
 }
