Search in sources :

Example 1 with TrustedUpdate

use of net.i2p.crypto.TrustedUpdate in project i2p.i2p by i2p.

the class PluginUpdateRunner method processSUD.

/**
 *  @since 0.9.15
 *  @return success
 */
private void processSUD(File f, File appDir, String url) {
    TrustedUpdate up = new TrustedUpdate(_context);
    File to = new File(_context.getTempDir(), "tmp" + _context.random().nextInt() + ZIP);
    // extract to a zip file whether the sig is good or not, so we can get the properties file
    String err = up.migrateFile(f, to);
    if (err != null) {
        statusDone("<b>" + err + ' ' + _t("from {0}", url) + " </b>");
        f.delete();
        to.delete();
        return;
    }
    Properties props = getPluginConfig(f, to, url);
    if (props == null)
        return;
    // ok, now we check sigs and deal with a bad sig
    String pubkey = props.getProperty("key");
    String signer = DataHelper.stripHTML(props.getProperty("signer"));
    if (pubkey == null || signer == null || pubkey.length() != 172 || signer.length() <= 0) {
        f.delete();
        to.delete();
        // updateStatus("<b>" + "Plugin contains an invalid key" + ' ' + pubkey + ' ' + signer + "</b>");
        statusDone("<b>" + _t("Plugin from {0} contains an invalid key", url) + "</b>");
        return;
    }
    SigningPublicKey spk;
    try {
        spk = new SigningPublicKey(pubkey);
    } catch (DataFormatException dfe) {
        f.delete();
        to.delete();
        statusDone("<b>" + _t("Plugin from {0} contains an invalid key", url) + "</b>");
        return;
    }
    // add all existing plugin keys, so any conflicts with existing keys
    // will be discovered and rejected
    Map<String, String> existingKeys = PluginStarter.getPluginKeys(_context);
    for (Map.Entry<String, String> e : existingKeys.entrySet()) {
        // ignore dups/bad keys
        up.addKey(e.getKey(), e.getValue());
    }
    // add all trusted plugin keys, so any conflicts with trusted keys
    // will be discovered and rejected
    Map<String, String> trustedKeys = TrustedPluginKeys.getKeys();
    for (Map.Entry<String, String> e : trustedKeys.entrySet()) {
        // ignore dups/bad keys
        up.addKey(e.getKey(), e.getValue());
    }
    if (up.haveKey(pubkey)) {
        // the key is already in the TrustedUpdate keyring
        // verify the sig and verify that it is signed by the signer in the plugin.config file
        // Allow "" as the previously-known signer
        boolean ok = up.verify(f, spk);
        String signingKeyName = up.getKeys().get(spk);
        if ((!ok) || !(signer.equals(signingKeyName) || "".equals(signingKeyName))) {
            f.delete();
            to.delete();
            if (signingKeyName == null)
                _log.error("Failed to verify plugin signature, corrupt plugin or bad signature, signed by: " + signer);
            else
                _log.error("Plugin signer \"" + signer + "\" does not match existing signer in plugin.config file \"" + signingKeyName + "\"");
            statusDone("<b>" + _t("Plugin signature verification of {0} failed", url) + "</b>");
            return;
        }
    } else if (_context.getBooleanProperty(PROP_ALLOW_NEW_KEYS)) {
        // add to keyring...
        if (!up.addKey(pubkey, signer)) {
            // bad or duplicate key
            f.delete();
            to.delete();
            _log.error("Bad key or key mismatch - Failed to add plugin key \"" + pubkey + "\" for plugin signer \"" + signer + "\"");
            statusDone("<b>" + _t("Plugin signature verification of {0} failed", url) + "</b>");
            return;
        }
        // ...and try the verify again
        // verify the sig and verify that it is signed by the signer in the plugin.config file
        String signingKeyName = up.verifyAndGetSigner(f);
        if (!signer.equals(signingKeyName)) {
            f.delete();
            to.delete();
            if (signingKeyName == null)
                _log.error("Failed to verify plugin signature, corrupt plugin or bad signature, signed by: " + signer);
            else
                // shouldn't happen
                _log.error("Plugin signer \"" + signer + "\" does not match new signer in plugin.config file \"" + signingKeyName + "\"");
            statusDone("<b>" + _t("Plugin signature verification of {0} failed", url) + "</b>");
            return;
        }
    } else {
        // unknown key
        f.delete();
        to.delete();
        _log.error("Untrusted plugin key \"" + pubkey + "\" for plugin signer \"" + signer + "\"");
        // don't display signer, we're really checking the key not the signer name
        statusDone("<b>" + _t("Plugin not installed - signer is untrusted") + "</b>");
        return;
    }
    String sudVersion = TrustedUpdate.getVersionString(f);
    f.delete();
    processFinal(to, appDir, url, props, sudVersion, pubkey, signer);
}
Also used : SigningPublicKey(net.i2p.data.SigningPublicKey) DataFormatException(net.i2p.data.DataFormatException) TrustedUpdate(net.i2p.crypto.TrustedUpdate) OrderedProperties(net.i2p.util.OrderedProperties) Properties(java.util.Properties) SecureFile(net.i2p.util.SecureFile) SU3File(net.i2p.crypto.SU3File) File(java.io.File) Map(java.util.Map)

Example 2 with TrustedUpdate

use of net.i2p.crypto.TrustedUpdate in project i2p.i2p by i2p.

the class ConfigUpdateHandler method processForm.

@Override
protected void processForm() {
    if (_action == null)
        return;
    if (_action.equals(_t("Check for updates"))) {
        ConsoleUpdateManager mgr = UpdateHandler.updateManager(_context);
        if (mgr == null) {
            addFormError("Update manager not registered, cannot check");
            return;
        }
        if (mgr.isUpdateInProgress() || mgr.isCheckInProgress()) {
            addFormError(_t("Update or check already in progress"));
            return;
        }
        boolean shouldProxy = _context.getProperty(PROP_SHOULD_PROXY_NEWS, DEFAULT_SHOULD_PROXY_NEWS);
        String proxyHost = _context.getProperty(PROP_PROXY_HOST, DEFAULT_PROXY_HOST);
        int proxyPort = proxyPort(_context);
        if (shouldProxy && proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT && proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) && _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) {
            addFormError(_t("HTTP client proxy tunnel must be running"));
            return;
        }
        boolean a1 = mgr.checkAvailable(NEWS, 40 * 1000) != null;
        boolean a2 = false;
        boolean a3 = false;
        if ((!a1) && _updateDevSU3 && _devSU3URL != null && _devSU3URL.length() > 0)
            a2 = mgr.checkAvailable(ROUTER_DEV_SU3, 40 * 1000) != null;
        if ((!a2) && _updateUnsigned && _zipURL != null && _zipURL.length() > 0)
            a3 = mgr.checkAvailable(ROUTER_UNSIGNED, 40 * 1000) != null;
        if (a1 || a2 || a3) {
            if ((_updatePolicy == null) || (!_updatePolicy.equals("notify")))
                addFormNotice(_t("Update available, attempting to download now"));
            else
                addFormNotice(_t("Update available, click button on left to download"));
            // So that update() will post a status to the summary bar before we reload
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
            }
        } else
            addFormNotice(_t("No update available"));
        return;
    }
    if (!_action.equals(_t("Save")))
        return;
    Map<String, String> changes = new HashMap<String, String>();
    if ((_newsURL != null) && (_newsURL.length() > 0)) {
        if (_newsURL.startsWith("https"))
            _newsThroughProxy = false;
        String oldURL = ConfigUpdateHelper.getNewsURL(_context);
        if ((oldURL == null) || (!_newsURL.equals(oldURL))) {
            if (isAdvanced()) {
                changes.put(PROP_NEWS_URL, _newsURL);
                // this invalidates the news
                changes.put(NewsHelper.PROP_LAST_CHECKED, "0");
                addFormNotice(_t("Updating news URL to {0}", _newsURL));
            } else {
                addFormError("Changing news URL disabled");
            }
        }
    }
    if (_proxyHost != null && _proxyHost.length() > 0 && !_proxyHost.equals(_t("internal"))) {
        String oldHost = _context.router().getConfigSetting(PROP_PROXY_HOST);
        if ((oldHost == null) || (!_proxyHost.equals(oldHost))) {
            changes.put(PROP_PROXY_HOST, _proxyHost);
            addFormNotice(_t("Updating proxy host to {0}", _proxyHost));
        }
    }
    if (_proxyPort != null && _proxyPort.length() > 0 && !_proxyPort.equals(_t("internal"))) {
        String oldPort = _context.router().getConfigSetting(PROP_PROXY_PORT);
        if ((oldPort == null) || (!_proxyPort.equals(oldPort))) {
            changes.put(PROP_PROXY_PORT, _proxyPort);
            addFormNotice(_t("Updating proxy port to {0}", _proxyPort));
        }
    }
    if (isAdvanced()) {
        changes.put(PROP_SHOULD_PROXY_NEWS, Boolean.toString(_newsThroughProxy));
        if (!_context.getBooleanProperty(PROP_UPDATE_DISABLED)) {
            changes.put(PROP_SHOULD_PROXY, Boolean.toString(_updateThroughProxy));
            changes.put(PROP_UPDATE_UNSIGNED, Boolean.toString(_updateUnsigned));
            changes.put(PROP_UPDATE_DEV_SU3, Boolean.toString(_updateDevSU3));
        }
    }
    String oldFreqStr = _context.getProperty(PROP_REFRESH_FREQUENCY, DEFAULT_REFRESH_FREQUENCY);
    long oldFreq = DEFAULT_REFRESH_FREQ;
    try {
        oldFreq = Long.parseLong(oldFreqStr);
    } catch (NumberFormatException nfe) {
    }
    if (_refreshFrequency != oldFreq) {
        changes.put(PROP_REFRESH_FREQUENCY, "" + _refreshFrequency);
        addFormNoticeNoEscape(_t("Updating refresh frequency to {0}", _refreshFrequency <= 0 ? _t("Never") : DataHelper.formatDuration2(_refreshFrequency)));
    }
    if ((_updatePolicy != null) && (_updatePolicy.length() > 0)) {
        String oldPolicy = _context.router().getConfigSetting(PROP_UPDATE_POLICY);
        if ((oldPolicy == null) || (!_updatePolicy.equals(oldPolicy))) {
            changes.put(PROP_UPDATE_POLICY, _updatePolicy);
            addFormNotice(_t("Updating update policy to {0}", _updatePolicy));
        }
    }
    if ((_updateURL != null) && (_updateURL.length() > 0)) {
        _updateURL = _updateURL.replace("\r\n", ",").replace("\n", ",");
        String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
        if ((oldURL == null) || (!_updateURL.equals(oldURL))) {
            changes.put(PROP_UPDATE_URL, _updateURL);
            addFormNotice(_t("Updating update URLs."));
        }
    }
    if ((_trustedKeys != null) && (_trustedKeys.length() > 0)) {
        _trustedKeys = _trustedKeys.replace("\r\n", ",").replace("\n", ",");
        String oldKeys = new TrustedUpdate(_context).getTrustedKeysString();
        oldKeys = oldKeys.replace("\r\n", ",");
        if (!_trustedKeys.equals(oldKeys)) {
            // note that keys are not validated here and no console error message will be generated
            if (isAdvanced()) {
                changes.put(PROP_TRUSTED_KEYS, _trustedKeys);
                addFormNotice(_t("Updating trusted keys."));
            } else {
                addFormError("Changing trusted keys disabled");
            }
        }
    }
    if ((_zipURL != null) && (_zipURL.length() > 0)) {
        String oldURL = _context.router().getConfigSetting(PROP_ZIP_URL);
        if ((oldURL == null) || (!_zipURL.equals(oldURL))) {
            if (isAdvanced()) {
                changes.put(PROP_ZIP_URL, _zipURL);
                addFormNotice(_t("Updating unsigned update URL to {0}", _zipURL));
            } else {
                addFormError("Changing unsigned update URL disabled");
            }
        }
    }
    if ((_devSU3URL != null) && (_devSU3URL.length() > 0)) {
        String oldURL = _context.router().getConfigSetting(PROP_DEV_SU3_URL);
        if ((oldURL == null) || (!_devSU3URL.equals(oldURL))) {
            if (isAdvanced()) {
                changes.put(PROP_DEV_SU3_URL, _devSU3URL);
                addFormNotice(_t("Updating signed development build URL to {0}", _devSU3URL));
            } else {
                addFormError("Changing signed update URL disabled");
            }
        }
    }
    _context.router().saveConfig(changes, null);
}
Also used : HashMap(java.util.HashMap) ConsoleUpdateManager(net.i2p.router.update.ConsoleUpdateManager) TrustedUpdate(net.i2p.crypto.TrustedUpdate)

Example 3 with TrustedUpdate

use of net.i2p.crypto.TrustedUpdate in project i2p.i2p by i2p.

the class ConsoleUpdateManager method handleRouterFile.

/**
 *  Process sud, su2, or su3
 *  @return success
 *  @since 0.9.9
 */
private boolean handleRouterFile(URI uri, String actualVersion, File f, boolean isSU3) {
    String url = uri.toString();
    updateStatus("<b>" + _t("Update downloaded") + "</b>");
    File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
    String err;
    // Process the file
    if (isSU3) {
        SU3File up = new SU3File(_context, f);
        File temp = new File(_context.getTempDir(), "su3out-" + _context.random().nextLong() + ".zip");
        try {
            if (up.verifyAndMigrate(temp)) {
                String ver = up.getVersionString();
                int type = up.getContentType();
                if (ver == null || VersionComparator.comp(RouterVersion.VERSION, ver) >= 0)
                    err = "Old version " + ver;
                else if (type != SU3File.CONTENT_ROUTER)
                    err = "Bad su3 content type " + type;
                else if (!FileUtil.copy(temp, to, true, false))
                    err = "Failed copy to " + to;
                else
                    // success
                    err = null;
            } else {
                err = "Signature failed, signer " + DataHelper.stripHTML(up.getSignerString()) + ' ' + up.getSigType();
            }
        } catch (IOException ioe) {
            _log.error("SU3 extract error", ioe);
            err = DataHelper.stripHTML(ioe.toString());
        } finally {
            temp.delete();
        }
    } else {
        TrustedUpdate up = new TrustedUpdate(_context);
        err = up.migrateVerified(RouterVersion.VERSION, f, to);
    }
    // f.delete();
    if (err == null) {
        String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
        // So unsigned update handler doesn't overwrite unless newer.
        long modtime = _context.clock().now();
        _context.router().saveConfig(NewsHelper.PROP_LAST_UPDATE_TIME, Long.toString(modtime));
        if ("install".equals(policy)) {
            _log.log(Log.CRIT, "Update was downloaded and verified, restarting to install it");
            updateStatus("<b>" + _t("Update verified") + "</b><br>" + _t("Restarting"));
            restart();
        } else {
            _log.logAlways(Log.WARN, "Update was downloaded and verified, will be installed at next restart");
            // SummaryHelper will display restart info separately
            updateStatus("");
        }
    } else {
        _log.log(Log.CRIT, err + " from " + url);
        updateStatus("<b>" + err + ' ' + _t("from {0}", linkify(url)) + " </b>");
    }
    return err == null;
}
Also used : TrustedUpdate(net.i2p.crypto.TrustedUpdate) IOException(java.io.IOException) SU3File(net.i2p.crypto.SU3File) SU3File(net.i2p.crypto.SU3File) File(java.io.File)

Aggregations

TrustedUpdate (net.i2p.crypto.TrustedUpdate)3 File (java.io.File)2 SU3File (net.i2p.crypto.SU3File)2 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Properties (java.util.Properties)1 DataFormatException (net.i2p.data.DataFormatException)1 SigningPublicKey (net.i2p.data.SigningPublicKey)1 ConsoleUpdateManager (net.i2p.router.update.ConsoleUpdateManager)1 OrderedProperties (net.i2p.util.OrderedProperties)1 SecureFile (net.i2p.util.SecureFile)1