예제 #1
0
  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)
              + ")");
    }
  }
예제 #3
0
  /**
   * 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);
  }
예제 #4
0
  /**
   * 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);
  }
예제 #5
0
  /**
   * 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;
  }