protected void handleResponse(IoBuffer buf) throws Exception { byte first = buf.get(0); if (first != 0) { throw new Exception("Socks response seems to be malformed"); } byte status = buf.get(1); buf.position(buf.position() + 8); if (status == 90) setHandshakeComplete(); else throw new Exception( "Proxy handshake failed - Code: 0x" + ByteUtilities.asHex(new byte[] {status}) + " (" + SocksProxyConstants.getReplyCodeAsString(status) + ")"); }
/** * Handle a SOCKS4/SOCKS4a response from the proxy server. Test the response buffer reply code and * call {@link #setHandshakeComplete()} if access is granted. * * @param buf the buffer holding the server response data. * @throws exception if server response is malformed or if request is rejected by the proxy * server. */ protected void handleResponse(final IoBuffer buf) throws Exception { byte first = buf.get(0); if (first != 0) { throw new Exception("Socks response seems to be malformed"); } byte status = buf.get(1); // Consumes all the response data from the buffer buf.position(buf.position() + SocksProxyConstants.SOCKS_4_RESPONSE_SIZE); if (status == SocksProxyConstants.V4_REPLY_REQUEST_GRANTED) { setHandshakeComplete(); } else { throw new Exception( "Proxy handshake failed - Code: 0x" + ByteUtilities.asHex(new byte[] {status}) + " (" + SocksProxyConstants.getReplyCodeAsString(status) + ")"); } }
/** * Computes the response to the DIGEST challenge. * * @param session the current session * @param map the map holding the directives sent by the proxy * @param method the HTTP verb * @param pwd the password * @param charsetName the name of the charset used for the challenge * @param body the html body to be hashed for integrity calculations */ public static String computeResponseValue( IoSession session, HashMap<String, String> map, String method, String pwd, String charsetName, String body) throws AuthenticationException, UnsupportedEncodingException { byte[] hA1; StringBuilder sb; boolean isMD5Sess = "md5-sess".equalsIgnoreCase(StringUtilities.getDirectiveValue(map, "algorithm", false)); if (!isMD5Sess || (session.getAttribute(SESSION_HA1) == null)) { // Build A1 sb = new StringBuilder(); sb.append( StringUtilities.stringTo8859_1( StringUtilities.getDirectiveValue(map, "username", true))) .append(':'); String realm = StringUtilities.stringTo8859_1(StringUtilities.getDirectiveValue(map, "realm", false)); if (realm != null) { sb.append(realm); } sb.append(':').append(pwd); if (isMD5Sess) { byte[] prehA1; synchronized (md5) { md5.reset(); prehA1 = md5.digest(sb.toString().getBytes(charsetName)); } sb = new StringBuilder(); sb.append(ByteUtilities.asHex(prehA1)); sb.append(':') .append( StringUtilities.stringTo8859_1( StringUtilities.getDirectiveValue(map, "nonce", true))); sb.append(':') .append( StringUtilities.stringTo8859_1( StringUtilities.getDirectiveValue(map, "cnonce", true))); synchronized (md5) { md5.reset(); hA1 = md5.digest(sb.toString().getBytes(charsetName)); } session.setAttribute(SESSION_HA1, hA1); } else { synchronized (md5) { md5.reset(); hA1 = md5.digest(sb.toString().getBytes(charsetName)); } } } else { hA1 = (byte[]) session.getAttribute(SESSION_HA1); } sb = new StringBuilder(method); sb.append(':'); sb.append(StringUtilities.getDirectiveValue(map, "uri", false)); String qop = StringUtilities.getDirectiveValue(map, "qop", false); if ("auth-int".equalsIgnoreCase(qop)) { ProxyIoSession proxyIoSession = (ProxyIoSession) session.getAttribute(ProxyIoSession.PROXY_SESSION); byte[] hEntity; synchronized (md5) { md5.reset(); hEntity = md5.digest(body.getBytes(proxyIoSession.getCharsetName())); } sb.append(':').append(hEntity); } byte[] hA2; synchronized (md5) { md5.reset(); hA2 = md5.digest(sb.toString().getBytes(charsetName)); } sb = new StringBuilder(); sb.append(ByteUtilities.asHex(hA1)); sb.append(':').append(StringUtilities.getDirectiveValue(map, "nonce", true)); sb.append(":00000001:"); sb.append(StringUtilities.getDirectiveValue(map, "cnonce", true)); sb.append(':').append(qop).append(':'); sb.append(ByteUtilities.asHex(hA2)); byte[] hFinal; synchronized (md5) { md5.reset(); hFinal = md5.digest(sb.toString().getBytes(charsetName)); } return ByteUtilities.asHex(hFinal); }
/** * Handle a SOCKS v5 response from the proxy server. * * @param nextFilter the next filter * @param buf the buffered data received * @param step the current step in the authentication process */ protected void handleResponse(final NextFilter nextFilter, final IoBuffer buf, int step) throws Exception { int len = 2; if (step == SocksProxyConstants.SOCKS5_GREETING_STEP) { // Send greeting message byte method = buf.get(1); if (method == SocksProxyConstants.NO_ACCEPTABLE_AUTH_METHOD) { throw new IllegalStateException( "No acceptable authentication method to use with " + "the socks proxy server"); } getSession().setAttribute(SELECTED_AUTH_METHOD, method); } else if (step == SocksProxyConstants.SOCKS5_AUTH_STEP) { // Authentication to the SOCKS server byte method = (Byte) getSession().getAttribute(Socks5LogicHandler.SELECTED_AUTH_METHOD); if (method == SocksProxyConstants.GSSAPI_AUTH) { int oldPos = buf.position(); if (buf.get(0) != 0x01) { throw new IllegalStateException("Authentication failed"); } if (buf.get(1) == 0xFF) { throw new IllegalStateException( "Authentication failed: GSS API Security Context Failure"); } if (buf.remaining() >= 2) { byte[] size = new byte[2]; buf.get(size); int s = ByteUtilities.makeIntFromByte2(size); if (buf.remaining() >= s) { byte[] token = new byte[s]; buf.get(token); getSession().setAttribute(GSS_TOKEN, token); len = 0; } else { // buf.position(oldPos); return; } } else { buf.position(oldPos); return; } } else if (buf.get(1) != SocksProxyConstants.V5_REPLY_SUCCEEDED) { throw new IllegalStateException("Authentication failed"); } } else if (step == SocksProxyConstants.SOCKS5_REQUEST_STEP) { // Send the request byte addressType = buf.get(3); len = 6; if (addressType == SocksProxyConstants.IPV6_ADDRESS_TYPE) { len += 16; } else if (addressType == SocksProxyConstants.IPV4_ADDRESS_TYPE) { len += 4; } else if (addressType == SocksProxyConstants.DOMAIN_NAME_ADDRESS_TYPE) { len += 1 + (buf.get(4)); } else { throw new IllegalStateException("Unknwon address type"); } if (buf.remaining() >= len) { // handle response byte status = buf.get(1); LOGGER.debug(" response status: {}", SocksProxyConstants.getReplyCodeAsString(status)); if (status == SocksProxyConstants.V5_REPLY_SUCCEEDED) { buf.position(buf.position() + len); setHandshakeComplete(); return; } throw new Exception( "Proxy handshake failed - Code: 0x" + ByteUtilities.asHex(new byte[] {status})); } return; } if (len > 0) { buf.position(buf.position() + len); } // Move to the handshaking next step if not in the middle of // the authentication process boolean isAuthenticating = false; if (step == SocksProxyConstants.SOCKS5_AUTH_STEP) { byte method = (Byte) getSession().getAttribute(Socks5LogicHandler.SELECTED_AUTH_METHOD); if (method == SocksProxyConstants.GSSAPI_AUTH) { GSSContext ctx = (GSSContext) getSession().getAttribute(GSS_CONTEXT); if (ctx == null || !ctx.isEstablished()) { isAuthenticating = true; } } } if (!isAuthenticating) { getSession().setAttribute(HANDSHAKE_STEP, ++step); } doHandshake(nextFilter); }
/** * Encodes the authentication packet for supported authentication methods. * * @param request the socks proxy request data * @return the encoded buffer * @throws GSSException when something fails while using GSSAPI */ private IoBuffer encodeGSSAPIAuthenticationPacket(final SocksProxyRequest request) throws GSSException { GSSContext ctx = (GSSContext) getSession().getAttribute(GSS_CONTEXT); if (ctx == null) { // first step in the authentication process GSSManager manager = GSSManager.getInstance(); GSSName serverName = manager.createName(request.getServiceKerberosName(), null); Oid krb5OID = new Oid(SocksProxyConstants.KERBEROS_V5_OID); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Available mechs:"); for (Oid o : manager.getMechs()) { if (o.equals(krb5OID)) { LOGGER.debug("Found Kerberos V OID available"); } LOGGER.debug("{} with oid = {}", manager.getNamesForMech(o), o); } } ctx = manager.createContext(serverName, krb5OID, null, GSSContext.DEFAULT_LIFETIME); ctx.requestMutualAuth(true); // Mutual authentication ctx.requestConf(false); ctx.requestInteg(false); getSession().setAttribute(GSS_CONTEXT, ctx); } byte[] token = (byte[]) getSession().getAttribute(GSS_TOKEN); if (token != null) { LOGGER.debug(" Received Token[{}] = {}", token.length, ByteUtilities.asHex(token)); } IoBuffer buf = null; if (!ctx.isEstablished()) { // token is ignored on the first call if (token == null) { token = new byte[32]; } token = ctx.initSecContext(token, 0, token.length); // Send a token to the server if one was generated by // initSecContext if (token != null) { LOGGER.debug(" Sending Token[{}] = {}", token.length, ByteUtilities.asHex(token)); getSession().setAttribute(GSS_TOKEN, token); buf = IoBuffer.allocate(4 + token.length); buf.put( new byte[] { SocksProxyConstants.GSSAPI_AUTH_SUBNEGOTIATION_VERSION, SocksProxyConstants.GSSAPI_MSG_TYPE }); buf.put(ByteUtilities.intToNetworkByteOrder(token.length, 2)); buf.put(token); } } return buf; }