Changes in / [a1c8e3e:6bb1505d]


Ignore:
Files:
20 added
11 deleted
40 edited

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java

    ra1c8e3e r6bb1505d  
    194194                _uhandler = new UpdateHandler(_context, _umgr, SnarkManager.this);
    195195                _umgr.register(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT, 10);
     196                _umgr.register(_uhandler, UpdateType.ROUTER_SIGNED_SU3, UpdateMethod.TORRENT, 10);
    196197                _log.warn("Registering with update manager");
    197198            } else {
     
    211212            //_uhandler.shutdown();
    212213            _umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT);
     214            _umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED_SU3, UpdateMethod.TORRENT);
    213215        }
    214216        _running = false;
  • apps/i2psnark/java/src/org/klomp/snark/UpdateHandler.java

    ra1c8e3e r6bb1505d  
    4343    public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
    4444                             String id, String newVersion, long maxTime) {
    45         if (type != UpdateType.ROUTER_SIGNED ||
     45        if ((type != UpdateType.ROUTER_SIGNED && type != UpdateType.ROUTER_SIGNED_SU3) ||
    4646            method != UpdateMethod.TORRENT || updateSources.isEmpty())
    4747            return null;
    48         UpdateRunner update = new UpdateRunner(_context, _umgr, _smgr, updateSources, newVersion);
     48        UpdateRunner update = new UpdateRunner(_context, _umgr, _smgr, type, updateSources, newVersion);
    4949        _umgr.notifyProgress(update, "<b>" + _smgr.util().getString("Updating") + "</b>");
    5050        return update;
  • apps/i2psnark/java/src/org/klomp/snark/UpdateRunner.java

    ra1c8e3e r6bb1505d  
    2323    private final UpdateManager _umgr;
    2424    private final SnarkManager _smgr;
     25    private final UpdateType _type;
    2526    private final List<URI> _urls;
    2627    private volatile boolean _isRunning;
     
    3738
    3839    public UpdateRunner(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr,
    39                         List<URI> uris, String newVersion) {
     40                        UpdateType type, List<URI> uris, String newVersion) {
    4041        _context = ctx;
    4142        _log = ctx.logManager().getLog(getClass());
    4243        _umgr = umgr;
    4344        _smgr = smgr;
     45        _type = type;
    4446        _urls = uris;
    4547        _newVersion = newVersion;
     
    5759    }
    5860
    59     public UpdateType getType() { return UpdateType.ROUTER_SIGNED; }
     61    public UpdateType getType() { return _type; }
    6062
    6163    public UpdateMethod getMethod() { return UpdateMethod.TORRENT; }
  • apps/i2psnark/mime.properties

    ra1c8e3e r6bb1505d  
    1919rar     = application/x-rar-compressed
    2020su2     = application/zip
     21su3     = application/zip
    2122sud     = application/zip
    2223tbz     = application/x-bzip2
  • apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java

    ra1c8e3e r6bb1505d  
    2020
    2121import net.i2p.I2PAppContext;
     22import net.i2p.crypto.SU3File;
    2223import net.i2p.crypto.TrustedUpdate;
    2324import net.i2p.data.DataHelper;
     
    7071    /** downloaded AND installed */
    7172    private final Map<UpdateItem, Version> _installed;
     73    private final boolean _allowTorrent;
    7274    private static final DecimalFormat _pct = new DecimalFormat("0.0%");
    7375
     
    9193        _installed = new ConcurrentHashMap();
    9294        _status = "";
     95        // DEBUG slow start for snark updates
     96        // For 0.9.4 update, only for dev builds
     97        // For 0.9.5 update, only for dev builds and 1% more
     98        // For 0.9.6 update, only for dev builds and 3% more
     99        // For 0.9.8 update, only for dev builds and 30% more
     100        // Remove this for 100%
     101        _allowTorrent = RouterVersion.BUILD != 0 || _context.random().nextInt(100) < 30;
    93102    }
    94103
     
    100109        notifyInstalled(NEWS, "", Long.toString(NewsHelper.lastUpdated(_context)));
    101110        notifyInstalled(ROUTER_SIGNED, "", RouterVersion.VERSION);
     111        notifyInstalled(ROUTER_SIGNED_SU3, "", RouterVersion.VERSION);
    102112        // hack to init from the current news file... do this before we register Updaters
    103113        // This will not kick off any Updaters as none are yet registered
     
    123133        Updater u = new UpdateHandler(_context, this);
    124134        register(u, ROUTER_SIGNED, HTTP, 0);
     135        if (ConfigUpdateHandler.USE_SU3_UPDATE) {
     136            register(c, ROUTER_SIGNED_SU3, HTTP, 0);
     137            register(u, ROUTER_SIGNED_SU3, HTTP, 0);
     138            // todo
     139            //register(c, ROUTER_SIGNED_SU3, HTTPS_CLEARNET, 0);
     140            //register(u, ROUTER_SIGNED_SU3, HTTPS_CLEARNET, -10);
     141            //register(c, ROUTER_SIGNED_SU3, HTTP_CLEARNET, 0);
     142            //register(u, ROUTER_SIGNED_SU3, HTTP_CLEARNET, -20);
     143        }
    125144        // TODO see NewsFetcher
    126145        //register(u, ROUTER_SIGNED, HTTPS_CLEARNET, -5);
     
    559578     */
    560579    public void register(Updater updater, UpdateType type, UpdateMethod method, int priority) {
    561         if ((type == ROUTER_SIGNED || type == ROUTER_UNSIGNED) && NewsHelper.dontInstall(_context)) {
     580        if ((type == ROUTER_SIGNED || type == ROUTER_UNSIGNED || type == ROUTER_SIGNED_SU3) &&
     581            NewsHelper.dontInstall(_context)) {
    562582            if (_log.shouldLog(Log.WARN))
    563583                _log.warn("Ignoring registration for " + type + ", router updates disabled");
    564584            return;
    565585        }
    566         // DEBUG slow start for snark updates
    567         // For 0.9.4 update, only for dev builds
    568         // For 0.9.5 update, only for dev builds and 1% more
    569         // For 0.9.6 update, only for dev builds and 3% more
    570         // For 0.9.8 update, only for dev builds and 30% more
    571         // Remove this for 100%
    572         if (method == TORRENT && RouterVersion.BUILD == 0 && _context.random().nextInt(100) > 29) {
     586        if (type == ROUTER_SIGNED_SU3 && !ConfigUpdateHandler.USE_SU3_UPDATE) {
     587            if (_log.shouldLog(Log.WARN))
     588                _log.warn("Ignoring registration for " + type + ", SU3 updates disabled");
     589            return;
     590        }
     591        if (method == TORRENT && !_allowTorrent) {
    573592            if (_log.shouldLog(Log.WARN))
    574593                _log.warn("Ignoring torrent registration");
     
    724743
    725744            case ROUTER_SIGNED:
     745            case ROUTER_SIGNED_SU3:
    726746                if (shouldInstall() &&
    727747                    !(isUpdateInProgress(ROUTER_SIGNED) ||
     748                      isUpdateInProgress(ROUTER_SIGNED_SU3) ||
    728749                      isUpdateInProgress(ROUTER_UNSIGNED))) {
    729750                    if (_log.shouldLog(Log.INFO))
     
    762783            case NEWS:
    763784            case ROUTER_SIGNED:
     785            case ROUTER_SIGNED_SU3:
    764786            case ROUTER_UNSIGNED:
    765787                // ConfigUpdateHandler, SummaryHelper, SummaryBarRenderer handle status display
     
    878900                break;
    879901
     902            case ROUTER_SIGNED_SU3:
     903                rv = handleSu3File(task.getURI(), actualVersion, file);
     904                if (rv)
     905                    notifyDownloaded(task.getType(), task.getID(), actualVersion);
     906                break;
     907
    880908            case ROUTER_UNSIGNED:
    881909                rv = handleUnsignedFile(task.getURI(), actualVersion, file);
     
    933961        _downloaded.put(ui, ver);
    934962        // one trumps the other
    935         if (type == ROUTER_SIGNED)
     963        if (type == ROUTER_SIGNED) {
    936964            _downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, ""));
    937         else if (type == ROUTER_UNSIGNED)
     965            _downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, ""));
     966            // remove available from other type
     967            UpdateItem altui = new UpdateItem(ROUTER_SIGNED_SU3, id);
     968            Version old = _available.get(altui);
     969            if (old != null && old.compareTo(ver) <= 0)
     970                _available.remove(altui);
     971            // ... and declare the alt downloaded as well
     972            _downloaded.put(altui, ver);
     973        } else if (type == ROUTER_SIGNED_SU3) {
    938974            _downloaded.remove(new UpdateItem(ROUTER_SIGNED, ""));
     975            _downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, ""));
     976            // remove available from other type
     977            UpdateItem altui = new UpdateItem(ROUTER_SIGNED, id);
     978            Version old = _available.get(altui);
     979            if (old != null && old.compareTo(ver) <= 0)
     980                _available.remove(altui);
     981            // ... and declare the alt downloaded as well
     982            _downloaded.put(altui, ver);
     983        } else if (type == ROUTER_UNSIGNED) {
     984            _downloaded.remove(new UpdateItem(ROUTER_SIGNED, ""));
     985            _downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, ""));
     986        }
    939987        Version old = _available.get(ui);
    940988        if (old != null && old.compareTo(ver) <= 0)
     
    9701018
    9711019            case ROUTER_SIGNED:
     1020              { // avoid dup variables in next case
    9721021                String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
    9731022                StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
     
    9801029                Collections.shuffle(rv, _context.random());
    9811030                return rv;
     1031              }
     1032
     1033            case ROUTER_SIGNED_SU3:
     1034              {
     1035                String URLs = ConfigUpdateHandler.SU3_UPDATE_URLS;
     1036                StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
     1037                List<URI> rv = new ArrayList();
     1038                while (tok.hasMoreTokens()) {
     1039                    try {
     1040                        rv.add(new URI(tok.nextToken().trim()));
     1041                    } catch (URISyntaxException use) {}
     1042                }
     1043                Collections.shuffle(rv, _context.random());
     1044                return rv;
     1045              }
    9821046
    9831047            case ROUTER_UNSIGNED:
     
    10121076     */
    10131077    private boolean handleSudFile(URI uri, String actualVersion, File f) {
     1078        return handleRouterFile(uri, actualVersion, f, false);
     1079    }
     1080
     1081    /**
     1082     *  @return success
     1083     *  @since 0.9.9
     1084     */
     1085    private boolean handleSu3File(URI uri, String actualVersion, File f) {
     1086        return handleRouterFile(uri, actualVersion, f, true);
     1087    }
     1088
     1089    /**
     1090     *  Process sud, su2, or su3
     1091     *  @return success
     1092     *  @since 0.9.9
     1093     */
     1094    private boolean handleRouterFile(URI uri, String actualVersion, File f, boolean isSU3) {
    10141095        String url = uri.toString();
    1015         // Process the .sud/.su2 file
    10161096        updateStatus("<b>" + _("Update downloaded") + "</b>");
    1017         TrustedUpdate up = new TrustedUpdate(_context);
    10181097        File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
    1019         String err = up.migrateVerified(RouterVersion.VERSION, f, to);
    1020 ///////////
    1021         // caller must delete now.. why?
     1098        String err;
     1099        // Process the file
     1100        if (isSU3) {
     1101            SU3File up = new SU3File(_context, f);
     1102            File temp = new File(_context.getTempDir(), "su3out-" + _context.random().nextLong() + ".zip");
     1103            try {
     1104                if (up.verifyAndMigrate(temp)) {
     1105                    String ver = up.getVersionString();
     1106                    int type = up.getContentType();
     1107                    if (ver == null || VersionComparator.comp(RouterVersion.VERSION, ver) >= 0)
     1108                        err = "Old version " + ver;
     1109                    else if (type != SU3File.CONTENT_ROUTER)
     1110                        err = "Bad su3 content type " + type;
     1111                    else if (!FileUtil.copy(temp, to, true, false))
     1112                        err = "Failed copy to " + to;
     1113                    else
     1114                        err = null;   // success
     1115                } else {
     1116                    err = "Signature failed, signer " + DataHelper.stripHTML(up.getSignerString()) +
     1117                          ' ' + up.getSigType();
     1118                }
     1119            } catch (IOException ioe) {
     1120                _log.error("SU3 extract error", ioe);
     1121                err = DataHelper.stripHTML(ioe.toString());
     1122            } finally {
     1123                temp.delete();
     1124            }
     1125        } else {
     1126            TrustedUpdate up = new TrustedUpdate(_context);
     1127            err = up.migrateVerified(RouterVersion.VERSION, f, to);
     1128        }
     1129
     1130        // caller must delete.. could be an active torrent
    10221131        //f.delete();
    10231132        if (err == null) {
     
    12781387        @Override
    12791388        public String toString() {
     1389            if ("".equals(id))
     1390                return "UpdateItem " + type;
    12801391            return "UpdateItem " + type + ' ' + id;
    12811392        }
  • apps/routerconsole/java/src/net/i2p/router/update/DummyHandler.java

    ra1c8e3e r6bb1505d  
    4949
    5050        public DummyRunner(RouterContext ctx, ConsoleUpdateManager mgr, long maxTime) {
    51             super(ctx, mgr, Collections.EMPTY_LIST);
     51            super(ctx, mgr, UpdateType.TYPE_DUMMY, Collections.EMPTY_LIST);
    5252            _delay = maxTime;
    5353        }
    54 
    55         @Override
    56         public UpdateType getType() { return UpdateType.TYPE_DUMMY; }
    5754
    5855        @Override
  • apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java

    ra1c8e3e r6bb1505d  
    3232import net.i2p.util.FileUtil;
    3333import net.i2p.util.Log;
     34import net.i2p.util.SSLEepGet;
    3435
    3536/**
     
    5051   
    5152    public NewsFetcher(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
    52         super(ctx, mgr, uris);
     53        super(ctx, mgr, NEWS, uris);
    5354        _newsFile = new File(ctx.getRouterDir(), NewsHelper.NEWS_FILE);
    5455        _tempFile = new File(ctx.getTempDir(), "tmp-" + ctx.random().nextLong() + TEMP_NEWS_FILE);
     
    5758            _lastModified = RFC822Date.to822Date(lastMod);
    5859    }
    59 
    60     @Override
    61     public UpdateType getType() { return NEWS; }
    6260
    6361    private boolean dontInstall() {
     
    7775
    7876    public void fetchNews() {
    79         boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
     77        boolean shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY_NEWS, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY_NEWS);
    8078        String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
    8179        int proxyPort = ConfigUpdateHandler.proxyPort(_context);
     
    9290                if (shouldProxy)
    9391                    get = new EepGet(_context, true, proxyHost, proxyPort, 0, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified);
     92                else if ("https".equals(uri.getScheme()))
     93                    // no constructor w/ last mod check
     94                    get = new SSLEepGet(_context, _tempFile.getAbsolutePath(), newsURL);
    9495                else
    9596                    get = new EepGet(_context, false, null, 0, 0, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified);
     
    115116    private static final String SUD_KEY = "sudtorrent";
    116117    private static final String SU2_KEY = "su2torrent";
     118    private static final String SU3_KEY = "su3torrent";
    117119    private static final String CLEARNET_SUD_KEY = "sudclearnet";
    118120    private static final String CLEARNET_SU2_KEY = "su2clearnet";
     121    private static final String CLEARNET_HTTP_SU3_KEY = "su3clearnet";
     122    private static final String CLEARNET_HTTPS_SU3_KEY = "su3ssl";
    119123    private static final String I2P_SUD_KEY = "sudi2p";
    120124    private static final String I2P_SU2_KEY = "su2i2p";
     
    150154                            // TODO clearnet URLs, notify with HTTP_CLEARNET and/or HTTPS_CLEARNET
    151155                            Map<UpdateMethod, List<URI>> sourceMap = new HashMap(4);
     156                            // Must do su3 first
     157                            if (ConfigUpdateHandler.USE_SU3_UPDATE) {
     158                                sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED_SU3, "", HTTP));
     159                                addMethod(TORRENT, args.get(SU3_KEY), sourceMap);
     160                                addMethod(HTTP_CLEARNET, args.get(CLEARNET_HTTP_SU3_KEY), sourceMap);
     161                                addMethod(HTTPS_CLEARNET, args.get(CLEARNET_HTTPS_SU3_KEY), sourceMap);
     162                                // notify about all sources at once
     163                                _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED_SU3,
     164                                                            "", sourceMap, ver, "");
     165                                sourceMap.clear();
     166                            }
     167                            // now do sud/su2
    152168                            sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP));
    153169                            String key = FileUtil.isPack200Supported() ? SU2_KEY : SUD_KEY;
    154                             String murl = args.get(key);
    155                             if (murl != null) {
    156                                 List<URI> uris = tokenize(murl);
    157                                 if (!uris.isEmpty()) {
    158                                     Collections.shuffle(uris, _context.random());
    159                                     sourceMap.put(TORRENT, uris);
    160                                 }
    161                             }
     170                            addMethod(TORRENT, args.get(key), sourceMap);
    162171                            // notify about all sources at once
    163                             _mgr.notifyVersionAvailable(this, _currentURI,
    164                                                         ROUTER_SIGNED, "", sourceMap,
    165                                                         ver, "");
     172                            _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED,
     173                                                        "", sourceMap, ver, "");
    166174                        } else {
    167175                            if (_log.shouldLog(Log.DEBUG))
     
    267275    }
    268276
     277    /**
     278     *  Parse URLs and add to the map
     279     *  @param urls may be null
     280     *  @since 0.9.9
     281     */
     282    private void addMethod(UpdateMethod method, String urls, Map<UpdateMethod, List<URI>> map) {
     283        if (urls != null) {
     284            List<URI> uris = tokenize(urls);
     285            if (!uris.isEmpty()) {
     286                Collections.shuffle(uris, _context.random());
     287                map.put(method, uris);
     288            }
     289        }
     290    }
     291
    269292    /** override to prevent status update */
    270293    @Override
  • apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateChecker.java

    ra1c8e3e r6bb1505d  
    3636    public PluginUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr,
    3737                               List<URI> uris, String appName, String oldVersion ) {
    38         super(ctx, mgr, uris, oldVersion);
     38        super(ctx, mgr, UpdateType.PLUGIN, uris, oldVersion);
    3939        if (!uris.isEmpty())
    4040            _currentURI = uris.get(0);
     
    4242        _oldVersion = oldVersion;
    4343    }
    44 
    45     @Override
    46     public UpdateType getType() { return UpdateType.PLUGIN; }
    4744
    4845    @Override
  • apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java

    ra1c8e3e r6bb1505d  
    6161    public PluginUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris,
    6262                              String appName, String oldVersion ) {
    63         super(ctx, mgr, uris);
     63        super(ctx, mgr, UpdateType.PLUGIN, uris);
    6464        if (uris.isEmpty())
    6565            throw new IllegalArgumentException("uri cannot be empty");
     
    6969        _appName = appName;
    7070        _oldVersion = oldVersion;
    71     }
    72 
    73 
    74     @Override
    75     public UpdateType getType() {
    76         return UpdateType.PLUGIN;
    7771    }
    7872
     
    10599                updateStatus("<b>" + _("Downloading plugin from {0}", _xpi2pURL) + "</b>");
    106100                // use the same settings as for updater
    107                 boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
     101                boolean shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
    108102                String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
    109103                int proxyPort = ConfigUpdateHandler.proxyPort(_context);
  • apps/routerconsole/java/src/net/i2p/router/update/UnsignedUpdateChecker.java

    ra1c8e3e r6bb1505d  
    2929    public UnsignedUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr,
    3030                                 List<URI> uris, long lastUpdateTime) {
    31         super(ctx, mgr, uris);
     31        super(ctx, mgr, UpdateType.ROUTER_UNSIGNED, uris);
    3232        _ms = lastUpdateTime;
    3333    }
    34 
    35     //////// begin UpdateTask methods
    36 
    37     @Override
    38     public UpdateType getType() { return UpdateType.ROUTER_UNSIGNED; }
    39 
    40     //////// end UpdateTask methods
    4134
    4235    @Override
  • apps/routerconsole/java/src/net/i2p/router/update/UnsignedUpdateRunner.java

    ra1c8e3e r6bb1505d  
    2626
    2727    public UnsignedUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
    28         super(ctx, mgr, uris);
     28        super(ctx, mgr, ROUTER_UNSIGNED, uris);
    2929        if (!uris.isEmpty())
    3030            _currentURI = uris.get(0);
    3131    }
    32 
    33 
    34     @Override
    35     public UpdateType getType() { return ROUTER_UNSIGNED; }
    3632
    3733
  • apps/routerconsole/java/src/net/i2p/router/update/UpdateHandler.java

    ra1c8e3e r6bb1505d  
    55
    66import net.i2p.router.RouterContext;
     7import net.i2p.router.web.ConfigUpdateHandler;
    78import net.i2p.update.*;
     9import static net.i2p.update.UpdateType.*;
     10import static net.i2p.update.UpdateMethod.*;
    811
    912/**
     
    3942    public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
    4043                             String id, String newVersion, long maxTime) {
    41         if (type != UpdateType.ROUTER_SIGNED ||
    42             method != UpdateMethod.HTTP || updateSources.isEmpty())
     44        boolean shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
     45        if ((type != ROUTER_SIGNED && type != ROUTER_SIGNED_SU3) ||
     46            (shouldProxy && method != HTTP) ||
     47            ((!shouldProxy) && method != HTTP_CLEARNET && method != HTTPS_CLEARNET) ||
     48            updateSources.isEmpty())
    4349            return null;
    44         UpdateRunner update = new UpdateRunner(_context, _mgr, updateSources);
     50        UpdateRunner update = new UpdateRunner(_context, _mgr, type, method, updateSources);
    4551        // set status before thread to ensure UI feedback
    4652        _mgr.notifyProgress(update, "<b>" + _mgr._("Updating") + "</b>");
  • apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java

    ra1c8e3e r6bb1505d  
    66import java.net.URI;
    77import java.util.List;
     8import java.util.Locale;
    89import java.util.StringTokenizer;
    910
     
    1415import net.i2p.router.web.ConfigUpdateHandler;
    1516import net.i2p.update.*;
     17import static net.i2p.update.UpdateMethod.*;
    1618import net.i2p.util.EepGet;
    1719import net.i2p.util.I2PAppThread;
    1820import net.i2p.util.Log;
    1921import net.i2p.util.PartialEepGet;
     22import net.i2p.util.SSLEepGet;
    2023import net.i2p.util.VersionComparator;
    2124
     
    3134    protected final Log _log;
    3235    protected final ConsoleUpdateManager _mgr;
     36    protected final UpdateType _type;
     37    protected final UpdateMethod _method;
    3338    protected final List<URI> _urls;
    3439    protected final String _updateFile;
     
    5459     *  Uses router version for partial checks
    5560     */
    56     public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
    57         this(ctx, mgr, uris, RouterVersion.VERSION);
     61    public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type, List<URI> uris) {
     62        this(ctx, mgr, type, uris, RouterVersion.VERSION);
     63    }
     64
     65    /**
     66     *  Uses router version for partial checks
     67     *  @since 0.9.9
     68     */
     69    public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type,
     70                        UpdateMethod method, List<URI> uris) {
     71        this(ctx, mgr, type, method, uris, RouterVersion.VERSION);
    5872    }
    5973
     
    6276     *  @since 0.9.7
    6377     */
    64     public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris, String currentVersion) {
     78    public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type,
     79                        List<URI> uris, String currentVersion) {
     80        this(ctx, mgr, type, HTTP, uris, currentVersion);
     81    }
     82
     83    /**
     84     *  @param method HTTP, HTTP_CLEARNET, or HTTPS_CLEARNET
     85     *  @param currentVersion used for partial checks
     86     *  @since 0.9.9
     87     */
     88    public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type,
     89                        UpdateMethod method, List<URI> uris, String currentVersion) {
    6590        super("Update Runner");
    6691        setDaemon(true);
     
    6893        _log = ctx.logManager().getLog(getClass());
    6994        _mgr = mgr;
     95        _type = type;
     96        _method = method;
    7097        _urls = uris;
    7198        _baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
     
    83110    }
    84111
    85     public UpdateType getType() { return UpdateType.ROUTER_SIGNED; }
    86 
    87     public UpdateMethod getMethod() { return UpdateMethod.HTTP; }
     112    public UpdateType getType() { return _type; }
     113
     114    public UpdateMethod getMethod() { return _method; }
    88115
    89116    public URI getURI() { return _currentURI; }
     
    118145        // we've received at least 56 bytes. Need a cancel() method in EepGet ?
    119146
    120         boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
    121         String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
    122         int proxyPort = ConfigUpdateHandler.proxyPort(_context);
     147        boolean shouldProxy;
     148        String proxyHost;
     149        int proxyPort;
     150        boolean isSSL = false;
     151        if (_method == HTTP) {
     152            shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
     153            if (shouldProxy) {
     154                proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
     155                proxyPort = ConfigUpdateHandler.proxyPort(_context);
     156            } else {
     157                // TODO, wrong method, fail
     158                proxyHost = null;
     159                proxyPort = 0;
     160            }
     161        } else if (_method == HTTP_CLEARNET) {
     162            shouldProxy = false;
     163            proxyHost = null;
     164            proxyPort = 0;
     165        } else if (_method == HTTPS_CLEARNET) {
     166            shouldProxy = false;
     167            proxyHost = null;
     168            proxyPort = 0;
     169            isSSL = true;
     170        } else {
     171            throw new IllegalArgumentException();
     172        }
    123173
    124174        if (_urls.isEmpty()) {
     
    133183            _currentURI = uri;
    134184            String updateURL = uri.toString();
     185            if ((_method == HTTP && !"http".equals(uri.getScheme())) ||
     186                (_method == HTTP_CLEARNET && !"http".equals(uri.getScheme())) ||
     187                (_method == HTTPS_CLEARNET && !"https".equals(uri.getScheme())) ||
     188                uri.getHost() == null ||
     189                (_method != HTTP && uri.getHost().toLowerCase(Locale.US).endsWith(".i2p"))) {
     190                if (_log.shouldLog(Log.WARN))
     191                    _log.warn("Bad update URI " + uri + " for method " + _method);
     192                continue;
     193            }
     194
    135195            updateStatus("<b>" + _("Updating from {0}", linkify(updateURL)) + "</b>");
    136196            if (_log.shouldLog(Log.DEBUG))
     
    138198
    139199            // Check the first 56 bytes for the version
    140             if (shouldProxy) {
     200            // FIXME PartialEepGet works with clearnet but not with SSL
     201            _newVersion = null;
     202            if (!isSSL) {
    141203                _isPartial = true;
    142204                _baos.reset();
     
    158220                    // 40 retries!!
    159221                    _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
     222                else if (isSSL)
     223                    _get = new SSLEepGet(_context, _updateFile, updateURL);
    160224                else
    161225                    _get = new EepGet(_context, 1, _updateFile, updateURL, false);
     
    209273        }
    210274
     275        // FIXME if we didn't do a partial, we don't know
     276        if (_newVersion == null)
     277            _newVersion = "unknown";
    211278        File tmp = new File(_updateFile);
    212279        if (_mgr.notifyComplete(this, _newVersion, tmp))
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java

    ra1c8e3e r6bb1505d  
    1414    private static final String HOPS = ngettext("1 hop", "{0} hops");
    1515    private static final String TUNNELS = ngettext("1 tunnel", "{0} tunnels");
    16 
    17     static final String PROP_ADVANCED = "routerconsole.advanced";
    1816
    1917    public String getForm() {
     
    7068    private void renderForm(StringBuilder buf, int index, String prefix, String name, TunnelPoolSettings in, TunnelPoolSettings out) {
    7169
    72         boolean advanced = _context.getBooleanProperty(PROP_ADVANCED);
     70        boolean advanced = isAdvanced();
    7371
    7472        buf.append("<tr><th colspan=\"3\"><a name=\"").append(prefix).append("\">");
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java

    ra1c8e3e r6bb1505d  
    11package net.i2p.router.web;
    22
     3import java.io.File;
    34import java.util.HashMap;
    45import java.util.Map;
     
    2324    private String _proxyPort;
    2425    private boolean _updateThroughProxy;
     26    private boolean _newsThroughProxy;
    2527    private String _trustedKeys;
    2628    private boolean _updateUnsigned;
     
    3739    public static final String DEFAULT_UPDATE_POLICY = "download";
    3840    public static final String PROP_SHOULD_PROXY = "router.updateThroughProxy";
    39     public static final String DEFAULT_SHOULD_PROXY = Boolean.TRUE.toString();
     41    public static final boolean DEFAULT_SHOULD_PROXY = true;
     42    /** @since 0.9.9 */
     43    public static final String PROP_SHOULD_PROXY_NEWS = "router.fetchNewsThroughProxy";
     44    /** @since 0.9.9 */
     45    public static final boolean DEFAULT_SHOULD_PROXY_NEWS = true;
    4046    public static final String PROP_PROXY_HOST = "router.updateProxyHost";
    4147    public static final String DEFAULT_PROXY_HOST = "127.0.0.1";
     
    5157   
    5258    public static final String PROP_UPDATE_URL = "router.updateURL";
     59
    5360    /**
    5461     *  Changed as of release 0.8 to support both .sud and .su2
     
    7683    "http://update.postman.i2p/i2pupdate.sud" ;
    7784
     85    /**
     86     *  These are only for .sud and .su2.
     87     *  Do NOT use this for .su3
     88     */
    7889    public static final String DEFAULT_UPDATE_URL;
    7990    static {
     
    8394            DEFAULT_UPDATE_URL = NO_PACK200_URLS;
    8495    }
     96
     97    private static final String SU3_CERT_DIR = "certificates/router";
     98
     99    /**
     100     *  Only enabled if we have pack200 and trusted public key certificates installed
     101     *  @since 0.9.9
     102     */
     103    public static final boolean USE_SU3_UPDATE;
     104    static {
     105        String[] files = (new File(I2PAppContext.getGlobalContext().getBaseDir(), SU3_CERT_DIR)).list();
     106        USE_SU3_UPDATE = FileUtil.isPack200Supported() && files != null && files.length > 0;
     107    }
     108
     109    private static final String DEFAULT_SU3_UPDATE_URLS =
     110    "http://echelon.i2p/i2p/i2pupdate.su3\r\n" +
     111    "http://inr.i2p/i2p/i2pupdate.su3\r\n" +
     112    "http://meeh.i2p/i2pupdate/i2pupdate.su3\r\n" +
     113    "http://stats.i2p/i2p/i2pupdate.su3\r\n" +
     114    "http://www.i2p2.i2p/_static/i2pupdate.su3\r\n" +
     115    "http://update.dg.i2p/files/i2pupdate.su3\r\n" +
     116    "http://update.killyourtv.i2p/i2pupdate.su3\r\n" +
     117    "http://update.postman.i2p/i2pupdate.su3" ;
     118
     119    /**
     120     *  Empty string if disabled. Cannot be overridden by config.
     121     *  @since 0.9.9
     122     */
     123    public static final String SU3_UPDATE_URLS = USE_SU3_UPDATE ? DEFAULT_SU3_UPDATE_URLS : "";
    85124
    86125    public static final String PROP_TRUSTED_KEYS = "router.trustedUpdateKeys";
     
    131170
    132171        if ( (_newsURL != null) && (_newsURL.length() > 0) ) {
     172            if (_newsURL.startsWith("https"))
     173                _newsThroughProxy = false;
    133174            String oldURL = ConfigUpdateHelper.getNewsURL(_context);
    134175            if ( (oldURL == null) || (!_newsURL.equals(oldURL)) ) {
     
    156197        }
    157198       
    158         changes.put(PROP_SHOULD_PROXY, "" + _updateThroughProxy);
    159         changes.put(PROP_UPDATE_UNSIGNED, "" + _updateUnsigned);
     199        changes.put(PROP_SHOULD_PROXY, Boolean.toString(_updateThroughProxy));
     200        changes.put(PROP_SHOULD_PROXY_NEWS, Boolean.toString(_newsThroughProxy));
     201        changes.put(PROP_UPDATE_UNSIGNED, Boolean.toString(_updateUnsigned));
    160202       
    161203        String oldFreqStr = _context.getProperty(PROP_REFRESH_FREQUENCY, DEFAULT_REFRESH_FREQUENCY);
     
    219261    public void setUpdateUnsigned(String foo) { _updateUnsigned = true; }
    220262    public void setZipURL(String url) { _zipURL = url; }
     263     /** @since 0.9.9 */
     264    public void setNewsThroughProxy(String foo) { _newsThroughProxy = true; }
    221265}
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java

    ra1c8e3e r6bb1505d  
    7474   
    7575    public String getUpdateThroughProxy() {
    76         String proxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
    77         if (Boolean.parseBoolean(proxy))
     76        if (_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY))
    7877            return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateThroughProxy\" checked=\"checked\" >";
    7978        else
    8079            return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateThroughProxy\" >";
     80    }
     81   
     82    /** @since 0.9.9 */
     83    public String getNewsThroughProxy() {
     84        if (_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY_NEWS, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY_NEWS))
     85            return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"newsThroughProxy\" checked=\"checked\" >";
     86        else
     87            return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"newsThroughProxy\" >";
    8188    }
    8289   
  • apps/routerconsole/java/src/net/i2p/router/web/HelperBase.java

    ra1c8e3e r6bb1505d  
    1212    protected Writer _out;
    1313
     14    static final String PROP_ADVANCED = "routerconsole.advanced";
     15
    1416    /**
    1517     * Configure this bean to query a particular router context
     
    2426            t.printStackTrace();
    2527        }
     28    }
     29
     30    /** @since 0.9.9 */
     31    public boolean isAdvanced() {
     32        return _context.getBooleanProperty(PROP_ADVANCED);
    2633    }
    2734
  • apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java

    ra1c8e3e r6bb1505d  
    5050        if (mgr == null) return false;
    5151        return mgr.isUpdateInProgress(ROUTER_SIGNED) ||
     52               mgr.isUpdateInProgress(ROUTER_SIGNED_SU3) ||
    5253               mgr.isUpdateInProgress(ROUTER_UNSIGNED) ||
    5354               mgr.isUpdateInProgress(TYPE_DUMMY);
     
    6162        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
    6263        if (mgr == null) return false;
    63         return mgr.getUpdateAvailable(ROUTER_SIGNED) != null;
     64        return mgr.getUpdateAvailable(ROUTER_SIGNED) != null ||
     65               mgr.getUpdateAvailable(ROUTER_SIGNED_SU3) != null;
    6466    }
    6567
     
    7274        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
    7375        if (mgr == null) return null;
     76        String rv = mgr.getUpdateAvailable(ROUTER_SIGNED_SU3);
     77        if (rv != null)
     78            return rv;
    7479        return mgr.getUpdateAvailable(ROUTER_SIGNED);
    7580    }
     
    8388        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
    8489        if (mgr == null) return null;
     90        String rv = mgr.getUpdateDownloaded(ROUTER_SIGNED_SU3);
     91        if (rv != null)
     92            return rv;
    8593        return mgr.getUpdateDownloaded(ROUTER_SIGNED);
    8694    }
  • apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java

    ra1c8e3e r6bb1505d  
    2828import static net.i2p.app.ClientAppState.*;
    2929import net.i2p.apps.systray.SysTray;
     30import net.i2p.crypto.KeyStoreUtil;
    3031import net.i2p.data.Base32;
    3132import net.i2p.data.DataHelper;
     
    3940import net.i2p.util.PortMapper;
    4041import net.i2p.util.SecureDirectory;
    41 import net.i2p.util.SecureFileOutputStream;
    42 import net.i2p.util.ShellCommand;
    4342import net.i2p.util.SystemVersion;
    4443import net.i2p.util.VersionComparator;
     
    676675            return rv;
    677676        }
    678         File dir = ks.getParentFile();
    679         if (!dir.exists()) {
    680             File sdir = new SecureDirectory(dir.getAbsolutePath());
    681             if (!sdir.mkdir())
    682                 return false;
    683         }
    684677        return createKeyStore(ks);
    685678    }
     
    696689    private boolean createKeyStore(File ks) {
    697690        // make a random 48 character password (30 * 8 / 5)
    698         byte[] rand = new byte[30];
    699         _context.random().nextBytes(rand);
    700         String keyPassword = Base32.encode(rand);
     691        String keyPassword = KeyStoreUtil.randomString();
    701692        // and one for the cname
    702         _context.random().nextBytes(rand);
    703         String cname = Base32.encode(rand) + ".console.i2p.net";
    704 
    705         String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath();
    706         String[] args = new String[] {
    707                    keytool,
    708                    "-genkey",            // -genkeypair preferred in newer keytools, but this works with more
    709                    "-storetype", KeyStore.getDefaultType(),
    710                    "-keystore", ks.getAbsolutePath(),
    711                    "-storepass", DEFAULT_KEYSTORE_PASSWORD,
    712                    "-alias", "console",
    713                    "-dname", "CN=" + cname + ",OU=Console,O=I2P Anonymous Network,L=XX,ST=XX,C=XX",
    714                    "-validity", "3652",  // 10 years
    715                    "-keyalg", "DSA",
    716                    "-keysize", "1024",
    717                    "-keypass", keyPassword};
    718         boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 30);  // 30 secs
     693        String cname = KeyStoreUtil.randomString() + ".console.i2p.net";
     694        boolean success = KeyStoreUtil.createKeys(ks, "console", cname, "Console", keyPassword);
    719695        if (success) {
    720696            success = ks.exists();
    721697            if (success) {
    722                 SecureFileOutputStream.setPerms(ks);
    723698                try {
    724699                    Map<String, String> changes = new HashMap();
     
    734709                               "IP address, host name, router identity, or destination keys.");
    735710        } else {
    736             System.err.println("Failed to create console SSL keystore using command line:");
    737             StringBuilder buf = new StringBuilder(256);
    738             for (int i = 0;  i < args.length; i++) {
    739                 buf.append('"').append(args[i]).append("\" ");
    740             }
    741             System.err.println(buf.toString());
    742             System.err.println("This is for the Sun/Oracle keytool, others may be incompatible.\n" +
     711            System.err.println("Failed to create console SSL keystore.\n" +
     712                               "This is for the Sun/Oracle keytool, others may be incompatible.\n" +
    743713                               "If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD +
    744714                               " to " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath());
  • apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java

    ra1c8e3e r6bb1505d  
    4040        Map<Hash, TunnelPool> clientOutboundPools = _context.tunnelManager().getOutboundClientPools();
    4141        destinations = new ArrayList(clientInboundPools.keySet());
    42         boolean debug = _context.getBooleanProperty(ConfigTunnelsHelper.PROP_ADVANCED);
     42        boolean debug = _context.getBooleanProperty(HelperBase.PROP_ADVANCED);
    4343        for (int i = 0; i < destinations.size(); i++) {
    4444            Hash client = destinations.get(i);
  • apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java

    ra1c8e3e r6bb1505d  
    6767            if (_action.contains("Unsigned")) {
    6868                update(ROUTER_UNSIGNED);
     69            } else if (ConfigUpdateHandler.USE_SU3_UPDATE) {
     70                update(ROUTER_SIGNED_SU3);
    6971            } else {
    7072                update(ROUTER_SIGNED);
     
    7779        if (mgr == null)
    7880            return;
    79         if (mgr.isUpdateInProgress(ROUTER_SIGNED) || mgr.isUpdateInProgress(ROUTER_UNSIGNED)) {
     81        if (mgr.isUpdateInProgress(ROUTER_SIGNED) || mgr.isUpdateInProgress(ROUTER_UNSIGNED) ||
     82            mgr.isUpdateInProgress(ROUTER_SIGNED_SU3)) {
    8083            _log.error("Update already running");
    8184            return;
  • apps/routerconsole/jsp/configupdate.jsp

    ra1c8e3e r6bb1505d  
    4949          <td><jsp:getProperty name="updatehelper" property="updatePolicySelectBox" /></td></tr>
    5050    <% }   // if canInstall %>
     51        <tr><td class="mediumtags" align="right"><b><%=intl._("Fetch news through the eepProxy?")%></b></td>
     52          <td><jsp:getProperty name="updatehelper" property="newsThroughProxy" /></td></tr>
    5153        <tr><td class="mediumtags" align="right"><b><%=intl._("Update through the eepProxy?")%></b></td>
    52           <td><jsp:getProperty name="updatehelper" property="updateThroughProxy" /></td>
    53         </tr><tr><td class="mediumtags" align="right"><b><%=intl._("eepProxy host")%>:</b></td>
     54          <td><jsp:getProperty name="updatehelper" property="updateThroughProxy" /></td></tr>
     55      <% if (updatehelper.isAdvanced()) { %>
     56        <tr><td class="mediumtags" align="right"><b><%=intl._("eepProxy host")%>:</b></td>
    5457          <td><input type="text" size="10" name="proxyHost" value="<jsp:getProperty name="updatehelper" property="proxyHost" />" /></td>
    5558        </tr><tr><td class="mediumtags" align="right"><b><%=intl._("eepProxy port")%>:</b></td>
    5659          <td><input type="text" size="10" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /></td></tr>
     60      <% }   // if isAdvanced %>
    5761    <% if (updatehelper.canInstall()) { %>
     62      <% if (updatehelper.isAdvanced()) { %>
    5863        <tr><td class="mediumtags" align="right"><b><%=intl._("Update URLs")%>:</b></td>
    5964          <td><textarea cols="60" rows="6" name="updateURL" wrap="off" spellcheck="false"><jsp:getProperty name="updatehelper" property="updateURL" /></textarea></td>
    6065        </tr><tr><td class="mediumtags" align="right"><b><%=intl._("Trusted keys")%>:</b></td>
    61           <td><textarea cols="60" rows="6" name="trustedKeys" wrap="off" spellcheck="false"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea></td>
    62         </tr><tr><td id="unsignedbuild" class="mediumtags" align="right"><b><%=intl._("Update with unsigned development builds?")%></b></td>
     66          <td><textarea cols="60" rows="6" name="trustedKeys" wrap="off" spellcheck="false"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea></td></tr>
     67      <% }   // if isAdvanced %>
     68        <tr><td id="unsignedbuild" class="mediumtags" align="right"><b><%=intl._("Update with unsigned development builds?")%></b></td>
    6369          <td><jsp:getProperty name="updatehelper" property="updateUnsigned" /></td>
    6470        </tr><tr><td class="mediumtags" align="right"><b><%=intl._("Unsigned Build URL")%>:</b></td>
  • build.xml

    ra1c8e3e r6bb1505d  
    14981498        </fail>
    14991499        <echo message="Key file is ${release.privkey}" />
     1500        <!-- now build and verify the unpacked sud from the unpacked zip -->
    15001501        <java classname="net.i2p.crypto.TrustedUpdate" fork="true" failonerror="true">
    15011502            <classpath>
     
    15301531            <arg value="i2pupdate.sud" />
    15311532        </java>
    1532         <!-- now build and verify the packed sud from the packed zip -->
     1533        <!-- now build and verify the packed su2 from the packed zip -->
    15331534        <java classname="net.i2p.crypto.TrustedUpdate" fork="true" failonerror="true">
    15341535            <classpath>
     
    15631564            <arg value="i2pupdate.su2" />
    15641565        </java>
     1566        <!-- now build and verify the packed su3 from the packed zip -->
     1567        <input message="Enter su3 private signing key store:" addproperty="release.privkey.su3" />
     1568        <fail message="You must enter a path." >
     1569            <condition>
     1570                <equals arg1="${release.privkey.su3}" arg2=""/>
     1571            </condition>
     1572        </fail>
     1573        <input message="Enter key name (you@mail.i2p):" addproperty="release.signer.su3" />
     1574        <fail message="You must enter a name." >
     1575            <condition>
     1576                <equals arg1="${release.signer.su3}" arg2=""/>
     1577            </condition>
     1578        </fail>
     1579        <input message="Enter key password for ${release.signer.su3}:" addproperty="release.password.su3" />
     1580        <fail message="You must enter a password." >
     1581            <condition>
     1582                <equals arg1="${release.password.su3}" arg2=""/>
     1583            </condition>
     1584        </fail>
     1585        <java classname="net.i2p.crypto.SU3File" inputstring="${release.password.su3}" fork="true" failonerror="true">
     1586            <classpath>
     1587                <pathelement location="build/i2p.jar" />
     1588            </classpath>
     1589            <arg value="sign" />
     1590            <arg value="-c" />
     1591            <arg value="ROUTER" />
     1592            <arg value="-t" />
     1593            <arg value="RSA_SHA512_4096" />
     1594            <arg value="i2pupdate200.zip" />
     1595            <arg value="i2pupdate.su3" />
     1596            <arg value="${release.privkey.su3}" />
     1597            <arg value="${release.number}" />
     1598            <arg value="${release.signer.su3}" />
     1599        </java>
     1600        <echo message="Verify version and VALID signature:" />
     1601        <java classname="net.i2p.crypto.SU3File" fork="true" failonerror="true">
     1602            <classpath>
     1603                <pathelement location="build/i2p.jar" />
     1604            </classpath>
     1605            <!-- set base dir so it can find the pubkey cert -->
     1606            <jvmarg value="-Di2p.dir.base=installer/resources" />
     1607            <arg value="verifysig" />
     1608            <arg value="i2pupdate.su3" />
     1609        </java>
     1610        <java classname="net.i2p.crypto.SU3File" fork="true" failonerror="true">
     1611            <classpath>
     1612                <pathelement location="build/i2p.jar" />
     1613            </classpath>
     1614            <!-- set base dir so it can find the pubkey cert -->
     1615            <jvmarg value="-Di2p.dir.base=installer/resources" />
     1616            <arg value="showversion" />
     1617            <arg value="i2pupdate.su3" />
     1618        </java>
    15651619        <!-- will this use the monotonerc file in the current workspace? -->
    15661620        <echo message="Checking out fresh copy into ../i2p-${release.number} for tarballing:" />
     
    16101664            <arg value="i2pupdate_${release.number}.zip" />
    16111665            <arg value="i2pupdate.su2" />
     1666            <arg value="i2pupdate.su3" />
    16121667            <arg value="i2pupdate.sud" />
    16131668            <arg value="i2pinstall_${release.number}_windows.exe.sig" />
     
    16241679            <arg value="i2pupdate_${release.number}.zip" />
    16251680            <arg value="i2pupdate.su2" />
     1681            <arg value="i2pupdate.su3" />
    16261682            <arg value="i2pupdate.sud" />
    16271683            <arg value="i2pinstall_${release.number}_windows.exe.sig" />
     
    16371693            <arg value="i2pupdate_${release.number}.zip" />
    16381694            <arg value="i2pupdate.su2" />
     1695            <arg value="i2pupdate.su3" />
    16391696            <arg value="i2pupdate.sud" />
    16401697        </exec>
     
    16561713            </classpath>
    16571714            <arg value="i2pupdate-${release.number}.su2" />
     1715            <arg value="http://tracker2.postman.i2p/announce.php" />
     1716        </java>
     1717        <copy file="i2pupdate.su3" tofile="i2pupdate-${release.number}.su3" />
     1718        <java classname="org.klomp.snark.Storage" fork="true" failonerror="true">
     1719            <classpath>
     1720                <pathelement location="build/i2p.jar" />
     1721                <pathelement location="build/i2psnark.jar" />
     1722            </classpath>
     1723            <arg value="i2pupdate-${release.number}.su3" />
    16581724            <arg value="http://tracker2.postman.i2p/announce.php" />
    16591725        </java>
  • core/java/src/net/i2p/client/I2CPSSLSocketFactory.java

    ra1c8e3e r6bb1505d  
    88import java.security.KeyStore;
    99import java.security.GeneralSecurityException;
    10 import java.security.cert.CertificateExpiredException;
    11 import java.security.cert.CertificateNotYetValidException;
    12 import java.security.cert.CertificateFactory;
    13 import java.security.cert.X509Certificate;
    14 import java.util.Locale;
    1510
    1611import javax.net.ssl.SSLContext;
     
    1914
    2015import net.i2p.I2PAppContext;
     16import net.i2p.crypto.KeyStoreUtil;
    2117import net.i2p.util.Log;
    2218
     
    7268
    7369        File dir = new File(context.getConfigDir(), CERT_DIR);
    74         int adds = addCerts(dir, ks);
     70        int adds = KeyStoreUtil.addCerts(dir, ks);
    7571        int totalAdds = adds;
    7672        if (adds > 0)
     
    7975        File dir2 = new File(System.getProperty("user.dir"), CERT_DIR);
    8076        if (!dir.getAbsolutePath().equals(dir2.getAbsolutePath())) {
    81             adds = addCerts(dir2, ks);
     77            adds = KeyStoreUtil.addCerts(dir2, ks);
    8278            totalAdds += adds;
    8379            if (adds > 0)
     
    106102    }
    107103
    108     /**
    109      *  Load all X509 Certs from a directory and add them to the
    110      *  trusted set of certificates in the key store
    111      *
    112      *  @return number successfully added
    113      */
    114     private static int addCerts(File dir, KeyStore ks) {
    115         info("Looking for X509 Certificates in " + dir.getAbsolutePath());
    116         int added = 0;
    117         if (dir.exists() && dir.isDirectory()) {
    118             File[] files = dir.listFiles();
    119             if (files != null) {
    120                 for (int i = 0; i < files.length; i++) {
    121                     File f = files[i];
    122                     if (!f.isFile())
    123                         continue;
    124                     // use file name as alias
    125                     String alias = f.getName().toLowerCase(Locale.US);
    126                     boolean success = addCert(f, alias, ks);
    127                     if (success)
    128                         added++;
    129                 }
    130             }
    131         }
    132         return added;
    133     }
    134 
    135     /**
    136      *  Load an X509 Cert from a file and add it to the
    137      *  trusted set of certificates in the key store
    138      *
    139      *  @return success
    140      */
    141     private static boolean addCert(File file, String alias, KeyStore ks) {
    142         InputStream fis = null;
    143         try {
    144             fis = new FileInputStream(file);
    145             CertificateFactory cf = CertificateFactory.getInstance("X.509");
    146             X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
    147             info("Read X509 Certificate from " + file.getAbsolutePath() +
    148                           " Issuer: " + cert.getIssuerX500Principal() +
    149                           "; Valid From: " + cert.getNotBefore() +
    150                           " To: " + cert.getNotAfter());
    151             try {
    152                 cert.checkValidity();
    153             } catch (CertificateExpiredException cee) {
    154                 error("Rejecting expired X509 Certificate: " + file.getAbsolutePath(), cee);
    155                 return false;
    156             } catch (CertificateNotYetValidException cnyve) {
    157                 error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve);
    158                 return false;
    159             }
    160             ks.setCertificateEntry(alias, cert);
    161             info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal());
    162         } catch (GeneralSecurityException gse) {
    163             error("Error reading X509 Certificate: " + file.getAbsolutePath(), gse);
    164             return false;
    165         } catch (IOException ioe) {
    166             error("Error reading X509 Certificate: " + file.getAbsolutePath(), ioe);
    167             return false;
    168         } finally {
    169             try { if (fis != null) fis.close(); } catch (IOException foo) {}
    170         }
    171         return true;
    172     }
    173 
    174     /** @since 0.9.8 */
    175     private static void info(String msg) {
    176         log(I2PAppContext.getGlobalContext(), Log.INFO, msg, null);
    177     }
    178 
    179     /** @since 0.9.8 */
    180     private static void error(String msg, Throwable t) {
    181         log(I2PAppContext.getGlobalContext(), Log.ERROR, msg, t);
    182     }
    183 
    184104    /** @since 0.9.8 */
    185105    private static void info(I2PAppContext ctx, String msg) {
  • core/java/src/net/i2p/crypto/CryptoConstants.java

    ra1c8e3e r6bb1505d  
    3131
    3232import java.math.BigInteger;
     33import java.security.spec.DSAParameterSpec;
    3334
    3435import net.i2p.util.NativeBigInteger;
     
    6465                                                               + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);
    6566    public static final BigInteger elgg = new NativeBigInteger("2");
     67
     68    /**
     69     *  @since 0.9.9
     70     */
     71    public static final DSAParameterSpec DSA_SHA1_SPEC = new DSAParameterSpec(dsap, dsaq, dsag);
    6672}
  • core/java/src/net/i2p/crypto/DSAEngine.java

    ra1c8e3e r6bb1505d  
    3535import java.math.BigInteger;
    3636import java.security.GeneralSecurityException;
     37import java.security.Key;
    3738import java.security.KeyFactory;
    3839import java.security.MessageDigest;
    3940import java.security.PrivateKey;
    4041import java.security.PublicKey;
    41 import java.security.spec.DSAPrivateKeySpec;
    42 import java.security.spec.DSAPublicKeySpec;
    43 import java.security.spec.KeySpec;
     42import java.security.interfaces.DSAKey;
     43import java.security.interfaces.ECKey;
     44import java.security.interfaces.RSAKey;
    4445
    4546import net.i2p.I2PAppContext;
     
    6364 *  Params and rv's changed from Hash to SHA1Hash for version 0.8.1
    6465 *  Hash variants of sign() and verifySignature() restored in 0.8.3, required by Syndie.
     66 *
     67 *  As of 0.9.9, certain methods support ECDSA keys and signatures, i.e. all types
     68 *  specified in SigType. The type is specified by the getType() method in
     69 *  Signature, SigningPublicKey, and SigningPrivateKey. See Javadocs for individual
     70 *  methods for the supported types. Methods encountering an unsupported type
     71 *  will throw an IllegalArgumentException.
    6572 */
    6673public class DSAEngine {
     
    8188
    8289    /**
    83      *  Verify using DSA-SHA1.
    84      *  Uses TheCrypto code unless configured to use the java.security libraries.
     90     *  Verify using DSA-SHA1 or ECDSA.
     91     *  Uses TheCrypto code for DSA-SHA1 unless configured to use the java.security libraries.
    8592     */
    8693    public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) {
    8794        boolean rv;
     95        SigType type = signature.getType();
     96        if (type != verifyingKey.getType())
     97            throw new IllegalArgumentException("type mismatch sig=" + signature.getType() + " key=" + verifyingKey.getType());
     98        if (type != SigType.DSA_SHA1) {
     99            try {
     100                rv = altVerifySig(signature, signedData, verifyingKey);
     101                if ((!rv) && _log.shouldLog(Log.WARN))
     102                    _log.warn(type + " Sig Verify Fail");
     103                return rv;
     104            } catch (GeneralSecurityException gse) {
     105                if (_log.shouldLog(Log.WARN))
     106                    _log.warn(type + " Sig Verify Fail", gse);
     107                return false;
     108            }
     109        }
    88110        if (_useJavaLibs) {
    89111            try {
     
    105127
    106128    /**
    107      *  Verify using DSA-SHA1
     129     *  Verify using DSA-SHA1 ONLY
    108130     */
    109131    public boolean verifySignature(Signature signature, byte signedData[], int offset, int size, SigningPublicKey verifyingKey) {
     
    112134
    113135    /**
    114      *  Verify using DSA-SHA1
     136     *  Verify using DSA-SHA1 ONLY
    115137     */
    116138    public boolean verifySignature(Signature signature, InputStream in, SigningPublicKey verifyingKey) {
     
    118140    }
    119141
    120     /** @param hash SHA-1 hash, NOT a SHA-256 hash */
     142    /**
     143     *  Verify using DSA-SHA1 ONLY
     144     *  @param hash SHA-1 hash, NOT a SHA-256 hash
     145     */
    121146    public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) {
    122147        return verifySig(signature, hash, verifyingKey);
     
    124149
    125150    /**
     151     *  Nonstandard.
    126152     *  Used by Syndie.
    127153     *  @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2)
     
    132158
    133159    /**
     160     *  Generic signature type.
     161     *
     162     *  @param hash SHA1Hash, Hash, Hash384, or Hash512
     163     *  @since 0.9.9
     164     */
     165    public boolean verifySignature(Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) {
     166        SigType type = signature.getType();
     167        if (type != verifyingKey.getType())
     168            throw new IllegalArgumentException("type mismatch sig=" + type + " key=" + verifyingKey.getType());
     169        int hashlen = type.getHashLen();
     170        if (hash.length() != hashlen)
     171            throw new IllegalArgumentException("type mismatch hash=" + hash.getClass() + " sig=" + type);
     172        if (type == SigType.DSA_SHA1)
     173            return verifySig(signature, hash, verifyingKey);
     174        try {
     175            return altVerifySigRaw(signature, hash, verifyingKey);
     176        } catch (GeneralSecurityException gse) {
     177            if (_log.shouldLog(Log.WARN))
     178                _log.warn(type + " Sig Verify Fail", gse);
     179            return false;
     180        }
     181    }
     182
     183    /**
     184     *  Generic signature type.
     185     *  If you have a Java pubkey, use this, so you don't lose the key parameters,
     186     *  which may be different than the ones defined in SigType.
     187     *
     188     *  @param hash SHA1Hash, Hash, Hash384, or Hash512
     189     *  @param pubKey Java key
     190     *  @since 0.9.9
     191     */
     192    public boolean verifySignature(Signature signature, SimpleDataStructure hash, PublicKey pubKey) {
     193        try {
     194            return altVerifySigRaw(signature, hash, pubKey);
     195        } catch (GeneralSecurityException gse) {
     196            if (_log.shouldLog(Log.WARN))
     197                _log.warn(signature.getType() + " Sig Verify Fail", gse);
     198            return false;
     199        }
     200    }
     201
     202    /**
     203     *  Verify using DSA-SHA1 or Syndie DSA-SHA256 ONLY.
    134204     *  @param hash either a Hash or a SHA1Hash
    135205     *  @since 0.8.3
    136206     */
    137207    private boolean verifySig(Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) {
     208        if (signature.getType() != SigType.DSA_SHA1)
     209            throw new IllegalArgumentException("Bad sig type " + signature.getType());
     210        if (verifyingKey.getType() != SigType.DSA_SHA1)
     211            throw new IllegalArgumentException("Bad key type " + verifyingKey.getType());
    138212        long start = _context.clock().now();
    139213
     
    185259
    186260    /**
    187      *  Sign using DSA-SHA1.
     261     *  Sign using DSA-SHA1 or ECDSA.
    188262     *  Uses TheCrypto code unless configured to use the java.security libraries.
     263     *
     264     *  @return null on error
    189265     */
    190266    public Signature sign(byte data[], SigningPrivateKey signingKey) {
     267        SigType type = signingKey.getType();
     268        if (type != SigType.DSA_SHA1) {
     269            try {
     270                return altSign(data, signingKey);
     271            } catch (GeneralSecurityException gse) {
     272                if (_log.shouldLog(Log.WARN))
     273                    _log.warn(type + " Sign Fail", gse);
     274                return null;
     275            }
     276        }
    191277        if (_useJavaLibs) {
    192278            try {
     
    202288
    203289    /**
    204      *  Sign using DSA-SHA1
     290     *  Sign using DSA-SHA1 ONLY
     291     *
     292     *  @return null on error
    205293     */
    206294    public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
     
    211299   
    212300    /**
    213      *  Sign using DSA-SHA1.
     301     *  Sign using DSA-SHA1 ONLY.
    214302     *  Reads the stream until EOF. Does not close the stream.
     303     *
     304     *  @return null on error
    215305     */
    216306    public Signature sign(InputStream in, SigningPrivateKey signingKey) {
     
    220310    }
    221311
    222     /** @param hash SHA-1 hash, NOT a SHA-256 hash */
     312    /**
     313     *  Sign using DSA-SHA1 ONLY.
     314     *
     315     *  @param hash SHA-1 hash, NOT a SHA-256 hash
     316     *  @return null on error
     317     */
    223318    public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) {
    224319        return signIt(hash, signingKey);
     
    226321
    227322    /**
     323     *  Nonstandard.
    228324     *  Used by Syndie.
     325     *
     326     *  @return null on error
    229327     *  @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2)
    230328     */
     
    234332
    235333    /**
     334     *  Generic signature type.
     335     *
     336     *  @param hash SHA1Hash, Hash, Hash384, or Hash512
     337     *  @return null on error
     338     *  @since 0.9.9
     339     */
     340    public Signature sign(SimpleDataStructure hash, SigningPrivateKey signingKey) {
     341        SigType type = signingKey.getType();
     342        int hashlen = type.getHashLen();
     343        if (hash.length() != hashlen)
     344            throw new IllegalArgumentException("type mismatch hash=" + hash.getClass() + " key=" + type);
     345        if (type == SigType.DSA_SHA1)
     346            return signIt(hash, signingKey);
     347        try {
     348            return altSignRaw(hash, signingKey);
     349        } catch (GeneralSecurityException gse) {
     350            if (_log.shouldLog(Log.WARN))
     351                _log.warn(type + " Sign Fail", gse);
     352            return null;
     353        }
     354    }
     355
     356    /**
     357     *  Generic signature type.
     358     *  If you have a Java privkey, use this, so you don't lose the key parameters,
     359     *  which may be different than the ones defined in SigType.
     360     *
     361     *  @param hash SHA1Hash, Hash, Hash384, or Hash512
     362     *  @param privKey Java key
     363     *  @param type returns a Signature of this type
     364     *  @return null on error
     365     *  @since 0.9.9
     366     */
     367    public Signature sign(SimpleDataStructure hash, PrivateKey privKey, SigType type) {
     368        String algo = getRawAlgo(privKey);
     369        String talgo = getRawAlgo(type);
     370        if (!algo.equals(talgo))
     371            throw new IllegalArgumentException("type mismatch type=" + type + " key=" + privKey.getClass().getSimpleName());
     372        try {
     373            return altSignRaw(algo, hash, privKey, type);
     374        } catch (GeneralSecurityException gse) {
     375            if (_log.shouldLog(Log.WARN))
     376                _log.warn(type + " Sign Fail", gse);
     377            return null;
     378        }
     379    }
     380
     381    /**
     382     *  Sign using DSA-SHA1 or Syndie DSA-SHA256 ONLY.
     383     *
    236384     *  @param hash either a Hash or a SHA1Hash
     385     *  @return null on error
    237386     *  @since 0.8.3
    238387     */
    239388    private Signature signIt(SimpleDataStructure hash, SigningPrivateKey signingKey) {
    240389        if ((signingKey == null) || (hash == null)) return null;
     390        if (signingKey.getType() != SigType.DSA_SHA1)
     391            throw new IllegalArgumentException("Bad key type " + signingKey.getType());
    241392        long start = _context.clock().now();
    242393
     
    276427                out[i] = rbytes[i + 1];
    277428            }
     429        } else if (rbytes.length > 21) {
     430            _log.error("Bad R length " + rbytes.length);
     431            return null;
    278432        } else {
    279             if (_log.shouldLog(Log.DEBUG)) _log.debug("Using short rbytes.length [" + rbytes.length + "]");
     433            //if (_log.shouldLog(Log.DEBUG)) _log.debug("Using short rbytes.length [" + rbytes.length + "]");
    280434            //System.arraycopy(rbytes, 0, out, 20 - rbytes.length, rbytes.length);
    281435            for (int i = 0; i < rbytes.length; i++)
     
    292446                out[i + 20] = sbytes[i + 1];
    293447            }
     448        } else if (sbytes.length > 21) {
     449            _log.error("Bad S length " + sbytes.length);
     450            return null;
    294451        } else {
    295             if (_log.shouldLog(Log.DEBUG)) _log.debug("Using short sbytes.length [" + sbytes.length + "]");
     452            //if (_log.shouldLog(Log.DEBUG)) _log.debug("Using short sbytes.length [" + sbytes.length + "]");
    296453            //System.arraycopy(sbytes, 0, out, 40 - sbytes.length, sbytes.length);
    297454            for (int i = 0; i < sbytes.length; i++)
     
    339496
    340497    /**
     498     *  Generic verify DSA_SHA1, ECDSA, or RSA
     499     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     500     *  @since 0.9.9
     501     */
     502    private boolean altVerifySig(Signature signature, byte[] data, SigningPublicKey verifyingKey)
     503                        throws GeneralSecurityException {
     504        SigType type = signature.getType();
     505        if (type != verifyingKey.getType())
     506            throw new IllegalArgumentException("type mismatch sig=" + type + " key=" + verifyingKey.getType());
     507        if (type == SigType.DSA_SHA1)
     508            return altVerifySigSHA1(signature, data, verifyingKey);
     509
     510        java.security.Signature jsig = java.security.Signature.getInstance(type.getAlgorithmName());
     511        PublicKey pubKey = SigUtil.toJavaKey(verifyingKey);
     512        jsig.initVerify(pubKey);
     513        jsig.update(data);
     514        boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
     515        return rv;
     516    }
     517
     518    /**
     519     *  Generic raw verify any type
     520     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     521     *  @since 0.9.9
     522     */
     523    private boolean altVerifySigRaw(Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey)
     524                        throws GeneralSecurityException {
     525        SigType type = signature.getType();
     526        if (type != verifyingKey.getType())
     527            throw new IllegalArgumentException("type mismatch sig=" + type + " key=" + verifyingKey.getType());
     528
     529        PublicKey pubKey = SigUtil.toJavaKey(verifyingKey);
     530        return verifySignature(signature, hash, pubKey);
     531    }
     532
     533    /**
     534     *  Generic raw verify any type.
     535     *  If you have a Java pubkey, use this, so you don't lose the key parameters,
     536     *  which may be different than the ones defined in SigType.
     537     *
     538     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     539     *  @param verifyingKey Java key
     540     *  @since 0.9.9
     541     */
     542    private boolean altVerifySigRaw(Signature signature, SimpleDataStructure hash, PublicKey pubKey)
     543                        throws GeneralSecurityException {
     544        SigType type = signature.getType();
     545        int hashlen = hash.length();
     546        if (type.getHashLen() != hashlen)
     547            throw new IllegalArgumentException("type mismatch hash=" + hash.getClass() + " key=" + type);
     548
     549        String algo = getRawAlgo(type);
     550        java.security.Signature jsig = java.security.Signature.getInstance(algo);
     551        jsig.initVerify(pubKey);
     552        jsig.update(hash.getData());
     553        boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
     554        return rv;
     555    }
     556
     557    /**
    341558     *  Alternate to verifySignature() using java.security libraries.
    342559     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     
    345562    private boolean altVerifySigSHA1(Signature signature, byte[] data, SigningPublicKey verifyingKey) throws GeneralSecurityException {
    346563        java.security.Signature jsig = java.security.Signature.getInstance("SHA1withDSA");
    347         KeyFactory keyFact = KeyFactory.getInstance("DSA");
    348         // y p q g
    349         KeySpec spec = new DSAPublicKeySpec(new NativeBigInteger(1, verifyingKey.getData()),
    350                                             CryptoConstants.dsap,
    351                                             CryptoConstants.dsaq,
    352                                             CryptoConstants.dsag);
    353         PublicKey pubKey = keyFact.generatePublic(spec);
     564        PublicKey pubKey = SigUtil.toJavaDSAKey(verifyingKey);
    354565        jsig.initVerify(pubKey);
    355566        jsig.update(data);
    356         boolean rv = jsig.verify(sigBytesToASN1(signature.getData()));
     567        boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
    357568        //if (!rv) {
    358569        //    System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(signature.getData()));
     
    363574
    364575    /**
     576     *  Generic sign DSA_SHA1, ECDSA, or RSA
     577     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     578     *  @since 0.9.9
     579     */
     580    private Signature altSign(byte[] data, SigningPrivateKey privateKey) throws GeneralSecurityException {
     581        SigType type = privateKey.getType();
     582        if (type == SigType.DSA_SHA1)
     583            return altSignSHA1(data, privateKey);
     584
     585        java.security.Signature jsig = java.security.Signature.getInstance(type.getAlgorithmName());
     586        PrivateKey privKey = SigUtil.toJavaKey(privateKey);
     587        jsig.initSign(privKey, _context.random());
     588        jsig.update(data);
     589        return SigUtil.fromJavaSig(jsig.sign(), type);
     590    }
     591
     592    /**
     593     *  Generic raw verify any type
     594     *  @param hash SHA1Hash, Hash, Hash384, or Hash512
     595     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     596     *  @since 0.9.9
     597     */
     598    private Signature altSignRaw(SimpleDataStructure hash, SigningPrivateKey privateKey) throws GeneralSecurityException {
     599        SigType type = privateKey.getType();
     600        String algo = getRawAlgo(type);
     601        java.security.Signature jsig = java.security.Signature.getInstance(algo);
     602        PrivateKey privKey = SigUtil.toJavaKey(privateKey);
     603        return altSignRaw(algo, hash, privKey, type);
     604    }
     605
     606    /**
     607     *  Generic raw verify any type
     608     *  @param hash SHA1Hash, Hash, Hash384, or Hash512
     609     *  @param type returns a Signature of this type
     610     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     611     *  @since 0.9.9
     612     */
     613    private Signature altSignRaw(String algo, SimpleDataStructure hash, PrivateKey privKey, SigType type)
     614                                 throws GeneralSecurityException {
     615        int hashlen = hash.length();
     616        if (type.getHashLen() != hashlen)
     617            throw new IllegalArgumentException("type mismatch hash=" + hash.getClass() + " key=" + type);
     618
     619        java.security.Signature jsig = java.security.Signature.getInstance(algo);
     620        jsig.initSign(privKey, _context.random());
     621        jsig.update(hash.getData());
     622        return SigUtil.fromJavaSig(jsig.sign(), type);
     623    }
     624
     625    /**
    365626     *  Alternate to sign() using java.security libraries.
    366627     *  @throws GeneralSecurityException if algorithm unvailable or on other errors
     
    369630    private Signature altSignSHA1(byte[] data, SigningPrivateKey privateKey) throws GeneralSecurityException {
    370631        java.security.Signature jsig = java.security.Signature.getInstance("SHA1withDSA");
    371         KeyFactory keyFact = KeyFactory.getInstance("DSA");
    372         // y p q g
    373         KeySpec spec = new DSAPrivateKeySpec(new NativeBigInteger(1, privateKey.getData()),
    374                                             CryptoConstants.dsap,
    375                                             CryptoConstants.dsaq,
    376                                             CryptoConstants.dsag);
    377         PrivateKey privKey = keyFact.generatePrivate(spec);
     632        PrivateKey privKey = SigUtil.toJavaDSAKey(privateKey);
    378633        jsig.initSign(privKey, _context.random());
    379634        jsig.update(data);
    380         return new Signature(aSN1ToSigBytes(jsig.sign()));
    381     }
    382 
    383     /**
    384      *  http://download.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html
    385      *  Signature Format        ASN.1 sequence of two INTEGER values: r and s, in that order:
    386      *                                SEQUENCE ::= { r INTEGER, s INTEGER }
    387      *
    388      *  http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
    389      *  30 -- tag indicating SEQUENCE
    390      *  xx - length in octets
    391      *
    392      *  02 -- tag indicating INTEGER
    393      *  xx - length in octets
    394      *  xxxxxx - value
    395      *
    396      *  Convert to BigInteger and back so we have the minimum length representation, as required.
    397      *  r and s are always non-negative.
    398      *
    399      *  @since 0.8.7
    400      */
    401     private static byte[] sigBytesToASN1(byte[] sig) {
    402         //System.out.println("pre TO asn1\n" + net.i2p.util.HexDump.dump(sig));
    403         ByteArrayOutputStream baos = new ByteArrayOutputStream(48);
    404         baos.write(0x30);
    405         baos.write(0);  // length to be filled in below
    406 
    407         byte[] tmp = new byte[20];
    408         baos.write(2);
    409         System.arraycopy(sig, 0, tmp, 0, 20);
    410         BigInteger r = new BigInteger(1, tmp);
    411         byte[] b = r.toByteArray();
    412         baos.write(b.length);
    413         baos.write(b, 0, b.length);
    414 
    415         baos.write(2);
    416         System.arraycopy(sig, 20, tmp, 0, 20);
    417         BigInteger s = new BigInteger(1, tmp);
    418         b = s.toByteArray();
    419         baos.write(b.length);
    420         baos.write(b, 0, b.length);
    421         byte[] rv = baos.toByteArray();
    422         rv[1] = (byte) (rv.length - 2);
    423         //System.out.println("post TO asn1\n" + net.i2p.util.HexDump.dump(rv));
    424         return rv;
    425     }
    426 
    427     /**
    428      *  See above.
    429      *  @since 0.8.7
    430      */
    431     private static byte[] aSN1ToSigBytes(byte[] asn) {
    432         //System.out.println("pre from asn1\n" + net.i2p.util.HexDump.dump(asn));
    433         byte[] rv = new byte[40];
    434         int rlen = asn[3];
    435         if ((asn[4] & 0x80) != 0)
    436             throw new IllegalArgumentException("R is negative");
    437         if (rlen > 21)
    438             throw new IllegalArgumentException("R too big " + rlen);
    439         else if (rlen == 21) {
    440             System.arraycopy(asn, 5, rv, 0, 20);
    441         } else
    442             System.arraycopy(asn, 4, rv, 20 - rlen, rlen);
    443         int slenloc = 25 + rlen - 20;
    444         int slen = asn[slenloc];
    445         if ((asn[slenloc + 1] & 0x80) != 0)
    446             throw new IllegalArgumentException("S is negative");
    447         if (slen > 21)
    448             throw new IllegalArgumentException("S too big " + slen);
    449         else if (slen == 21) {
    450             System.arraycopy(asn, slenloc + 2, rv, 20, 20);
    451         } else
    452             System.arraycopy(asn, slenloc + 1, rv, 40 - slen, slen);
    453         //System.out.println("post from asn1\n" + net.i2p.util.HexDump.dump(rv));
    454         return rv;
     635        return SigUtil.fromJavaSig(jsig.sign(), SigType.DSA_SHA1);
     636    }
     637
     638    /** @since 0.9.9 */
     639    private static String getRawAlgo(SigType type) {
     640        switch (type.getBaseAlgorithm()) {
     641            case DSA:
     642                return "NONEwithDSA";
     643            case EC:
     644                return "NONEwithECDSA";
     645            case RSA:
     646                return "NONEwithRSA";
     647            default:
     648                throw new IllegalArgumentException();
     649        }
     650    }
     651
     652    /** @since 0.9.9 */
     653    private static String getRawAlgo(Key key) {
     654        if (key instanceof DSAKey)
     655            return "NONEwithDSA";
     656        if (key instanceof ECKey)
     657            return "NONEwithECDSA";
     658        if (key instanceof RSAKey)
     659            return "NONEwithRSA";
     660        throw new IllegalArgumentException();
    455661    }
    456662
  • core/java/src/net/i2p/crypto/ElGamalEngine.java

    ra1c8e3e r6bb1505d  
    8282    public void shutdown() {
    8383        _ykgen.shutdown();
     84        SigUtil.clearCaches();
    8485    }
    8586
  • core/java/src/net/i2p/crypto/KeyGenerator.java

    ra1c8e3e r6bb1505d  
    1111
    1212import java.math.BigInteger;
     13import java.security.GeneralSecurityException;
     14import java.security.InvalidKeyException;
     15import java.security.KeyPair;
     16import java.security.KeyPairGenerator;
     17import java.security.ProviderException;
     18import java.security.interfaces.ECPrivateKey;
     19import java.security.interfaces.ECPublicKey;
     20import java.security.spec.ECPoint;
    1321
    1422import net.i2p.I2PAppContext;
     
    2028import net.i2p.data.SigningPublicKey;
    2129import net.i2p.data.SimpleDataStructure;
     30import net.i2p.util.Log;
    2231import net.i2p.util.NativeBigInteger;
    2332import net.i2p.util.SystemVersion;
     33
     34
     35// main()
     36import net.i2p.data.DataHelper;
     37import net.i2p.data.Signature;
     38import net.i2p.util.Clock;
     39import net.i2p.util.RandomSource;
    2440
    2541/** Define a way of generating asymmetrical key pairs as well as symmetrical keys
     
    130146        keys[0] = new PublicKey();
    131147        keys[1] = new PrivateKey();
    132         byte[] k0 = aalpha.toByteArray();
    133         byte[] k1 = a.toByteArray();
    134148
    135149        // bigInteger.toByteArray returns SIGNED integers, but since they'return positive,
    136150        // signed two's complement is the same as unsigned
    137151
    138         keys[0].setData(padBuffer(k0, PublicKey.KEYSIZE_BYTES));
    139         keys[1].setData(padBuffer(k1, PrivateKey.KEYSIZE_BYTES));
     152        try {
     153            keys[0].setData(SigUtil.rectify(aalpha, PublicKey.KEYSIZE_BYTES));
     154            keys[1].setData(SigUtil.rectify(a, PrivateKey.KEYSIZE_BYTES));
     155        } catch (InvalidKeyException ike) {
     156            throw new IllegalArgumentException(ike);
     157        }
    140158
    141159        return keys;
     
    150168        BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp);
    151169        PublicKey pub = new PublicKey();
    152         byte [] pubBytes = aalpha.toByteArray();
    153         pub.setData(padBuffer(pubBytes, PublicKey.KEYSIZE_BYTES));
     170        try {
     171            pub.setData(SigUtil.rectify(aalpha, PublicKey.KEYSIZE_BYTES));
     172        } catch (InvalidKeyException ike) {
     173            throw new IllegalArgumentException(ike);
     174        }
    154175        return pub;
    155176    }
    156177
    157178    /** Generate a pair of DSA keys, where index 0 is a SigningPublicKey, and
    158      * index 1 is a SigningPrivateKey
     179     * index 1 is a SigningPrivateKey.
     180     * DSA-SHA1 only.
     181     *
    159182     * @return pair of keys
    160183     */
     
    164187
    165188    /**
     189     *  DSA-SHA1 only.
     190     *
    166191     *  Same as above but different return type
    167192     *  @since 0.8.7
     
    179204        keys[0] = new SigningPublicKey();
    180205        keys[1] = new SigningPrivateKey();
    181         byte k0[] = padBuffer(y.toByteArray(), SigningPublicKey.KEYSIZE_BYTES);
    182         byte k1[] = padBuffer(x.toByteArray(), SigningPrivateKey.KEYSIZE_BYTES);
    183 
    184         keys[0].setData(k0);
    185         keys[1].setData(k1);
     206        try {
     207            keys[0].setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
     208            keys[1].setData(SigUtil.rectify(x, SigningPrivateKey.KEYSIZE_BYTES));
     209        } catch (InvalidKeyException ike) {
     210            throw new IllegalStateException(ike);
     211        }
    186212        return keys;
    187213    }
    188214
    189     /** Convert a SigningPrivateKey to a SigningPublicKey
     215    /**
     216     *  Generic signature type, supports DSA and ECDSA
     217     *  @since 0.9.9
     218     */
     219    public SimpleDataStructure[] generateSigningKeys(SigType type) throws GeneralSecurityException {
     220        if (type == SigType.DSA_SHA1)
     221            return generateSigningKeys();
     222        KeyPairGenerator kpg = KeyPairGenerator.getInstance(type.getBaseAlgorithm().getName());
     223        KeyPair kp;
     224        try {
     225            kpg.initialize(type.getParams(), _context.random());
     226            kp = kpg.generateKeyPair();
     227        } catch (ProviderException pe) {
     228            // java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_DOMAIN_PARAMS_INVALID
     229            // This is a RuntimeException, thx Sun
     230            // Fails for P-192 only, on Ubuntu
     231            Log log = _context.logManager().getLog(KeyGenerator.class);
     232            String pname = kpg.getProvider().getName();
     233            if ("BC".equals(pname)) {
     234                if (log.shouldLog(Log.WARN))
     235                    log.warn("BC KPG failed for " + type, pe);
     236                throw new GeneralSecurityException("BC KPG for " + type, pe);
     237            }
     238            if (!ECConstants.isBCAvailable())
     239                throw new GeneralSecurityException(pname + " KPG failed for " + type, pe);
     240            if (log.shouldLog(Log.WARN))
     241                log.warn(pname + " KPG failed for " + type + ", trying BC"  /* , pe */ );
     242            try {
     243                kpg = KeyPairGenerator.getInstance(type.getBaseAlgorithm().getName(), "BC");
     244                kpg.initialize(type.getParams(), _context.random());
     245                kp = kpg.generateKeyPair();
     246            } catch (ProviderException pe2) {
     247                if (log.shouldLog(Log.WARN))
     248                    log.warn("BC KPG failed for " + type + " also", pe2);
     249                // throw original exception
     250                throw new GeneralSecurityException(pname + " KPG for " + type, pe);
     251            } catch (GeneralSecurityException gse) {
     252                if (log.shouldLog(Log.WARN))
     253                    log.warn("BC KPG failed for " + type + " also", gse);
     254                // throw original exception
     255                throw new GeneralSecurityException(pname + " KPG for " + type, pe);
     256            }
     257        }
     258        java.security.PublicKey pubkey = kp.getPublic();
     259        java.security.PrivateKey privkey = kp.getPrivate();
     260        SimpleDataStructure[] keys = new SimpleDataStructure[2];
     261        keys[0] = SigUtil.fromJavaKey(pubkey, type);
     262        keys[1] = SigUtil.fromJavaKey(privkey, type);
     263        return keys;
     264    }
     265
     266    /** Convert a SigningPrivateKey to a SigningPublicKey.
     267     * DSA-SHA1 only.
     268     *
    190269     * @param priv a SigningPrivateKey object
    191270     * @return a SigningPublicKey object
     
    195274        BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
    196275        SigningPublicKey pub = new SigningPublicKey();
    197         byte [] pubBytes = padBuffer(y.toByteArray(), SigningPublicKey.KEYSIZE_BYTES);
    198         pub.setData(pubBytes);
     276        try {
     277            pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
     278        } catch (InvalidKeyException ike) {
     279            throw new IllegalArgumentException(ike);
     280        }
    199281        return pub;
    200282    }
    201283
    202     /**
    203      * Pad the buffer w/ leading 0s or trim off leading bits so the result is the
    204      * given length. 
    205      */
    206     private final static byte[] padBuffer(byte src[], int length) {
    207         byte buf[] = new byte[length];
    208 
    209         if (src.length > buf.length) // extra bits, chop leading bits
    210             System.arraycopy(src, src.length - buf.length, buf, 0, buf.length);
    211         else if (src.length < buf.length) // short bits, padd w/ 0s
    212             System.arraycopy(src, 0, buf, buf.length - src.length, src.length);
    213         else
    214             // eq
    215             System.arraycopy(src, 0, buf, 0, buf.length);
    216 
    217         return buf;
     284    public static void main(String args[]) {
     285        try {
     286             main2(args);
     287        } catch (Exception e) {
     288             e.printStackTrace();
     289        }
     290    }
     291
     292    public static void main2(String args[]) {
     293        RandomSource.getInstance().nextBoolean();
     294        try { Thread.sleep(1000); } catch (InterruptedException ie) {}
     295        int runs = 200; // warmup
     296        for (int j = 0; j < 2; j++) {
     297            for (int i = 0; i <= 100; i++) {
     298                SigType type = SigType.getByCode(i);
     299                if (type == null)
     300                    break;
     301                try {
     302                    System.out.println("Testing " + type);
     303                    testSig(type, runs);
     304                } catch (Exception e) {
     305                    System.out.println("error testing " + type);
     306                    e.printStackTrace();
     307                }
     308            }
     309            runs = 1000;
     310        }
     311    }
     312
     313    private static void testSig(SigType type, int runs) throws GeneralSecurityException {
     314        byte src[] = new byte[512];
     315        long stime = 0;
     316        long vtime = 0;
     317        SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
     318        //System.out.println("pubkey " + keys[0]);
     319        //System.out.println("privkey " + keys[1]);
     320        for (int i = 0; i < runs; i++) {
     321            RandomSource.getInstance().nextBytes(src);
     322            long start = System.nanoTime();
     323            Signature sig = DSAEngine.getInstance().sign(src, (SigningPrivateKey) keys[1]);
     324            long mid = System.nanoTime();
     325            boolean ok = DSAEngine.getInstance().verifySignature(sig, src, (SigningPublicKey) keys[0]);
     326            long end = System.nanoTime();
     327            stime += mid - start;
     328            vtime += end - mid;
     329            if (!ok)
     330                throw new GeneralSecurityException(type + " V(S(data)) fail");
     331        }
     332        stime /= 1000*1000;
     333        vtime /= 1000*1000;
     334        System.out.println(type + " sign/verify " + runs + " times: " + (vtime+stime) + " ms = " +
     335                           (((double) stime) / runs) + " each sign, " +
     336                           (((double) vtime) / runs) + " each verify, " +
     337                           (((double) (stime + vtime)) / runs) + " s+v");
    218338    }
    219339
  • core/java/src/net/i2p/crypto/SHA1Hash.java

    ra1c8e3e r6bb1505d  
    2626
    2727    public final static int HASH_LENGTH = SHA1.HASH_LENGTH;
     28   
     29    /** @since 0.9.9 */
     30    public SHA1Hash() {
     31        super();
     32    }
    2833   
    2934    /** @throws IllegalArgumentException if data is not 20 bytes (null is ok) */
  • core/java/src/net/i2p/crypto/SU3File.java

    ra1c8e3e r6bb1505d  
    1212import java.security.DigestInputStream;
    1313import java.security.DigestOutputStream;
     14import java.security.GeneralSecurityException;
    1415import java.security.MessageDigest;
     16import java.security.PrivateKey;
     17import java.security.PublicKey;
     18import java.util.ArrayList;
     19import java.util.Arrays;
     20import java.util.EnumSet;
    1521import java.util.HashMap;
     22import java.util.Iterator;
     23import java.util.List;
     24import java.util.Locale;
    1625import java.util.Map;
     26import java.util.NoSuchElementException;
     27import java.util.Properties;
    1728
    1829import net.i2p.I2PAppContext;
     
    2233import net.i2p.data.SigningPrivateKey;
    2334import net.i2p.data.SigningPublicKey;
     35import net.i2p.data.SimpleDataStructure;
     36import net.i2p.util.HexDump;
     37import net.i2p.util.SecureFileOutputStream;
    2438
    2539/**
     
    3246
    3347    private final I2PAppContext _context;
    34     private final Map<SigningPublicKey, String> _trustedKeys;
    3548
    3649    private final File _file;
     
    3952    private String _signer;
    4053    private int _signerLength;
    41     private int _contentType;
     54    private ContentType _contentType;
    4255    private long _contentLength;
    43     private SigningPublicKey _signerPubkey;
     56    private PublicKey _signerPubkey;
    4457    private boolean _headerVerified;
     58    private SigType _sigType;
    4559
    4660    private static final byte[] MAGIC = DataHelper.getUTF8("I2Psu3");
    4761    private static final int FILE_VERSION = 0;
    4862    private static final int MIN_VERSION_BYTES = 16;
    49     private static final int VERSION_OFFSET = Signature.SIGNATURE_BYTES;
     63    private static final int VERSION_OFFSET = 40; // Signature.SIGNATURE_BYTES; avoid early ctx init
    5064
    5165    private static final int TYPE_ZIP = 0;
    5266
    53     private static final int CONTENT_ROUTER = 0;
    54     private static final int CONTENT_ROUTER_P200 = 1;
    55     private static final int CONTENT_PLUGIN = 2;
    56     private static final int CONTENT_RESEED = 3;
    57 
    58     private static final int SIG_DSA_160 = SigType.DSA_SHA1.getCode();
    59 
    60     /**
    61      *  Uses TrustedUpdate's default keys for verification.
     67    public static final int CONTENT_UNKNOWN = 0;
     68    public static final int CONTENT_ROUTER = 1;
     69    public static final int CONTENT_PLUGIN = 2;
     70    public static final int CONTENT_RESEED = 3;
     71
     72    private enum ContentType {
     73        UNKNOWN(CONTENT_UNKNOWN, "unknown"),
     74        ROUTER(CONTENT_ROUTER, "router"),
     75        PLUGIN(CONTENT_PLUGIN, "plugin"),
     76        RESEED(CONTENT_RESEED, "reseed")
     77        ;
     78
     79        private final int code;
     80        private final String name;
     81
     82        ContentType(int code, String name) {
     83            this.code = code;
     84            this.name = name;
     85        }
     86        public int getCode() { return code; }
     87        public String getName() { return name; }
     88
     89        /** @return null if not supported */
     90        public static ContentType getByCode(int code) {
     91            return BY_CODE.get(Integer.valueOf(code));
     92        }
     93    }
     94
     95    private static final Map<Integer, ContentType> BY_CODE = new HashMap<Integer, ContentType>();
     96
     97    static {
     98        for (ContentType type : ContentType.values()) {
     99            BY_CODE.put(Integer.valueOf(type.getCode()), type);
     100        }
     101    }
     102
     103    private static final ContentType DEFAULT_CONTENT_TYPE = ContentType.UNKNOWN;
     104    // avoid early ctx init
     105    //private static final SigType DEFAULT_SIG_TYPE = SigType.DSA_SHA1;
     106    private static final int DEFAULT_SIG_CODE = 0;
     107
     108    /**
     109     *
    62110     */
    63111    public SU3File(String file) {
     
    66114
    67115    /**
    68      *  Uses TrustedUpdate's default keys for verification.
     116     *
    69117     */
    70118    public SU3File(File file) {
    71         this(file, (new TrustedUpdate()).getKeys());
    72     }
    73 
    74     /**
    75      *  @param trustedKeys map of pubkey to signer name, null ok if not verifying
    76      */
    77     public SU3File(File file, Map<SigningPublicKey, String> trustedKeys) {
    78         this(I2PAppContext.getGlobalContext(), file, trustedKeys);
    79     }
    80 
    81     /**
    82      *  @param trustedKeys map of pubkey to signer name, null ok if not verifying
    83      */
    84     public SU3File(I2PAppContext context, File file, Map<SigningPublicKey, String> trustedKeys) {
     119        this(I2PAppContext.getGlobalContext(), file);
     120    }
     121
     122    /**
     123     *
     124     */
     125    public SU3File(I2PAppContext context, File file) {
    85126        _context = context;
    86127        _file = file;
    87         _trustedKeys = trustedKeys;
    88128    }
    89129
     
    96136        verifyHeader();
    97137        return _signer;
     138    }
     139
     140    /**
     141     *  @return null if unknown
     142     *  @since 0.9.9
     143     */
     144    public SigType getSigType() throws IOException {
     145        verifyHeader();
     146        return _sigType;
     147    }
     148
     149    /**
     150     *  @return -1 if unknown
     151     *  @since 0.9.9
     152     */
     153    public int getContentType() throws IOException {
     154        verifyHeader();
     155        return _contentType != null ? _contentType.getCode() : -1;
    98156    }
    99157
     
    129187        if (foo != FILE_VERSION)
    130188            throw new IOException("bad file version");
    131         skip(in, 1);
    132         int sigType = in.read();
    133         // TODO, for other known algos we must start over with a new MessageDigest
    134         // (rewind 10 bytes)
    135         if (sigType != SIG_DSA_160)
    136             throw new IOException("bad sig type");
     189        int sigTypeCode = (int) DataHelper.readLong(in, 2);
     190        _sigType = SigType.getByCode(sigTypeCode);
     191        // In verifyAndMigrate it reads this far then rewinds, but we don't need to here
     192        if (_sigType == null)
     193            throw new IOException("unknown sig type: " + sigTypeCode);
    137194        _signerLength = (int) DataHelper.readLong(in, 2);
    138         if (_signerLength != Signature.SIGNATURE_BYTES)
     195        if (_signerLength != _sigType.getSigLen())
    139196            throw new IOException("bad sig length");
    140197        skip(in, 1);
     
    154211            throw new IOException("bad type");
    155212        skip(in, 1);
    156         _contentType = in.read();
    157         if (_contentType < CONTENT_ROUTER || _contentType > CONTENT_RESEED)
    158             throw new IOException("bad content type");
     213        int cType = in.read();
     214        _contentType = BY_CODE.get(Integer.valueOf(cType));
     215        if (_contentType == null)
     216            throw new IOException("unknown content type " + cType);
    159217        skip(in, 12);
    160218
     
    175233            throw new EOFException();
    176234        _signer = DataHelper.getUTF8(data);
    177         if (_trustedKeys != null) {
    178             for (Map.Entry<SigningPublicKey, String> e : _trustedKeys.entrySet()) {
    179                 if (e.getValue().equals(_signer)) {
    180                     _signerPubkey = e.getKey();
    181                     break;
    182                 }
    183             }
    184             if (_signerPubkey == null)
    185                 throw new IOException("unknown signer: " + _signer);
    186         }
     235
     236        KeyRing ring = new DirKeyRing(new File(_context.getBaseDir(), "certificates"));
     237        try {
     238            _signerPubkey = ring.getKey(_signer, _contentType.getName(), _sigType);
     239        } catch (GeneralSecurityException gse) {
     240            IOException ioe = new IOException("keystore error");
     241            ioe.initCause(gse);
     242            throw ioe;
     243        }
     244
     245        if (_signerPubkey == null)
     246            throw new IOException("unknown signer: " + _signer);
    187247        _headerVerified = true;
    188248    }
     
    202262
    203263    /**
     264     *  One-pass verify.
     265     *  Throws IOE on all format errors.
     266     *
     267     *  @return true if signature is good
     268     *  @since 0.9.9
     269     */
     270    public boolean verify() throws IOException {
     271        return verifyAndMigrate(null);
     272    }
     273
     274    /**
    204275     *  One-pass verify and extract the content.
    205276     *  Recommend extracting to a temp location as the sig is not checked until
     
    207278     *  Throws IOE on all format errors.
    208279     *
    209      *  @param migrateTo the output file, probably in zip format
     280     *  @param migrateTo the output file, probably in zip format. Null for verify only.
    210281     *  @return true if signature is good
    211282     */
    212283    public boolean verifyAndMigrate(File migrateTo) throws IOException {
    213         DigestInputStream in = null;
     284        InputStream in = null;
    214285        OutputStream out = null;
    215286        boolean rv = false;
    216287        try {
    217             MessageDigest md = SHA1.getInstance();
    218             in = new DigestInputStream(new BufferedInputStream(new FileInputStream(_file)), md);
     288            in = new BufferedInputStream(new FileInputStream(_file));
     289            // read 10 bytes to get the sig type
     290            in.mark(10);
     291            // following is a dup of that in verifyHeader()
     292            byte[] magic = new byte[MAGIC.length];
     293            DataHelper.read(in, magic);
     294            if (!DataHelper.eq(magic, MAGIC))
     295                throw new IOException("Not an su3 file");
     296            skip(in, 1);
     297            int foo = in.read();
     298            if (foo != FILE_VERSION)
     299                throw new IOException("bad file version");
     300            skip(in, 1);
     301            int sigTypeCode = in.read();
     302            _sigType = SigType.getByCode(sigTypeCode);
     303            if (_sigType == null)
     304                throw new IOException("unknown sig type: " + sigTypeCode);
     305            // end duplicate code
     306            // rewind
     307            in.reset();
     308            MessageDigest md = _sigType.getDigestInstance();
     309            DigestInputStream din = new DigestInputStream(in, md);
     310            in = din;
    219311            if (!_headerVerified)
    220312                verifyHeader(in);
     
    223315            if (_signerPubkey == null)
    224316                throw new IOException("unknown signer: " + _signer);
    225             out = new FileOutputStream(migrateTo);
     317            if (migrateTo != null)  // else verify only
     318                out = new FileOutputStream(migrateTo);
    226319            byte[] buf = new byte[16*1024];
    227320            long tot = 0;
     
    230323                if (read < 0)
    231324                    throw new EOFException();
    232                 out.write(buf, 0, read);
     325                if (migrateTo != null)  // else verify only
     326                    out.write(buf, 0, read);
    233327                tot += read;
    234328            }
    235329            byte[] sha = md.digest();
    236             in.on(false);
    237             Signature signature = new Signature();
     330            din.on(false);
     331            Signature signature = new Signature(_sigType);
    238332            signature.readBytes(in);
    239             SHA1Hash hash = new SHA1Hash(sha);
     333            SimpleDataStructure hash = _sigType.getHashInstance();
     334            hash.setData(sha);
     335            //System.out.println("hash\n" + HexDump.dump(sha));
     336            //System.out.println("sig\n" + HexDump.dump(signature.getData()));
    240337            rv = _context.dsa().verifySignature(signature, hash, _signerPubkey);
    241338        } catch (DataFormatException dfe) {
     
    246343            if (in != null) try { in.close(); } catch (IOException ioe) {}
    247344            if (out != null) try { out.close(); } catch (IOException ioe) {}
    248             if (!rv)
     345            if (migrateTo != null && !rv)
    249346                migrateTo.delete();
    250347        }
     
    263360     */
    264361    public void write(File content, int contentType, String version,
    265                       String signer, SigningPrivateKey privkey) throws IOException {
     362                      String signer, PrivateKey privkey, SigType sigType) throws IOException {
    266363        InputStream in = null;
    267364        DigestOutputStream out = null;
     
    269366        try {
    270367            in = new BufferedInputStream(new FileInputStream(content));
    271             MessageDigest md = SHA1.getInstance();
     368            MessageDigest md = sigType.getDigestInstance();
    272369            out = new DigestOutputStream(new BufferedOutputStream(new FileOutputStream(_file)), md);
    273370            out.write(MAGIC);
    274371            out.write((byte) 0);
    275372            out.write((byte) FILE_VERSION);
    276             out.write((byte) 0);
    277             out.write((byte) SIG_DSA_160);
    278             DataHelper.writeLong(out, 2, Signature.SIGNATURE_BYTES);
     373            DataHelper.writeLong(out, 2, sigType.getCode());
     374            DataHelper.writeLong(out, 2, sigType.getSigLen());
    279375            out.write((byte) 0);
    280376            byte[] verBytes = DataHelper.getUTF8(version);
     
    316412            byte[] sha = md.digest();
    317413            out.on(false);
    318             SHA1Hash hash = new SHA1Hash(sha);
    319             Signature signature = _context.dsa().sign(hash, privkey);
     414            SimpleDataStructure hash = sigType.getHashInstance();
     415            hash.setData(sha);
     416            Signature signature = _context.dsa().sign(hash, privkey, sigType);
     417            if (signature == null)
     418                throw new IOException("sig fail");
     419            //System.out.println("hash\n" + HexDump.dump(sha));
     420            //System.out.println("sig\n" + HexDump.dump(signature.getData()));
    320421            signature.writeBytes(out);
    321422            ok = true;
     
    341442    public static void main(String[] args) {
    342443        boolean ok = false;
    343         try {
    344             if ("showversion".equals(args[0])) {
    345                 ok = showVersionCLI(args[1]);
    346             } else if ("sign".equals(args[0])) {
    347                 ok = signCLI(args[1], args[2], args[3], args[4], args[5]);
    348             } else if ("verifysig".equals(args[0])) {
    349                 ok = verifySigCLI(args[1]);
     444        List<String> a = new ArrayList(Arrays.asList(args));
     445        try {
     446            // defaults
     447            String stype = null;
     448            String ctype = null;
     449            Iterator<String> iter = a.iterator();
     450            String cmd = iter.next();
     451            iter.remove();
     452            for ( ; iter.hasNext(); ) {
     453                String arg = iter.next();
     454                if (arg.equals("-t")) {
     455                    iter.remove();
     456                    stype = iter.next();
     457                    iter.remove();
     458                } else if (arg.equals("-c")) {
     459                    iter.remove();
     460                    ctype = iter.next();
     461                    iter.remove();
     462                }
     463            }
     464            if ("showversion".equals(cmd)) {
     465                ok = showVersionCLI(a.get(0));
     466            } else if ("sign".equals(cmd)) {
     467                // speed things up by specifying a small PRNG buffer size
     468                Properties props = new Properties();
     469                props.setProperty("prng.bufferSize", "16384");
     470                new I2PAppContext(props);
     471                ok = signCLI(stype, ctype, a.get(0), a.get(1), a.get(2), a.get(3), a.get(4));
     472            } else if ("verifysig".equals(cmd)) {
     473                ok = verifySigCLI(a.get(0));
     474            } else if ("keygen".equals(cmd)) {
     475                ok = genKeysCLI(stype, a.get(0), a.get(1), a.get(2));
     476            } else if ("extract".equals(cmd)) {
     477                ok = extractCLI(a.get(0), a.get(1));
    350478            } else {
    351479                showUsageCLI();
    352480            }
    353         } catch (ArrayIndexOutOfBoundsException aioobe) {
     481        } catch (NoSuchElementException nsee) {
     482            showUsageCLI();
     483        } catch (IndexOutOfBoundsException ioobe) {
    354484            showUsageCLI();
    355485        }
     
    359489
    360490    private static final void showUsageCLI() {
    361         System.err.println("Usage: SU3File showversion   signedFile.su3");
    362         System.err.println("       SU3File sign          inputFile.zip signedFile.su3 privateKeyFile version signerName@mail.i2p");
    363         System.err.println("       SU3File verifysig     signedFile.su3");
     491        System.err.println("Usage: SU3File keygen       [-t type|code] publicKeyFile keystore.ks you@mail.i2p");
     492        System.err.println("       SU3File sign         [-c type|code] [-t type|code] inputFile.zip signedFile.su3 keystore.ks version you@mail.i2p");
     493        System.err.println("       SU3File showversion  signedFile.su3");
     494        System.err.println("       SU3File verifysig    signedFile.su3");
     495        System.err.println("       SU3File extract      signedFile.su3 outFile.zip");
     496        System.err.println(dumpTypes());
     497    }
     498
     499    /** @since 0.9.9 */
     500    private static String dumpTypes() {
     501        StringBuilder buf = new StringBuilder(256);
     502        buf.append("Available signature types:\n");
     503        for (SigType t : EnumSet.allOf(SigType.class)) {
     504            buf.append("      ").append(t).append("\t(code: ").append(t.getCode()).append(')');
     505            if (t.getCode() == DEFAULT_SIG_CODE)
     506                buf.append(" DEFAULT");
     507            buf.append('\n');
     508        }
     509        buf.append("Available content types:\n");
     510        for (ContentType t : EnumSet.allOf(ContentType.class)) {
     511            buf.append("      ").append(t).append("\t(code: ").append(t.getCode()).append(')');
     512            if (t == DEFAULT_CONTENT_TYPE)
     513                buf.append(" DEFAULT");
     514            buf.append('\n');
     515        }
     516        return buf.toString();
     517    }
     518
     519    /**
     520     *  @param stype number or name
     521     *  @return null if not found
     522     *  @since 0.9.9
     523     */
     524    private static SigType parseSigType(String stype) {
     525        try {
     526            return SigType.valueOf(stype.toUpperCase(Locale.US));
     527        } catch (IllegalArgumentException iae) {
     528            try {
     529                int code = Integer.parseInt(stype);
     530                return SigType.getByCode(code);
     531            } catch (NumberFormatException nfe) {
     532                return null;
     533             }
     534        }
     535    }
     536    /**
     537     *  @param stype number or name
     538     *  @return null if not found
     539     *  @since 0.9.9
     540     */
     541    private static ContentType parseContentType(String ctype) {
     542        try {
     543            return ContentType.valueOf(ctype.toUpperCase(Locale.US));
     544        } catch (IllegalArgumentException iae) {
     545            try {
     546                int code = Integer.parseInt(ctype);
     547                return ContentType.getByCode(code);
     548            } catch (NumberFormatException nfe) {
     549                return null;
     550             }
     551        }
    364552    }
    365553
     
    367555    private static final boolean showVersionCLI(String signedFile) {
    368556        try {
    369             SU3File file = new SU3File(new File(signedFile), null);
     557            SU3File file = new SU3File(signedFile);
    370558            String versionString = file.getVersionString();
    371559            if (versionString.equals(""))
    372560                System.out.println("No version string found in file '" + signedFile + "'");
    373561            else
    374                 System.out.println("Version: " + versionString);
     562                System.out.println("Version:  " + versionString);
     563            String signerString = file.getSignerString();
     564            if (signerString.equals(""))
     565                System.out.println("No signer string found in file '" + signedFile + "'");
     566            else
     567                System.out.println("Signer:   " + signerString);
     568            if (file._sigType != null)
     569                System.out.println("SigType:  " + file._sigType);
    375570            return !versionString.equals("");
    376571        } catch (IOException ioe) {
     
    380575    }
    381576
    382     /** @return success */
    383     private static final boolean signCLI(String inputFile, String signedFile, String privateKeyFile,
    384                                          String version, String signerName) {
    385         InputStream in = null;
    386         try {
    387             in = new FileInputStream(privateKeyFile);
    388             SigningPrivateKey spk = new SigningPrivateKey();
    389             spk.readBytes(in);
    390             in.close();
     577    /**
     578     *  @return success
     579     *  @since 0.9.9
     580     */
     581    private static final boolean signCLI(String stype, String ctype, String inputFile, String signedFile,
     582                                         String privateKeyFile, String version, String signerName) {
     583        SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : parseSigType(stype);
     584        if (type == null) {
     585            System.out.println("Signature type " + stype + " is not supported");
     586            return false;
     587        }
     588        ContentType ct = ctype == null ? DEFAULT_CONTENT_TYPE : parseContentType(ctype);
     589        if (ct == null) {
     590            System.out.println("Content type " + ctype + " is not supported");
     591            return false;
     592        }
     593        return signCLI(type, ct, inputFile, signedFile, privateKeyFile, version, signerName);
     594    }
     595
     596    /**
     597     *  @return success
     598     *  @since 0.9.9
     599     */
     600    private static final boolean signCLI(SigType type, ContentType ctype, String inputFile, String signedFile,
     601                                         String privateKeyFile, String version, String signerName) {
     602        try {
     603            String keypw = "";
     604            while (keypw.length() < 6) {
     605                System.out.print("Enter password for key \"" + signerName + "\": ");
     606                keypw = DataHelper.readLine(System.in).trim();
     607                if (keypw.length() > 0 && keypw.length() < 6)
     608                    System.out.println("Key password must be at least 6 characters");
     609            }
     610            File pkfile = new File(privateKeyFile);
     611            PrivateKey pk = KeyStoreUtil.getPrivateKey(pkfile,KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, signerName, keypw);
     612            if (pk == null) {
     613                System.out.println("Private key for " + signerName + " not found in keystore " + privateKeyFile);
     614                return false;
     615            }
    391616            SU3File file = new SU3File(signedFile);
    392             file.write(new File(inputFile), CONTENT_ROUTER, version, signerName, spk);
     617            file.write(new File(inputFile), ctype.getCode(), version, signerName, pk, type);
    393618            System.out.println("Input file '" + inputFile + "' signed and written to '" + signedFile + "'");
    394619            return true;
    395         } catch (DataFormatException dfe) {
     620        } catch (GeneralSecurityException gse) {
    396621            System.out.println("Error signing input file '" + inputFile + "'");
    397             dfe.printStackTrace();
     622            gse.printStackTrace();
    398623            return false;
    399624        } catch (IOException ioe) {
     
    401626            ioe.printStackTrace();
    402627            return false;
    403         } finally {
    404             if (in != null) try { in.close(); } catch (IOException ioe) {}
    405628        }
    406629    }
     
    411634        try {
    412635            SU3File file = new SU3File(signedFile);
    413             boolean isValidSignature = file.verifyAndMigrate(new File("/dev/null"));
     636            boolean isValidSignature = file.verify();
    414637            if (isValidSignature)
    415                 System.out.println("Signature VALID (signed by " + file.getSignerString() + ')');
     638                System.out.println("Signature VALID (signed by " + file.getSignerString() + ' ' + file._sigType + ')');
    416639            else
    417                 System.out.println("Signature INVALID (signed by " + file.getSignerString() + ')');
     640                System.out.println("Signature INVALID (signed by " + file.getSignerString() + ' ' + file._sigType +')');
    418641            return isValidSignature;
    419642        } catch (IOException ioe) {
     
    423646        }
    424647    }
     648
     649    /**
     650     *  @return success
     651     *  @since 0.9.9
     652     */
     653    private static final boolean extractCLI(String signedFile, String outFile) {
     654        InputStream in = null;
     655        try {
     656            SU3File file = new SU3File(signedFile);
     657            File out = new File(outFile);
     658            boolean ok = file.verifyAndMigrate(out);
     659            if (ok)
     660                System.out.println("File extracted (signed by " + file.getSignerString() + ' ' + file._sigType + ')');
     661            else
     662                System.out.println("Signature INVALID (signed by " + file.getSignerString() + ' ' + file._sigType +')');
     663            return ok;
     664        } catch (IOException ioe) {
     665            System.out.println("Error extracting from file '" + signedFile + "'");
     666            ioe.printStackTrace();
     667            return false;
     668        }
     669    }
     670
     671    /**
     672     *  @return success
     673     *  @since 0.9.9
     674     */
     675    private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile, String alias) {
     676        SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : parseSigType(stype);
     677        if (type == null) {
     678            System.out.println("Signature type " + stype + " is not supported");
     679            return false;
     680        }
     681        return genKeysCLI(type, publicKeyFile, privateKeyFile, alias);
     682    }
     683
     684    /**
     685     *  Writes Java-encoded keys (X.509 for public and PKCS#8 for private)
     686     *  @return success
     687     *  @since 0.9.9
     688     */
     689    private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile, String alias) {
     690        File pubFile = new File(publicKeyFile);
     691        if (pubFile.exists()) {
     692            System.out.println("Error: Not overwriting file " + publicKeyFile);
     693            return false;
     694        }
     695        File ksFile = new File(privateKeyFile);
     696        String keypw = "";
     697        try {
     698            while (alias.length() == 0) {
     699                System.out.print("Enter key name (example@mail.i2p): ");
     700                alias = DataHelper.readLine(System.in).trim();
     701            }
     702            while (keypw.length() < 6) {
     703                System.out.print("Enter new key password: ");
     704                keypw = DataHelper.readLine(System.in).trim();
     705                if (keypw.length() > 0 && keypw.length() < 6)
     706                    System.out.println("Key password must be at least 6 characters");
     707            }
     708        } catch (IOException ioe) {
     709            return false;
     710        }
     711        int keylen = type.getPubkeyLen() * 8;
     712        if (type.getBaseAlgorithm() == SigAlgo.EC) {
     713            keylen /= 2;
     714            if (keylen == 528)
     715                keylen = 521;
     716        }
     717        boolean success = KeyStoreUtil.createKeys(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias,
     718                                                  alias, "I2P", 3652, type.getBaseAlgorithm().getName(),
     719                                                  keylen, keypw);
     720        if (!success) {
     721            System.err.println("Error creating keys for " + alias);
     722            return false;
     723        }
     724        File outfile = new File(publicKeyFile);
     725        success = KeyStoreUtil.exportCert(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias, outfile);
     726        if (!success) {
     727            System.err.println("Error writing public key for " + alias + " to " + outfile);
     728            return false;
     729        }
     730        return true;
     731    }
    425732}
  • core/java/src/net/i2p/crypto/SigType.java

    ra1c8e3e r6bb1505d  
    77import java.util.HashMap;
    88import java.util.Map;
     9
     10import net.i2p.data.Hash;
     11import net.i2p.data.SimpleDataStructure;
    912
    1013/**
     
    2427     *  @since 0.9.8
    2528     */
    26     DSA_SHA1(0, 128, 20, 20, 40, "SHA-1", "SHA1withDSA", null),
     29    DSA_SHA1(0, 128, 20, 20, 40, SigAlgo.DSA, "SHA-1", "SHA1withDSA", CryptoConstants.DSA_SHA1_SPEC),
     30    /**  Pubkey 64 bytes; privkey 32 bytes; hash 32 bytes; sig 64 bytes */
     31    ECDSA_SHA256_P256(1, 64, 32, 32, 64, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.P256_SPEC),
     32    /**  Pubkey 96 bytes; privkey 48 bytes; hash 48 bytes; sig 96 bytes */
     33    ECDSA_SHA384_P384(2, 96, 48, 48, 96, SigAlgo.EC, "SHA-384", "SHA384withECDSA", ECConstants.P384_SPEC),
     34    /**  Pubkey 132 bytes; privkey 66 bytes; hash 64 bytes; sig 132 bytes */
     35    ECDSA_SHA512_P521(3, 132, 66, 64, 132, SigAlgo.EC, "SHA-512", "SHA512withECDSA", ECConstants.P521_SPEC),
     36
     37    /**  Pubkey 256 bytes; privkey 512 bytes; hash 32 bytes; sig 256 bytes */
     38    RSA_SHA256_2048(4, 256, 512, 32, 256, SigAlgo.RSA, "SHA-256", "SHA256withRSA", RSAConstants.F4_2048_SPEC),
     39    /**  Pubkey 384 bytes; privkey 768 bytes; hash 48 bytes; sig 384 bytes */
     40    RSA_SHA384_3072(5, 384, 768, 48, 384, SigAlgo.RSA, "SHA-384", "SHA384withRSA", RSAConstants.F4_3072_SPEC),
     41    /**  Pubkey 512 bytes; privkey 1024 bytes; hash 64 bytes; sig 512 bytes */
     42    RSA_SHA512_4096(6, 512, 1024, 64, 512, SigAlgo.RSA, "SHA-512", "SHA512withRSA", RSAConstants.F4_4096_SPEC),
     43
     44
     45
     46    // TESTING....................
     47
     48
     49
     50    // others..........
     51
     52    // EC mix and match
     53    //ECDSA_SHA256_P192(5, 48, 24, 32, 48, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.P192_SPEC),
     54    //ECDSA_SHA256_P384(6, 96, 48, 32, 96, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.P384_SPEC),
     55    //ECDSA_SHA256_P521(7, 132, 66, 32, 132, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.P521_SPEC),
     56    //ECDSA_SHA384_P256(8, 64, 32, 48, 64, SigAlgo.EC, "SHA-384", "SHA384withECDSA", ECConstants.P256_SPEC),
     57    //ECDSA_SHA384_P521(9, 132, 66, 48, 132, SigAlgo.EC, "SHA-384", "SHA384withECDSA", ECConstants.P521_SPEC),
     58    //ECDSA_SHA512_P256(10, 64, 32, 64, 64, SigAlgo.EC, "SHA-512", "SHA512withECDSA", ECConstants.P256_SPEC),
     59    //ECDSA_SHA512_P384(11, 96, 48, 64, 96, SigAlgo.EC, "SHA-512", "SHA512withECDSA", ECConstants.P384_SPEC),
     60
     61    // Koblitz
     62    //ECDSA_SHA256_K163(12, 42, 21, 32, 42, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.K163_SPEC),
     63    //ECDSA_SHA256_K233(13, 60, 30, 32, 60, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.K233_SPEC),
     64    //ECDSA_SHA256_K283(14, 72, 36, 32, 72, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.K283_SPEC),
     65    //ECDSA_SHA256_K409(15, 104, 52, 32, 104, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.K409_SPEC),
     66    //ECDSA_SHA256_K571(16, 144, 72, 32, 144, SigAlgo.EC, "SHA-256", "SHA256withECDSA", ECConstants.K571_SPEC),
     67
     68    // too short..............
    2769    /**  Pubkey 48 bytes; privkey 24 bytes; hash 20 bytes; sig 48 bytes */
    28     ECDSA_SHA1_P192(1, 48, 24, 20, 48, "SHA-1", "SHA1withECDSA", null),
    29     /**  Pubkey 64 bytes; privkey 32 bytes; hash 32 bytes; sig 64 bytes */
    30     ECDSA_SHA256_P256(2, 64, 32, 32, 64, "SHA-256", "SHA256withECDSA", null),
    31     /**  Pubkey 96 bytes; privkey 48 bytes; hash 48 bytes; sig 96 bytes */
    32     ECDSA_SHA384_P384(3, 96, 48, 48, 96, "SHA-384", "SHA384withECDSA", null),
    33     /**  Pubkey 132 bytes; privkey 66 bytes; hash 64 bytes; sig 132 bytes */
    34     ECDSA_SHA512_P521(4, 132, 66, 64, 132, "SHA-512", "SHA512withECDSA", null),
     70    //ECDSA_SHA1_P192(1, 48, 24, 20, 48, SigAlgo.EC, "SHA-1", "SHA1withECDSA", ECConstants.P192_SPEC),
     71    //RSA_SHA1(17, 128, 256, 20, 128, SigAlgo.RSA, "SHA-1", "SHA1withRSA", RSAConstants.F4_1024_SPEC),
     72    //MD5
     73    //RSA_SHA1
    3574
    36     //MD5
    3775    //ELGAMAL_SHA256
    38     //RSA_SHA1
    39     //RSA_SHA256
    40     //RSA_SHA384
    41     //RSA_SHA512
    4276    //DSA_2048_224(2, 256, 28, 32, 56, "SHA-256"),
    4377    // Nonstandard, used by Syndie.
     
    4882    // Pubkey 384 bytes; privkey 32 bytes; hash 32 bytes; sig 64 bytes
    4983    //DSA_3072_256(3, 384, 32, 32, 64, "SHA-256", "?"),
     84
    5085    ;   
    5186
    5287    private final int code, pubkeyLen, privkeyLen, hashLen, sigLen;
     88    private final SigAlgo base;
    5389    private final String digestName, algoName;
    5490    private final AlgorithmParameterSpec params;
    5591
    56     SigType(int cod, int pubLen, int privLen, int hLen, int sLen,
     92    SigType(int cod, int pubLen, int privLen, int hLen, int sLen, SigAlgo baseAlgo,
    5793            String mdName, String aName, AlgorithmParameterSpec pSpec) {
    5894        code = cod;
     
    6197        hashLen = hLen;
    6298        sigLen = sLen;
     99        base = baseAlgo;
    63100        digestName = mdName;
    64101        algoName = aName;
     
    76113    /** the length of the signature, in bytes */
    77114    public int getSigLen() { return sigLen; }
     115    /** the standard base algorithm name used for the Java crypto factories */
     116    public SigAlgo getBaseAlgorithm() { return base; }
    78117    /** the standard name used for the Java crypto factories */
    79118    public String getAlgorithmName() { return algoName; }
     
    101140    }
    102141
     142    /**
     143     *  @since 0.9.9
     144     *  @throws UnsupportedOperationException if not supported
     145     */
     146    public SimpleDataStructure getHashInstance() {
     147        switch (getHashLen()) {
     148            case 20:
     149                return new SHA1Hash();
     150            case 32:
     151                return new Hash();
     152            case 48:
     153                return new Hash384();
     154            case 64:
     155                return new Hash512();
     156            default:
     157                throw new UnsupportedOperationException("Unsupported hash length: " + getHashLen());
     158        }
     159    }
     160
    103161    private static final Map<Integer, SigType> BY_CODE = new HashMap<Integer, SigType>();
    104162
  • core/java/src/net/i2p/crypto/TrustedUpdate.java

    ra1c8e3e r6bb1505d  
    2222import net.i2p.data.SigningPublicKey;
    2323import net.i2p.util.Log;
     24import net.i2p.util.SecureFileOutputStream;
    2425import net.i2p.util.VersionComparator;
    2526import net.i2p.util.ZipFileComment;
     
    316317    /** @return success */
    317318    private static final boolean genKeysCLI(String publicKeyFile, String privateKeyFile) {
     319        File pubFile = new File(publicKeyFile);
     320        File privFile = new File(privateKeyFile);
     321        if (pubFile.exists()) {
     322            System.out.println("Error: Not overwriting file " + publicKeyFile);
     323            return false;
     324        }
     325        if (privFile.exists()) {
     326            System.out.println("Error: Not overwriting file " + privateKeyFile);
     327            return false;
     328        }
    318329        FileOutputStream fileOutputStream = null;
    319 
    320330        I2PAppContext context = I2PAppContext.getGlobalContext();
    321331        try {
     
    324334            SigningPrivateKey signingPrivateKey = (SigningPrivateKey) signingKeypair[1];
    325335
    326             fileOutputStream = new FileOutputStream(publicKeyFile);
     336            fileOutputStream = new SecureFileOutputStream(pubFile);
    327337            signingPublicKey.writeBytes(fileOutputStream);
    328338            fileOutputStream.close();
    329339            fileOutputStream = null;
    330340
    331             fileOutputStream = new FileOutputStream(privateKeyFile);
     341            fileOutputStream = new SecureFileOutputStream(privFile);
    332342            signingPrivateKey.writeBytes(fileOutputStream);
    333343
  • core/java/src/net/i2p/update/UpdateType.java

    ra1c8e3e r6bb1505d  
    77 */
    88public enum UpdateType {
    9     TYPE_DUMMY,   // Internal use only
     9    /** Dummy: internal use only */
     10    TYPE_DUMMY,
    1011    NEWS,
    1112    ROUTER_SIGNED,
    1213    ROUTER_UNSIGNED,
    1314    PLUGIN,
     15    /** unused */
    1416    GEOIP,
     17    /** unused */
    1518    BLOCKLIST,
     19    /** unused */
    1620    RESEED,
     21    /** unused */
    1722    HOMEPAGE,
    18     ADDRESSBOOK
     23    /** unused */
     24    ADDRESSBOOK,
     25    /** @since 0.9.9 */
     26    ROUTER_SIGNED_SU3
    1927}
  • core/java/src/net/i2p/util/EepGet.java

    ra1c8e3e r6bb1505d  
    10561056                if ("http".equals(url.getProtocol())) {
    10571057                    String host = url.getHost();
     1058                    if (host.toLowerCase(Locale.US).endsWith(".i2p"))
     1059                        throw new MalformedURLException("I2P addresses must be proxied");
    10581060                    int port = url.getPort();
    10591061                    if (port == -1)
     
    10611063                    _proxy = new Socket(host, port);
    10621064                } else {
    1063                     throw new IOException("URL is not supported:" + _actualURL);
     1065                    throw new MalformedURLException("URL is not supported:" + _actualURL);
    10641066                }
    10651067            // an MUE is an IOE
     
    10901092        URL url = new URL(_actualURL);
    10911093        String host = url.getHost();
     1094        if (host == null || host.length() <= 0)
     1095            throw new MalformedURLException("Bad URL, no host");
    10921096        int port = url.getPort();
    10931097        String path = url.getPath();
  • core/java/src/net/i2p/util/NativeBigInteger.java

    ra1c8e3e r6bb1505d  
    113113     */
    114114    private static boolean _doLog = System.getProperty("jbigi.dontLog") == null &&
    115                                     I2PAppContext.getGlobalContext().isRouterContext();
     115                                    I2PAppContext.getCurrentContext() != null &&
     116                                    I2PAppContext.getCurrentContext().isRouterContext();
    116117   
    117118    /**
  • core/java/src/net/i2p/util/PartialEepGet.java

    ra1c8e3e r6bb1505d  
    44import java.io.IOException;
    55import java.io.OutputStream;
     6import java.net.MalformedURLException;
    67import java.net.URL;
    78
     
    1213 * Anything less or more will throw an IOException
    1314 * No retries, no min and max size options, no timeout option
     15 * If the server does not return a Content-Length header of the correct size,
     16 * the fetch will fail.
     17 *
    1418 * Useful for checking .sud versions
    1519 *
     
    2024    long _fetchSize;
    2125
    22     /** @param size fetch exactly this many bytes */
     26    /**
     27     * Instantiate an EepGet that will fetch exactly size bytes when fetch() is called.
     28     *
     29     * @param proxyHost use null or "" for no proxy
     30     * @param proxyPort use 0 for no proxy
     31     * @param size fetch exactly this many bytes
     32     */
    2333    public PartialEepGet(I2PAppContext ctx, String proxyHost, int proxyPort,
    2434                         OutputStream outputStream,  String url, long size) {
    2535        // we're using this constructor:
    26         // public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) {
    27         super(ctx, true, proxyHost, proxyPort, 0, size, size, null, outputStream, url, true, null, null);
     36        // public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries,
     37        //               long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) {
     38        super(ctx, proxyHost != null && proxyPort > 0, proxyHost, proxyPort, 0,
     39              size, size, null, outputStream, url, true, null, null);
    2840        _fetchSize = size;
    2941    }
     
    89101   
    90102    private static void usage() {
    91         System.err.println("PartialEepGet [-p 127.0.0.1:4444] [-l #bytes] url");
     103        System.err.println("PartialEepGet [-p 127.0.0.1:4444] [-l #bytes] url\n" +
     104                           "              (use -p :0 for no proxy)");
    92105    }
    93106   
     
    97110        URL url = new URL(_actualURL);
    98111        String host = url.getHost();
     112        if (host == null || host.length() <= 0)
     113            throw new MalformedURLException("Bad URL, no host");
    99114        int port = url.getPort();
    100115        String path = url.getPath();
  • core/java/src/net/i2p/util/SSLEepGet.java

    ra1c8e3e r6bb1505d  
    4747import java.io.PipedInputStream;
    4848import java.io.PipedOutputStream;
    49 import java.io.PrintWriter;
     49import java.net.MalformedURLException;
    5050import java.net.URL;
    5151import java.security.KeyStore;
    5252import java.security.GeneralSecurityException;
    5353import java.security.cert.Certificate;
     54import java.security.cert.CertificateEncodingException;
    5455import java.security.cert.CertificateException;
    55 import java.security.cert.CertificateEncodingException;
    56 import java.security.cert.CertificateExpiredException;
    57 import java.security.cert.CertificateNotYetValidException;
    58 import java.security.cert.CertificateFactory;
    5956import java.security.cert.X509Certificate;
    60 import java.util.Enumeration;
    6157import java.util.Locale;
    6258import javax.net.ssl.SSLContext;
     
    6864
    6965import net.i2p.I2PAppContext;
    70 import net.i2p.data.Base64;
     66import net.i2p.crypto.CertUtil;
     67import net.i2p.crypto.KeyStoreUtil;
    7168import net.i2p.data.DataHelper;
    7269
     
    7774 * Self-signed certs or CAs not in the JVM key store must be loaded to be trusted.
    7875 *
    79  * Since 0.8.2, loads additional trusted CA certs from $I2P/certificates/ and ~/.i2p/certificates/
     76 * Since 0.8.2, loads additional trusted CA certs from $I2P/certificates/ssl/ and ~/.i2p/certificates/ssl/
    8077 *
    8178 * @author zzz
     
    9289    private SavingTrustManager _stm;
    9390
    94     private static final boolean _isAndroid = SystemVersion.isAndroid();
     91    private static final String CERT_DIR = "certificates/ssl";
    9592
    9693    /**
     
    108105     */
    109106    public SSLEepGet(I2PAppContext ctx, OutputStream outputStream, String url, SSLState state) {
     107        this(ctx, null, outputStream, url, null);
     108    }
     109
     110    /**
     111     *  A new SSLEepGet with a new SSLState
     112     *  @since 0.9.9
     113     */
     114    public SSLEepGet(I2PAppContext ctx, String outputFile, String url) {
     115        this(ctx, outputFile, url, null);
     116    }
     117
     118    /**
     119     *  @param state an SSLState retrieved from a previous SSLEepGet with getSSLState(), or null.
     120     *               This makes repeated fetches from the same host MUCH faster,
     121     *               and prevents repeated key store loads even for different hosts.
     122     *  @since 0.9.9
     123     */
     124    public SSLEepGet(I2PAppContext ctx, String outputFile, String url, SSLState state) {
     125        this(ctx, outputFile, null, url, null);
     126    }
     127
     128    /**
     129     *  outputFile, outputStream: One null, one non-null
     130     *
     131     *  @param state an SSLState retrieved from a previous SSLEepGet with getSSLState(), or null.
     132     *               This makes repeated fetches from the same host MUCH faster,
     133     *               and prevents repeated key store loads even for different hosts.
     134     *  @since 0.9.9
     135     */
     136    private SSLEepGet(I2PAppContext ctx, String outputFile, OutputStream outputStream, String url, SSLState state) {
    110137        // we're using this constructor:
    111138        // public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) {
    112         super(ctx, false, null, -1, 0, -1, -1, null, outputStream, url, true, null, null);
     139        super(ctx, false, null, -1, 0, -1, -1, outputFile, outputStream, url, true, null, null);
    113140        if (state != null && state.context != null)
    114141            _sslContext = state.context;
     
    178205     *  else from $JAVA_HOME/lib/security/cacerts.
    179206     *
    180      *  Then adds certs found in the $I2P/certificates/ directory
    181      *  and in the ~/.i2p/certificates/ directory.
     207     *  Then adds certs found in the $I2P/certificates/ssl/ directory
     208     *  and in the ~/.i2p/certificates/ssl/ directory.
    182209     *
    183210     *  @return null on failure
     
    185212     */
    186213    private SSLContext initSSLContext() {
    187         KeyStore ks;
    188         try {
    189             ks = KeyStore.getInstance(KeyStore.getDefaultType());
    190         } catch (GeneralSecurityException gse) {
    191             _log.error("Key Store init error", gse);
     214        KeyStore ks = KeyStoreUtil.loadSystemKeyStore();
     215        if (ks == null) {
     216            _log.error("Key Store init error");
    192217            return null;
    193218        }
    194         boolean success = false;
    195         String override = System.getProperty("javax.net.ssl.keyStore");
    196         if (override != null)
    197             success = loadCerts(new File(override), ks);
    198         if (!success) {
    199             if (_isAndroid) {
    200                 // thru API 13. As of API 14 (ICS), the file is gone, but
    201                 // ks.load(null, pw) will bring in the default certs?
    202                 success = loadCerts(new File(System.getProperty("java.home"), "etc/security/cacerts.bks"), ks);
    203             } else {
    204                 success = loadCerts(new File(System.getProperty("java.home"), "lib/security/jssecacerts"), ks);
    205                 if (!success)
    206                     success = loadCerts(new File(System.getProperty("java.home"), "lib/security/cacerts"), ks);
    207             }
    208         }
    209 
    210         if (!success) {
    211             try {
    212                 // must be initted
    213                 ks.load(null, "changeit".toCharArray());
    214             } catch (Exception e) {}
    215             _log.error("All key store loads failed, will only load local certificates");
    216         } else if (_log.shouldLog(Log.INFO)) {
    217             int count = 0;
    218             try {
    219                 for(Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
    220                     String alias = e.nextElement();
    221                     if (ks.isCertificateEntry(alias))
    222                         count++;
    223                 }
    224             } catch (Exception foo) {}
     219        if (_log.shouldLog(Log.INFO)) {
     220            int count = KeyStoreUtil.countCerts(ks);
    225221            _log.info("Loaded " + count + " default trusted certificates");
    226222        }
    227223
    228         File dir = new File(_context.getBaseDir(), "certificates");
    229         int adds = addCerts(dir, ks);
     224        File dir = new File(_context.getBaseDir(), CERT_DIR);
     225        int adds = KeyStoreUtil.addCerts(dir, ks);
    230226        int totalAdds = adds;
    231227        if (adds > 0 && _log.shouldLog(Log.INFO))
    232228            _log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
    233229        if (!_context.getBaseDir().getAbsolutePath().equals(_context.getConfigDir().getAbsolutePath())) {
    234             dir = new File(_context.getConfigDir(), "certificates");
    235             adds = addCerts(dir, ks);
     230            dir = new File(_context.getConfigDir(), CERT_DIR);
     231            adds = KeyStoreUtil.addCerts(dir, ks);
    236232            totalAdds += adds;
    237233            if (adds > 0 && _log.shouldLog(Log.INFO))
     
    240236        dir = new File(System.getProperty("user.dir"));
    241237        if (!_context.getBaseDir().getAbsolutePath().equals(dir.getAbsolutePath())) {
    242             dir = new File(_context.getConfigDir(), "certificates");
    243             adds = addCerts(dir, ks);
     238            dir = new File(_context.getConfigDir(), CERT_DIR);
     239            adds = KeyStoreUtil.addCerts(dir, ks);
    244240            totalAdds += adds;
    245241            if (adds > 0 && _log.shouldLog(Log.INFO))
     
    261257        }
    262258        return null;
    263     }
    264 
    265     /**
    266      *  Load all X509 Certs from a key store File into a KeyStore
    267      *  Note that each call reinitializes the KeyStore
    268      *
    269      *  @return success
    270      *  @since 0.8.2
    271      */
    272     private boolean loadCerts(File file, KeyStore ks) {
    273         if (!file.exists())
    274             return false;
    275         InputStream fis = null;
    276         try {
    277             fis = new FileInputStream(file);
    278             // "changeit" is the default password
    279             ks.load(fis, "changeit".toCharArray());
    280         } catch (GeneralSecurityException gse) {
    281             _log.error("KeyStore load error, no default keys: " + file.getAbsolutePath(), gse);
    282             try {
    283                 // not clear if null is allowed for password
    284                 ks.load(null, "changeit".toCharArray());
    285             } catch (Exception foo) {}
    286             return false;
    287         } catch (IOException ioe) {
    288             _log.error("KeyStore load error, no default keys: " + file.getAbsolutePath(), ioe);
    289             try {
    290                 ks.load(null, "changeit".toCharArray());
    291             } catch (Exception foo) {}
    292             return false;
    293         } finally {
    294             try { if (fis != null) fis.close(); } catch (IOException foo) {}
    295         }
    296         return true;
    297     }
    298 
    299     /**
    300      *  Load all X509 Certs from a directory and add them to the
    301      *  trusted set of certificates in the key store
    302      *
    303      *  @return number successfully added
    304      *  @since 0.8.2
    305      */
    306     private int addCerts(File dir, KeyStore ks) {
    307         if (_log.shouldLog(Log.INFO))
    308             _log.info("Looking for X509 Certificates in " + dir.getAbsolutePath());
    309         int added = 0;
    310         if (dir.exists() && dir.isDirectory()) {
    311             File[] files = dir.listFiles();
    312             if (files != null) {
    313                 for (int i = 0; i < files.length; i++) {
    314                     File f = files[i];
    315                     if (!f.isFile())
    316                         continue;
    317                     // use file name as alias
    318                     // https://www.sslshopper.com/ssl-converter.html
    319                     // No idea if all these formats can actually be read by CertificateFactory
    320                     String alias = f.getName().toLowerCase(Locale.US);
    321                     if (alias.endsWith(".crt") || alias.endsWith(".pem") || alias.endsWith(".key") ||
    322                         alias.endsWith(".der") || alias.endsWith(".key") || alias.endsWith(".p7b") ||
    323                         alias.endsWith(".p7c") || alias.endsWith(".pfx") || alias.endsWith(".p12"))
    324                         alias = alias.substring(0, alias.length() - 4);
    325                     boolean success = addCert(f, alias, ks);
    326                     if (success)
    327                         added++;
    328                 }
    329             }
    330         }
    331         return added;
    332     }
    333 
    334     /**
    335      *  Load an X509 Cert from a file and add it to the
    336      *  trusted set of certificates in the key store
    337      *
    338      *  @return success
    339      *  @since 0.8.2
    340      */
    341     private boolean addCert(File file, String alias, KeyStore ks) {
    342         InputStream fis = null;
    343         try {
    344             fis = new FileInputStream(file);
    345             CertificateFactory cf = CertificateFactory.getInstance("X.509");
    346             X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
    347             if (_log.shouldLog(Log.INFO)) {
    348                 _log.info("Read X509 Certificate from " + file.getAbsolutePath() +
    349                           " Issuer: " + cert.getIssuerX500Principal() +
    350                           "; Valid From: " + cert.getNotBefore() +
    351                           " To: " + cert.getNotAfter());
    352             }
    353             try {
    354                 cert.checkValidity();
    355             } catch (CertificateExpiredException cee) {
    356                 _log.error("Rejecting expired X509 Certificate: " + file.getAbsolutePath(), cee);
    357                 return false;
    358             } catch (CertificateNotYetValidException cnyve) {
    359                 _log.error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve);
    360                 return false;
    361             }
    362             ks.setCertificateEntry(alias, cert);
    363             if (_log.shouldLog(Log.INFO))
    364                 _log.info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal());
    365         } catch (GeneralSecurityException gse) {
    366             _log.error("Error reading X509 Certificate: " + file.getAbsolutePath(), gse);
    367             return false;
    368         } catch (IOException ioe) {
    369             _log.error("Error reading X509 Certificate: " + file.getAbsolutePath(), ioe);
    370             return false;
    371         } finally {
    372             try { if (fis != null) fis.close(); } catch (IOException foo) {}
    373         }
    374         return true;
    375259    }
    376260   
     
    426310                System.out.println("      WARNING: Certificate is not currently valid, it cannot be used");
    427311            }
    428             saveCert(cert, new File(name));
     312            CertUtil.saveCert(cert, new File(name));
    429313        }
    430314        System.out.println("NOTE: To trust them, copy the certificate file(s) to the certificates directory and rerun without the -s option");
    431315        System.out.println("NOTE: EepGet failed, certificate error follows:");
    432     }
    433 
    434     private static final int LINE_LENGTH = 64;
    435 
    436     /**
    437      *  Modified from:
    438      *  http://www.exampledepot.com/egs/java.security.cert/ExportCert.html
    439      *
    440      *  This method writes a certificate to a file in base64 format.
    441      *  @since 0.8.2
    442      */
    443     private static void saveCert(Certificate cert, File file) {
    444         OutputStream os = null;
    445         try {
    446            // Get the encoded form which is suitable for exporting
    447            byte[] buf = cert.getEncoded();
    448            os = new FileOutputStream(file);
    449            PrintWriter wr = new PrintWriter(os);
    450            wr.println("-----BEGIN CERTIFICATE-----");
    451            String b64 = Base64.encode(buf, true);     // true = use standard alphabet
    452            for (int i = 0; i < b64.length(); i += LINE_LENGTH) {
    453                wr.println(b64.substring(i, Math.min(i + LINE_LENGTH, b64.length())));
    454            }
    455            wr.println("-----END CERTIFICATE-----");
    456            wr.flush();
    457         } catch (CertificateEncodingException cee) {
    458             System.out.println("Error writing X509 Certificate " + file.getAbsolutePath() + ' ' + cee);
    459         } catch (IOException ioe) {
    460             System.out.println("Error writing X509 Certificate " + file.getAbsolutePath() + ' ' + ioe);
    461         } finally {
    462             try { if (os != null) os.close(); } catch (IOException foo) {}
    463         }
    464316    }
    465317
     
    642494            if ("https".equals(url.getProtocol())) {
    643495                host = url.getHost();
     496                if (host.toLowerCase(Locale.US).endsWith(".i2p"))
     497                    throw new MalformedURLException("I2P addresses unsupported");
    644498                port = url.getPort();
    645499                if (port == -1)
     
    650504                    _proxy = SSLSocketFactory.getDefault().createSocket(host, port);
    651505            } else {
    652                 throw new IOException("Only https supported: " + _actualURL);
     506                throw new MalformedURLException("Only https supported: " + _actualURL);
    653507            }
    654508        // an MUE is an IOE
  • installer/resources/deletelist.txt

    ra1c8e3e r6bb1505d  
    6969docs/initialNews/initialNews_ru.xml
    7070docs/initialNews/initialNews_sv.xml
     71# certificates moved to certificates/ssl
     72certificates/193.150.121.66.crt
     73certificates/cert.smartcom.org.crt
     74certificates/i2p.feared.eu.crt
     75certificates/i2p.mooo.com.crt
     76certificates/i2pprojekt.de.cert
     77certificates/ieb9oopo.mooo.com.crt
     78certificates/netdb.i2p2.de.crt
     79certificates/netdb.i2p2.no.crt
     80certificates/reseed.info.crt
     81certificates/reseed.pkol.de.crt
     82certificates/www.cacert.org.crt
  • router/java/src/net/i2p/router/client/SSLClientListenerRunner.java

    ra1c8e3e r6bb1505d  
    2222
    2323import net.i2p.client.I2PClient;
     24import net.i2p.crypto.CertUtil;
     25import net.i2p.crypto.KeyStoreUtil;
    2426import net.i2p.data.Base32;
    25 import net.i2p.data.Base64;
    2627import net.i2p.router.RouterContext;
    2728import net.i2p.util.Log;
    2829import net.i2p.util.SecureDirectory;
    29 import net.i2p.util.SecureFileOutputStream;
    30 import net.i2p.util.ShellCommand;
    3130
    3231/**
     
    8887    private boolean createKeyStore(File ks) {
    8988        // make a random 48 character password (30 * 8 / 5)
    90         byte[] rand = new byte[30];
    91         _context.random().nextBytes(rand);
    92         String keyPassword = Base32.encode(rand);
     89        String keyPassword = KeyStoreUtil.randomString();
    9390        // and one for the cname
    94         _context.random().nextBytes(rand);
    95         String cname = Base32.encode(rand) + ".i2cp.i2p.net";
    96 
    97         String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath();
    98         String[] args = new String[] {
    99                    keytool,
    100                    "-genkey",            // -genkeypair preferred in newer keytools, but this works with more
    101                    "-storetype", KeyStore.getDefaultType(),
    102                    "-keystore", ks.getAbsolutePath(),
    103                    "-storepass", DEFAULT_KEYSTORE_PASSWORD,
    104                    "-alias", KEY_ALIAS,
    105                    "-dname", "CN=" + cname + ",OU=I2CP,O=I2P Anonymous Network,L=XX,ST=XX,C=XX",
    106                    "-validity", "3652",  // 10 years
    107                    "-keyalg", "DSA",
    108                    "-keysize", "1024",
    109                    "-keypass", keyPassword};
    110         boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 30);  // 30 secs
     91        String cname = KeyStoreUtil.randomString() + ".i2cp.i2p.net";
     92
     93        boolean success = KeyStoreUtil.createKeys(ks, KEY_ALIAS, cname, "I2CP", keyPassword);
    11194        if (success) {
    11295            success = ks.exists();
    11396            if (success) {
    114                 SecureFileOutputStream.setPerms(ks);
    11597                Map<String, String> changes = new HashMap();
    11698                changes.put(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
     
    124106                           "IP address, host name, router identity, or destination keys.");
    125107        } else {
    126             _log.error("Failed to create I2CP SSL keystore using command line:");
    127             StringBuilder buf = new StringBuilder(256);
    128             for (int i = 0;  i < args.length; i++) {
    129                 buf.append('"').append(args[i]).append("\" ");
    130             }
    131             _log.error(buf.toString());
    132             _log.error("This is for the Sun/Oracle keytool, others may be incompatible.\n" +
     108            _log.error("Failed to create I2CP SSL keystore.\n" +
     109                       "This is for the Sun/Oracle keytool, others may be incompatible.\n" +
    133110                       "If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD +
    134111                       " to " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath());
     
    144121        File sdir = new SecureDirectory(_context.getConfigDir(), "certificates");
    145122        if (sdir.exists() || sdir.mkdir()) {
    146             InputStream fis = null;
    147             try {
    148                 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    149                 fis = new FileInputStream(ks);
    150                 String ksPass = _context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
    151                 keyStore.load(fis, ksPass.toCharArray());
    152                 Certificate cert = keyStore.getCertificate(KEY_ALIAS);
    153                 if (cert != null) {
    154                     File certFile = new File(sdir, ASCII_KEYFILE);
    155                     saveCert(cert, certFile);
    156                 } else {
    157                     _log.error("Error getting SSL cert to save as ASCII");
    158                 }
    159             } catch (GeneralSecurityException gse) {
    160                 _log.error("Error saving ASCII SSL keys", gse);
    161             } catch (IOException ioe) {
    162                 _log.error("Error saving ASCII SSL keys", ioe);
    163             } finally {
    164                 if (fis != null) try { fis.close(); } catch (IOException ioe) {}
    165             }
     123            String ksPass = _context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
     124            File out = new File(sdir, ASCII_KEYFILE);
     125            boolean success = KeyStoreUtil.exportCert(ks, ksPass, KEY_ALIAS, out);
     126            if (!success)
     127                _log.error("Error getting SSL cert to save as ASCII");
    166128        } else {
    167129            _log.error("Error saving ASCII SSL keys");
    168         }
    169     }
    170 
    171     private static final int LINE_LENGTH = 64;
    172 
    173     /**
    174      *  Modified from:
    175      *  http://www.exampledepot.com/egs/java.security.cert/ExportCert.html
    176      *
    177      *  Write a certificate to a file in base64 format.
    178      */
    179     private void saveCert(Certificate cert, File file) {
    180         OutputStream os = null;
    181         try {
    182            // Get the encoded form which is suitable for exporting
    183            byte[] buf = cert.getEncoded();
    184            os = new SecureFileOutputStream(file);
    185            PrintWriter wr = new PrintWriter(os);
    186            wr.println("-----BEGIN CERTIFICATE-----");
    187            String b64 = Base64.encode(buf, true);     // true = use standard alphabet
    188            for (int i = 0; i < b64.length(); i += LINE_LENGTH) {
    189                wr.println(b64.substring(i, Math.min(i + LINE_LENGTH, b64.length())));
    190            }
    191            wr.println("-----END CERTIFICATE-----");
    192            wr.flush();
    193         } catch (CertificateEncodingException cee) {
    194            _log.error("Error writing X509 Certificate " + file.getAbsolutePath(), cee);
    195         } catch (IOException ioe) {
    196             _log.error("Error writing X509 Certificate " + file.getAbsolutePath(), ioe);
    197         } finally {
    198             try { if (os != null) os.close(); } catch (IOException foo) {}
    199130        }
    200131    }
  • tests/scripts/checkcerts.sh

    ra1c8e3e r6bb1505d  
    155155cd `dirname $0`/../../installer/resources/certificates
    156156
    157 for i in *.crt *.cert
     157for i in */*.crt
    158158do
    159159    echo "Checking $i ..."
Note: See TracChangeset for help on using the changeset viewer.