Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add certificate checking feature. #146

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions application/res/layout/serveradd.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,29 @@ along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
android:layout_height="wrap_content"
android:text="@string/server_port"
android:visibility="gone" />
<CheckBox
android:id="@+id/useSSL"
android:contentDescription="@string/server_useSSL"
<TextView
android:text="@string/server_securityType"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/securityType"
android:contentDescription="@string/server_securityType"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/server_useSSL" />
android:entries="@array/server_securityTypes" />
<TextView
android:id="@+id/fingerprint_label"
android:text="@string/server_fingerprint"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<EditText
android:id="@+id/fingerprint"
android:contentDescription="@string/server_fingerprint"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:visibility="gone" />
<!-- ############################################################################ -->
<TextView
android:text="@string/user"
Expand Down
6 changes: 6 additions & 0 deletions application/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,10 @@
<item>20</item>
<item>30</item>
</string-array>
<string-array name="server_securityTypes">
<item>None</item>
<item>SSL/TLS (Accept all certificates)</item>
<item>SSL/TLS</item>
<item>SSL/TLS (Fixed key)</item>
</string-array>
</resources>
7 changes: 6 additions & 1 deletion application/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@
<string name="line_missing">Line is missing</string>
<string name="nickname_in_use">Nickname %1$s already in use</string>
<string name="irc_login_error">Could not log into the IRC server %1$s:%2$d</string>
<string name="could_not_connect">Could not connect to %1$s:%2$d</string>
<string name="could_not_connect">Could not connect to %1$s:%2$d: %3$s</string>
<string name="ssl_handshake_error">Could not handshake with %1$s:%2$d: %3$s</string>

<string name="command_desc_amsg">Send a message to all channels</string>
<string name="command_desc_away">Sets you away</string>
Expand Down Expand Up @@ -234,4 +235,8 @@
<string name="settings_ime_extract_desc">Use fullscreen keyboard when in landscape mode</string>
<string name="settings_history_size_title">History size</string>
<string name="settings_history_size_desc">Number of lines of conversation history to keep</string>

<string name="server_securityType">Security type</string>
<string name="server_fingerprint">SHA-1 fingerprint</string>
<string name="validation_bad_fingerprint">Invalid fingerprint value</string>
</resources>
69 changes: 44 additions & 25 deletions application/src/org/jibble/pircbot/PircBot.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ General Public License (GPL) and the www.jibble.org Commercial License.
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.security.NoSuchAlgorithmException;
import java.security.KeyManagementException;

import org.yaaic.ssl.NaiveTrustManager;
import org.yaaic.ssl.FixedTrustManager;
import org.yaaic.tools.Base64;

/**
Expand Down Expand Up @@ -88,6 +91,8 @@ public abstract class PircBot implements ReplyConstants {
private static final int VOICE_ADD = 3;
private static final int VOICE_REMOVE = 4;

public enum SecurityType { NONE, TLS_INSECURE, TLS, TLS_FIXED_KEY };

/**
* Constructs a PircBot with the default settings. Your own constructors
* in classes which extend the PircBot abstract class should be responsible
Expand All @@ -105,7 +110,10 @@ public PircBot() {}
* @throws IrcException if the server would not let us join it.
* @throws NickAlreadyInUseException if our nick is already in use on the server.
*/
public final synchronized void connect(String hostname) throws IOException, IrcException, NickAlreadyInUseException {
public final synchronized void connect(String hostname)
throws IOException, IrcException, NickAlreadyInUseException,
NoSuchAlgorithmException, KeyManagementException
{
this.connect(hostname, 6667, null);
}

Expand All @@ -121,7 +129,10 @@ public final synchronized void connect(String hostname) throws IOException, IrcE
* @throws IrcException if the server would not let us join it.
* @throws NickAlreadyInUseException if our nick is already in use on the server.
*/
public final synchronized void connect(String hostname, int port) throws IOException, IrcException, NickAlreadyInUseException {
public final synchronized void connect(String hostname, int port)
throws IOException, IrcException, NickAlreadyInUseException,
NoSuchAlgorithmException, KeyManagementException
{
this.connect(hostname, port, null);
}

Expand All @@ -139,7 +150,7 @@ public final synchronized void connect(String hostname, int port) throws IOExcep
* @throws IrcException if the server would not let us join it.
* @throws NickAlreadyInUseException if our nick is already in use on the server.
*/
public final synchronized void connect(String hostname, int port, String password) throws IOException, IrcException, NickAlreadyInUseException {
public final synchronized void connect(String hostname, int port, String password) throws IOException, IrcException, NickAlreadyInUseException, NoSuchAlgorithmException, KeyManagementException {
_registered = false;

_server = hostname;
Expand All @@ -159,20 +170,24 @@ public final synchronized void connect(String hostname, int port, String passwor
// Connect to the server.

// XXX: PircBot Patch for SSL
if (_useSSL) {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[] { new NaiveTrustManager() }, null);
SSLSocketFactory factory = context.getSocketFactory();
SSLSocket ssocket = (SSLSocket) factory.createSocket(hostname, port);
ssocket.startHandshake();
_socket = ssocket;
}
catch(Exception e)
{
// XXX: It's not really an IOException :)
throw new IOException("Cannot open SSL socket");
if (_securityType != SecurityType.NONE){
SSLContext context = SSLContext.getInstance("TLS");
switch (_securityType){
case TLS_INSECURE:
context.init(null, new X509TrustManager[] { new NaiveTrustManager() }, null);
break;
case TLS:
/* Use default certificate validation. */
context.init(null, null, null);
break;
case TLS_FIXED_KEY:
context.init(null, new X509TrustManager[] { new FixedTrustManager(_fingerprint) }, null);
break;
}
SSLSocketFactory factory = context.getSocketFactory();
SSLSocket ssocket = (SSLSocket) factory.createSocket(hostname, port);
ssocket.startHandshake();
_socket = ssocket;
} else {
_socket = new Socket(hostname, port);
}
Expand Down Expand Up @@ -278,21 +293,24 @@ public final synchronized void connect(String hostname, int port, String passwor
* @throws IrcException if the server would not let us join it.
* @throws NickAlreadyInUseException if our nick is already in use on the server.
*/
public final synchronized void reconnect() throws IOException, IrcException, NickAlreadyInUseException{
public final synchronized void reconnect()
throws IOException, IrcException, NickAlreadyInUseException,
NoSuchAlgorithmException, KeyManagementException
{
if (getServer() == null) {
throw new IrcException("Cannot reconnect to an IRC server because we were never connected to one previously!");
}
connect(getServer(), getPort(), getPassword());
}

/**
* Set wether SSL should be used to connect to the server.
*
* @author Sebastian Kaspari <[email protected]>
*/
public void setUseSSL(boolean useSSL)
public void setSecurityType(SecurityType securityType)
{
_securityType = securityType;
}

public void setFingerprint(String fingerprint)
{
_useSSL = useSSL;
_fingerprint = fingerprint;
}

/**
Expand Down Expand Up @@ -3171,7 +3189,8 @@ else if (userMode == VOICE_REMOVE) {
// Default settings for the PircBot.
private boolean _autoNickChange = false;
private int _autoNickTries = 1;
private boolean _useSSL = false;
private SecurityType _securityType = SecurityType.NONE;
private String _fingerprint = "";
private boolean _registered = false;

private String _name = "PircBot";
Expand Down
63 changes: 59 additions & 4 deletions application/src/org/yaaic/activity/AddServerActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.yaaic.model.Identity;
import org.yaaic.model.Server;
import org.yaaic.model.Status;
import org.yaaic.ssl.FixedTrustManager;
import org.jibble.pircbot.PircBot;

import android.content.Intent;
import android.net.Uri;
Expand All @@ -44,6 +46,8 @@
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Toast;

import com.actionbarsherlock.app.ActionBar;
Expand All @@ -57,7 +61,8 @@
*
* @author Sebastian Kaspari <[email protected]>
*/
public class AddServerActivity extends SherlockActivity implements OnClickListener
public class AddServerActivity extends SherlockActivity
implements OnClickListener, OnItemSelectedListener
{
private static final int REQUEST_CODE_CHANNELS = 1;
private static final int REQUEST_CODE_COMMANDS = 2;
Expand Down Expand Up @@ -94,6 +99,7 @@ public void onCreate(Bundle savedInstanceState)
((Button) findViewById(R.id.channels)).setOnClickListener(this);
((Button) findViewById(R.id.commands)).setOnClickListener(this);
((Button) findViewById(R.id.authentication)).setOnClickListener(this);
((Spinner) findViewById(R.id.securityType)).setOnItemSelectedListener(this);

Spinner spinner = (Spinner) findViewById(R.id.charset);
String[] charsets = getResources().getStringArray(R.array.charsets);
Expand Down Expand Up @@ -123,7 +129,8 @@ public void onCreate(Bundle savedInstanceState)
((EditText) findViewById(R.id.nickname)).setText(server.getIdentity().getNickname());
((EditText) findViewById(R.id.ident)).setText(server.getIdentity().getIdent());
((EditText) findViewById(R.id.realname)).setText(server.getIdentity().getRealName());
((CheckBox) findViewById(R.id.useSSL)).setChecked(server.useSSL());
((Spinner) findViewById(R.id.securityType)).setSelection(server.securityType().ordinal());
((EditText) findViewById(R.id.fingerprint)).setText(server.fingerprint());

// Select charset
if (server.getCharset() != null) {
Expand Down Expand Up @@ -157,6 +164,8 @@ public void onCreate(Bundle savedInstanceState)
((EditText) findViewById(R.id.password)).setText(String.valueOf(uri.getQuery()));
}
}

showHide();
}

/**
Expand Down Expand Up @@ -224,6 +233,37 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data)
}
}

private void showHide()
{
Spinner v_securityType = (Spinner) findViewById(R.id.securityType);
if (v_securityType.getSelectedItemPosition() >= 0){
PircBot.SecurityType securityType = PircBot.SecurityType.values()[v_securityType.getSelectedItemPosition()];
if (securityType == PircBot.SecurityType.TLS_FIXED_KEY){
findViewById(R.id.fingerprint_label).setVisibility(View.VISIBLE);
findViewById(R.id.fingerprint).setVisibility(View.VISIBLE);
} else {
findViewById(R.id.fingerprint_label).setVisibility(View.GONE);
findViewById(R.id.fingerprint).setVisibility(View.GONE);
}
}
}

@Override
public void onItemSelected(AdapterView parent, View v, int position, long id)
{
switch (parent.getId()) {
case R.id.securityType:
showHide();
break;
}
}

@Override
public void onNothingSelected(AdapterView parent)
{

}

/**
* On click add server or cancel activity
*/
Expand Down Expand Up @@ -368,7 +408,12 @@ private Server getServerFromView()
int port = Integer.parseInt(((EditText) findViewById(R.id.port)).getText().toString().trim());
String password = ((EditText) findViewById(R.id.password)).getText().toString().trim();
String charset = ((Spinner) findViewById(R.id.charset)).getSelectedItem().toString();
Boolean useSSL = ((CheckBox) findViewById(R.id.useSSL)).isChecked();
PircBot.SecurityType securityType = PircBot.SecurityType.values()[
((Spinner) findViewById(R.id.securityType)).getSelectedItemPosition()];
String fingerprint = "";
if (securityType == PircBot.SecurityType.TLS_FIXED_KEY){
fingerprint = ((EditText) findViewById(R.id.fingerprint)).getText().toString().trim();
}

// not in use yet
//boolean autoConnect = ((CheckBox) findViewById(R.id.autoconnect)).isChecked();
Expand All @@ -379,7 +424,8 @@ private Server getServerFromView()
server.setPassword(password);
server.setTitle(title);
server.setCharset(charset);
server.setUseSSL(useSSL);
server.setSecurityType(securityType);
server.setFingerprint(fingerprint);
server.setStatus(Status.DISCONNECTED);

return server;
Expand Down Expand Up @@ -433,6 +479,15 @@ private void validateServer() throws ValidationException
throw new ValidationException(getResources().getString(R.string.validation_invalid_port));
}

PircBot.SecurityType securityType = PircBot.SecurityType.values()
[((Spinner) findViewById(R.id.securityType)).getSelectedItemPosition()];
if (securityType == PircBot.SecurityType.TLS_FIXED_KEY){
String fingerprint = ((EditText) findViewById(R.id.fingerprint)).getText().toString().trim();
if (FixedTrustManager.parseDigest(fingerprint) == null){
throw new ValidationException(getResources().getString(R.string.validation_bad_fingerprint));
}
}

try {
"".getBytes(charset);
}
Expand Down
Loading