Monday, October 10, 2011

Trouble in Android Wifi land

It has been a while since I posted last, but there are some issues with how Android handles the WPA/WPA2-Enterprise modes. Hopefully making these issues a little more public will help get them fixed. (And, before you start throwing things, yes, Google is aware of these issues.)

Let's start with an easy, common issue. Self signed certificates. There are many tutorials on the net about how to configure WPA/WPA2-Enterprise using self signed certificates. I would imagine that for any IT person that is trying to wrap their heads around 802.1X/WPA/WPA2-Enterprise, they are one of the first stops. Hopefully, Android isn't running on their primary test device.

If you attempt to use a self signed certificate on Android, it will usually fail. I have run across the occasional device that doesn't have this problem, but 'stock' Android like that found on the Nexus series generally has this problem.

Not being able to use self signed certificates is annoying, and it leads us nicely in to the next Android annoyance. To paraphrase, "If an Android fails to authenticate, and nobody is watching the logs, did the authentication actually fail?" I think the best answer is, "If I didn't get my network access, then yes, it failed." However, because Android didn't tell you that it failed, you may be sitting there for some time before you realize something is wrong.

Let's jump back to the self signed certificate issue I mentioned above. I like to say that in the event of an error case, the program usually has some idea of what went wrong. It just needs to present that information to the user in a useful way. This case is no different.

Under the hood, Android uses wpa_supplicant to handle authentication 802.11 management and authentication. In the self signed certificate case, wpa_supplicant will produce an error such as this :

TLS: Certificate verification failed, error 18 (self signed certificate)

This error is usually surrounded with a bunch of OpenSSL error codes so many people just "check out" when reading the logs, and don't notice it. On Android, it is a little bit worse. This error message is buried in a log that the average user probably doesn't even know exists. So, how does the user know what went wrong?

In this example, the user figures it out after sitting there for a while and they don't get a connection to the network. But, once they have come to the conclusion that they can't get on the network, what are they supposed to do? Worse, what is the helpdesk call going to sound like? I need you to summon your best red-neck, inbred, hillbilly with buck teeth accent and said, "It's broke". ("It don't work" is another wonderfully helpful description.)

Since most users have a really short attention span, at this point they wander off to complain to anyone they can that the network is broken. When a coworker or friend says, "Yeah, but it works for me." that will change to "Wireless is broken on Android."

The reality is that Android's wireless is NOT broken. Well, maybe not very broken. When the wireless hardware is behaving itself, wpa_supplicant does a fine job of getting you connected. You just have to be running something like CatLog, or have a development environment set up that will let you run "adb logcat". Then, you have to know enough about 802.1X authentications, and certificates to be able to recognize the one log line that tells you everything you need to know about the failure. That should be easy enough. (In case you are missing my sarcasm, consider trying to talk your mom through figuring this out over the phone.)

While I use the self-signed certificate issue as an example of the problem, it is just the tip of the iceberg. Other similar issues, that you won't hear about, include :

  • The certificate isn't yet valid.
  • The certificate is no longer valid.
  • Your authentication failed.
  • MS-CHAPv2 messages such as 'invalid password', or 'your password has expired'.
  • And many, MANY others.

Let's assume that you understand these issues, have the tools to figure them out when they happen, and work in a small enough business that the helpdesk can go through this dance with everyone in the company. Out of nowhere, you get slammed with an issue you CAN'T fix!


Here, you will find your next issue. Section F, item 2 basically says that CAs can no longer sign certificates with their root certificate. Or, in other words, all certificates have to be signed by an intermediate CA cert. Now, I understand that Microsoft isn't a standards setting body, so CAs don't have to comply with these rules. However, as Microsoft is still a dominant OS provider, CAs that don't comply won't be allowed in the shipping Microsoft cert store. Based on this, it is pretty reasonable to assume that most CAs will follow these rules.

The problem this creates for Android shows itself when you try to install a chain of certificates on Android. I was unable to find any sane way that worked. Digging in the Android source code seems to indicate that cert chains can be installed using PKCS#12 certificate bundles. However, Android seems to insist that PKCS#12 certificate bundles contain a user cert. In other words, if you are using anything but EAP-TLS, you probably can't use PKCS#12 bundles to get your certificates in the store.

It may seem reasonable that creating a PEM file that has multiple certificates in it would get around this issue. However, if you try that, you are presented with the following dialog :




Note that the dialog indicates that there is only one CA certificate that will be installed. If you complete the installation, and set up a new wireless authentication using this certificate, you will find the connection doesn't work. If you happen to have CatLog, or a development machine around you will see in the logs that the certificate chain failed to validate.

If you can't use self signed certificates, and can only buy certificates that are chained, it starts to become clear that the 802.1X/WPA-Enterprise/WPA2-Enterprise authentication on Android is darn near unusable. You either need to find a CA that is willing to go against Microsoft. Or, you have to choose not to use certificates in your authentications. (Which, is a *BAD* idea!)

I just want to restate that Google has been made aware of these issues. However, it was recent enough that they probably haven't had time to do anything about it, let alone get anything fixed and released. Also, since I get really annoyed with people that like to complain, but don't offer any real solutions, I will be submitting patches to Google that will hopefully start to fix some of these issues. At a minimum, hopefully Google can use my patches as a jumping off point for a good fix.

Monday, April 11, 2011

Color changing rounded rectangles and Android

I recently came across an interesting problem. I needed to have a rounded rectangle as the background of one of my widgets, but I needed to allow the border color of the rounded rectangle to be set by a configuration setting.

Before the color changing requirement showed up, I was using a 9-patch to create my rounded rectangle. It was simple, and worked quite well. So, after some digging I came to the conclusion that I would need to change the colors in the 9-patch image in order to achieve my goals. I ended up burning a lot of time trying to figure out how to do this. (It isn't as simple as changing the colors in a normal .png file, unfortunately.)

While digging, I came across this post that hinted that I might not need the 9-patch to do what I wanted. But, the documentation for the shape XML is pretty much non-existent. Which made things hard.

A little more digging found an article that linked to this page. This provided me the attributes for the XML that allow me to do what I needed to do. So, I set out to give it a shot. I started with a rounded rectangle with a white background and a black line around the outside. The XML looked like this :

<!--?xml version="1.0" encoding="utf-8"?-->
<shape android="http://schemas.android.com/apk/res/android" shape="rectangle">
<solid color="#ffffffff">
<stroke width="2dip" color="#ff000000">
<corners radius="75dip">
</corners></stroke></solid></shape>


When I created the XML file in eclipse, there wasn't an option to create a shape XML file. So, I picked one of the other types, and just deleted what was automatically created, and replaced it with the code above. However, I also needed to move the XML file so that it was in the drawable directory. (If you are like I was, you are thinking, "But an XML file isn't a drawable!" But, you'll just have to trust me.)

This provided me the basic rounded rectangle that I needed. But, changing colors on-the-fly was still an issue. After a bit of digging, I found that using this XML to create a drawable would give me everything I needed to get the job done.

I decided to set the background for the layout that contained everything I was going to use. (Which is why I am using a LinearLayout instead of some other widget. But, any widget that allows a background to be set should work.)

For a test, I changed my onCreate() method to include this code :

workareaLayout = (LinearLayout)findViewById(R.id.rightColumnInner);

GradientDrawable sd = (GradientDrawable)this.getResources().getDrawable(R.drawable.roundrect);
sd.setColor(0xff00ff00);
sd.setStroke(10, 0xffff0000);
workareaLayout.setBackgroundDrawable(sd);

This created a nice rounded rectangle that is suitable for Christmas. (It has a green background with a large red border.)

The sd.setColor() call sets the background color for the rectangle. The color is an ARGB value, so we start with 0xff since we don't want any transparency. The 00ff00 portion indicates that we want to be the brightest green we can have.

The sd.setStroke() call specifies the width of the border line, along with the color. For this example, the width is 10, and the color is bright red, with no transparency. The documentation isn't clear what a width of "10" means. (Is it pixels? Or one of the other measures commonly used in Android development?) But, it appears that it is probably pixels.

And with that, you should have the ability to create all kinds of crazy rounded rectangles. However, keep in mind that this same method should work for other types of shapes that can be created with the shape XML.