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);
}
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);
}
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;
}
Aggregations