i2ptunnel: New b32 error page

Do basic b32 checks before looking up with session
Util: Fix AIOOBE on bad input to base 32 decode
log tweaks
b33 decode error message tweaks
This commit is contained in:
zzz
2019-09-10 14:21:28 +00:00
parent 479461ab3b
commit b4a5cc07c2
5 changed files with 92 additions and 28 deletions

View File

@ -1215,12 +1215,39 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
} else if("i2p".equals(host)) {
clientDest = null;
} else if (destination.length() >= 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
} else if (destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
int len = destination.length();
if (len < 60 || (len >= 61 && len <= 63)) {
// 8-59 or 61-63 chars, this won't work
String header = getErrorPage("b32", ERR_DESTINATION_UNKNOWN);
try {
writeErrorMessage(header, _t("Corrupt b32 address"), out, targetRequest, false, destination);
} catch (IOException ioe) {}
return;
}
if (len >= 64) {
// catch b33 errors before session lookup
try {
BlindData bd = Blinding.decode(_context, destination);
if (_log.shouldWarn())
_log.warn("Resolved b33 " + bd);
// TESTING
//sess.sendBlindingInfo(bd, 24*60*60*1000);
} catch (IllegalArgumentException iae) {
if (_log.shouldWarn())
_log.warn("Unable to resolve b33 " + destination, iae);
// b33 error page
String header = getErrorPage("b32", ERR_DESTINATION_UNKNOWN);
try {
writeErrorMessage(header, iae.getMessage(), out, targetRequest, false, destination);
} catch (IOException ioe) {}
return;
}
}
// use existing session to look up for efficiency
verifySocketManager();
I2PSession sess = sockMgr.getSession();
if (!sess.isClosed()) {
int len = destination.length();
if (len == 60) {
byte[] hData = Base32.decode(destination.substring(0, 52));
if (hData != null) {
@ -1234,33 +1261,43 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
} else if (len >= 64) {
if (_log.shouldInfo())
_log.info("lookup b33 in-session " + destination);
try {
BlindData bd = Blinding.decode(_context, destination);
if (_log.shouldWarn())
_log.warn("Resolved b33 " + bd);
// TESTING
//sess.sendBlindingInfo(bd, 24*60*60*1000);
} catch (IllegalArgumentException iae) {
if (_log.shouldWarn())
_log.warn("Unable to resolve b33 " + destination, iae);
// TODO new error page
}
LookupResult lresult = sess.lookupDest2(destination, 20*1000);
clientDest = lresult.getDestination();
int code = lresult.getResultCode();
if (code != 0) {
if (code != LookupResult.RESULT_SUCCESS) {
if (_log.shouldWarn())
_log.warn("Unable to resolve b33 " + destination + " error code " + code);
// TODO new form
// TODO new form to supply missing data
if (code != LookupResult.RESULT_FAILURE) {
String header = getErrorPage("b32", ERR_DESTINATION_UNKNOWN);
String msg;
if (code == LookupResult.RESULT_SECRET_REQUIRED)
msg = "b32 address requires lookup password";
else if (code == LookupResult.RESULT_KEY_REQUIRED)
msg = "b32 address requires encryption key";
else if (code == LookupResult.RESULT_SECRET_AND_KEY_REQUIRED)
msg = "b32 address requires encryption key and lookup password";
else if (code == LookupResult.RESULT_DECRYPTION_FAILURE)
msg = "b32 address decryption failure, check encryption key";
else
msg = "lookup failure code " + code;
try {
writeErrorMessage(header, msg, out, targetRequest, false, destination);
} catch (IOException ioe) {}
return;
}
}
} else {
// 61-63 chars, this won't work
clientDest = _context.namingService().lookup(destination);
}
} else {
if (_log.shouldInfo())
_log.info("lookup b32 out of session " + destination);
// TODO can't get result code from here
clientDest = _context.namingService().lookup(destination);
}
} else {
if (_log.shouldInfo())
_log.info("lookup hostname " + destination);
clientDest = _context.namingService().lookup(destination);
}
@ -1518,7 +1555,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(host == null) {
return null;
}
if(host.length() == 60 && host.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
if (host.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
return host;
}
Destination dest = _context.namingService().lookup(host);

View File

@ -209,7 +209,7 @@ public final class Blinding {
throw new IllegalArgumentException("Not a .b32.i2p address");
byte[] b = Base32.decode(address.substring(0, address.length() - 8));
if (b == null)
throw new IllegalArgumentException("Bad base32 encoding");
throw new IllegalArgumentException("Corrupt b32 address");
if (b.length < 35)
throw new IllegalArgumentException("Not a new-format address");
return decode(ctx, b);
@ -234,22 +234,22 @@ public final class Blinding {
b[2] ^= (byte) (check >> 16);
int flag = b[0] & 0xff;
if ((flag & 0xf8) != 0)
throw new IllegalArgumentException("Corrupt b32 or unsupported options");
throw new IllegalArgumentException("Corrupt b32 address (or unsupported options)");
if ((flag & FLAG_TWOBYTE) != 0)
throw new IllegalArgumentException("Two byte sig types unsupported");
throw new IllegalArgumentException("Two byte signature types unsupported");
// TODO two-byte sigtypes
int st1 = b[1] & 0xff;
int st2 = b[2] & 0xff;
SigType sigt1 = SigType.getByCode(st1);
SigType sigt2 = SigType.getByCode(st2);
if (sigt1 == null)
throw new IllegalArgumentException("Unknown sig type " + st1);
throw new IllegalArgumentException("Unsupported signature type " + st1);
if (!sigt1.isAvailable())
throw new IllegalArgumentException("Unavailable sig type " + sigt1);
throw new IllegalArgumentException("Unavailable signature type " + sigt1);
if (sigt2 == null)
throw new IllegalArgumentException("Unknown blinded sig type " + st2);
throw new IllegalArgumentException("Unsupported blinded signature type " + st2);
if (!sigt2.isAvailable())
throw new IllegalArgumentException("Unavailable blinded sig type " + sigt2);
throw new IllegalArgumentException("Unavailable blinded signature type " + sigt2);
// todo secret/privkey
int spkLen = sigt1.getPubkeyLen();
if (3 + spkLen > b.length)

View File

@ -235,6 +235,8 @@ public class Base32 {
fivebits = DECODABET[source[i] - '2'];
if (fivebits >= 0) {
if (outBuffPosn >= len58)
return null;
if (usedbits == 0) {
outBuff[outBuffPosn] = (byte) ((fivebits << 3) & 0xf8);
usedbits = 5;

View File

@ -0,0 +1,25 @@
HTTP/1.1 400 Destination Not Found
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache
Connection: close
Proxy-Connection: close
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>_("Website Unreachable")</title>
<noscript><style type="text/css">.script {display: none;}</style></noscript>
<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico">
<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="logo">
<a href="http://127.0.0.1:7657/" title="_("Router Console")"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="_("I2P Router Console")" border="0"></a><hr>
<a href="http://127.0.0.1:7657/config.jsp">_("Configuration")</a> <a href="http://127.0.0.1:7657/help.jsp">_("Help")</a> <a href="http://127.0.0.1:7657/susidns/index">_("Addressbook")</a>
</div>
<div class="warning" id="warning">
<h3>_("Warning: Invalid Destination")</h3>
<p>
_("The b32 address is invalid.")
<hr>
<p><b>_("Could not find the following destination:")</b>
</p>

View File

@ -129,7 +129,7 @@ class LookupDestJob extends JobImpl {
Destination d = _blindData.getDestination();
if (d != null) {
if (_log.shouldDebug())
_log.debug("Found cached b33 lookup " + _name + " to " + d);
_log.debug("Found cached b33 lookup " + _blindData.getUnblindedPubKey() + " to " + d);
returnDest(d);
return;
}
@ -144,7 +144,7 @@ class LookupDestJob extends JobImpl {
else
code = HostReplyMessage.RESULT_SECRET_REQUIRED;
if (_log.shouldDebug())
_log.debug("Failed b33 lookup " + _name + " with code " + code);
_log.debug("Failed b33 lookup " + _blindData.getUnblindedPubKey() + " with code " + code);
returnFail(code);
}
}