As3Crypto 1.3 is out, TLS support is in.

There we go, Flash now has a TLS 1.0 implementation written entirely in ActionScript.

In spite of my previous post, I didn’t feel right releasing something that didn’t have a shot at protecting against Man-in-the-middle attacks, so I took a few more days to implement some X.509 certificate parsing and validating.
This release ships with a number of well-known Certificate Authorities, so you should be able to use the lib to connect to public TLS-enabled services easily.

The easiest way to get started is with TLSSocket. Check out TLSTest.as for some sample code using it.

As an aside, RSAKey.as now has sign/verify methods, which get used by X509Certificate.as.

I reverted a change I talked about in the last post, namely the existence of some odd “rc4block” cipher. It’s not needed, so it’s gone.

Here are the release notes for this version:

- TLS: partial TLS 1.0 support (RSA only), with TLSSocket and STARTTLS support.
- cert: Basic X509 (v1 and v2) Certificate parsing and validation
- cert: Builtin Root CAs, ripped from Mozilla. (see MozillaRootCertificates.as)
- DER: bug fix in parsing of UTCTime
- DER: limited support for outputing ASN-1 structures as DER (as little as needed for X509 cert. signing to work.)
- RSA: support for RSA signing/verifying (needed for TLS cert validation)
- hash: MD5 and MD2 classes no longer alter their source data
- secret key: RC4 doesn’t reset its state before every encrypt/decrypt operation anymore.
If you need that behavior, you need to use .init(key) before each call.

So where do we go from here? Well, that’s a whole lot of new code, so expect a release or two dedicated to stabilizing the code base. I’m also falling behind on my test coverage, and I don’t even have a demo UI to showcase TLS.

That should keep me busy for a little while.

By the way, if you guys are using this library in some public project, please write a quick comment with a URL to your project.
I’d like to keep a list of projects somewhere on the site.

Explore posts in the same categories: Security, web, flash, actionscript

34 Comments on “As3Crypto 1.3 is out, TLS support is in.”

  1. LEE Says:

    Wow, nice update!!

  2. Chris Says:

    Very anxious to try out the new TLS stuff. This was a very big hole in AS3 until now. Thanks for the hard work on such a necessary library!

  3. Dean Says:

    Hi, I have been waiting for TLS for a while, thanks for taking the time to implement it :)

    I willl be including the entire AS3Crypto library in my project, I will give you a link once it reaches the beta stages.

    Thanks again for the great work, keep it up!

  4. llangolas Says:

    We want to use the AS3Crypto 1.3 with the DES (or 3DES) encryption to secure some data which is send to a .net asp 2.0 webservice.
    Unfortunately we get the general error (bad data) when we start to decrypt the data in the .net world.
    The problem is that the .net/windows crypt implementation doesnīt give more infos what went wrong and we also couldnīt go into code cause its not open source ;(.
    So I assume that somebody has already tried a similar example and I really would appreciate if someone could bring some light into the darkness of “bad data” ;)

    I hope the blog is the correct place to get an answer to my question (otherwise please delete the entry )

    best regards,
    llangolas

  5. llangolas Says:

    Hi all,

    finally I solved our problem with the 3DES of .net. I have to use the PKCS#5 padding when using the 3DES .net implementation.

    I will post a link to the application if the app is ready for launch ;)
    The app is a webclient frontend for a agency search and news production system (connected via asp.net webservice and backended with a MS SQL server 2005 db ).

    best regards
    llangolas

  6. ido Says:

    Is there any demo using this class with an FLA file?

  7. Ignacio Alles Says:

    It would be useful during development to disable some security checks, like requiring a CA signed certificate or that the common name matches the domain we are connecting to. If you like, I can send you those modifications I’ve made in the source code.

  8. Metal Hurlant Says:

    llangolas: Cool. I’m wondering whether PKCS#5 should be applied by default. Right now, one has to explicitly set that padding.

    Ido: Not from me. I don’t have the Flash IDE. If a kind soul puts together

    Ignacio Alles: That’s true.
    Right now, It is possible to create a TLSConfig object that adds your own CA, which would let you sign your own certificates for testing.
    I’ve been considering adding a few flags to override the default stricter behaviors. Ideally, it should be done through TLSConfig as well.

  9. Bjorn Harvold Says:

    This is really cool! You should put up a donate link you know. You did a good job and you’re giving support.

  10. Gabe Says:

    I found a bug in the cert identity check not supporting wildcards.. (e.g. Invalid common name: *.s3.amazonaws.com, expected http-test.s3.amazonaws.com)

    I have a patch for TLSEngine, if you want it, shoot me an email.

    Basically instead of doing a ==, you use a regex:

    var escaped:String = regexEscape(firstCert.getCommonName());
    var reg:String = escaped.replace(/\\\*/g, “[^.]+”)
    if (new RegExp(reg).exec(_otherIdentity)) {

    The function to escape regular expression characters:

    // Regexp.escape(’\\*?{}.’) #=> \\\\\*\?\{\}\.
    private function regexEscape(s:String):String {
    return s.replace(/([\\*?{}.])/g, “\\$1″);
    }

    And the *.s3.amazonaws.com becomes: [^.]+\.s3\.amazonaws\.com

  11. Metal Hurlant Says:

    Gabe: Thanks! I’ll put a patch in for that on the next release.

    Bjorn: Thanks for the kind words, but money ain’t free, and I want to keep doing this for fun, untainted by a vague sense of obligation.

  12. Bobby Parker Says:

    So question…

    Looking at TLSEngine/TLSSocket, I’m very excited by it, but I’m in dire need of SSL 3.0 vs. TLS 1.0. Just how difficult do you think it’s going to be patch TLSEngine to support SSL 3.0? Preliminary research has given me some good information, but I’d like a bit of feedback from you on it, if at all possible.

    This is for a socket-based Air application, just so you know, that requires an SSL socket to odd port numbers.

  13. Gonzalo Says:

    I have some problems reading the public key of RSA.
    I tried running your test case, but rsa is always assigned to null:
    var pem:String = “—–BEGIN PUBLIC KEY—–\n” +
    +
    “—–END PUBLIC KEY—–”;
    var rsa:RSAKey = PEM.readRSAPublicKey(pem);
    here rsa is always null.

    Any ideas? I’m using Flex Builder 3 to run and test the code

  14. Gonzalo Says:

    By the way the error says:
    “I DONT KNOW HOW TO HANDLE DER stuff of TYPE 24″

    And the private key reading works ok.

  15. Gonzalo Says:

    I think I solved it, but please check it.
    In the readRSAPublicKey function (PEM.as file) you have:

    arr[1].position = 1; // there’s a 0×00 byte up front. find out why later. like, read a spec.

    But I realized that that was not true in my case, so I change that line with this one (taken from the bit string reading):

    if (arr[1][arr[1].position]==0) { arr[1].position++; }

    and now everything works :) Hope that helps to others.

  16. Metal Hurlant Says:

    Bobby: Good question.
    I had somehow hoped TLS was widespread enough that this wouldn’t come up. At least that’s how I justified not implementing SSL 3.0. Off the top of my head, the negotiation part would need to accept both 3.0 and 3.1 versions. With 3.0, the way secrets are computed is different, so that would need to be tweaked accordingly:
    TLS uses HMAC, while SSL uses a different MAC algorithm. The PRF algorithm ends up being different, and there’s some tweaks in the way the FINISHED payloads are computed. There might be a bit more, but that’s the gist of it.
    In practice, the hard part is not so much implementing the spec, but debugging the code you end up with. That’s why this TLS implementation includes a TLS server. It’s not terribly useful for as3 apps, but it helped to debug things a bit. To get it to interoperate properly with existing implementations, I also had to compile a version of openSSL, then add debug messages at each point of failure to understand why it didn’t like my packets.
    Conservatively, I’d guess it’d take someone about 2 weeks to put that together.

    Gonzalo: Woops. You’ve bumped into some ugly corner of my code. I plan to rewrite that particular chunk. I’ll make sure that case is covered.

  17. Dreaming in Flash Says:

    As3Crypto

    There we go, Flash now has a TLS 1.0 implementation written entirely in ActionScript.

  18. Andrew Westberg Says:

    I found a bug in RSAKey although I’m not sure what’s causing it. To reproduce it, do the following.

    1.) Generate a random byte array of length 100 to encrypt.
    2.) Create an RSAKey
    3.) Encrypt the same 100 byte array in an infinite loop using the RSAKey and checking the length of the dst byte array after each iteration. Most times, the length comes out to 128 which is correct, but occasionally, it will come back with only 127 bytes.

    Right now, I’m using a hack I put at the bottom of the _encrypt method in RSAKey to re-run the function if something incorrect happened.

    if(dst.length % 2 == 1)
    {
    //something bad happened during encryption. try it again until we get it right
    dst.position = 0;
    dst.length = 0;
    src.position = 0;
    _encrypt(op, src, dst, length, pad, padType);
    }

  19. andrewl Says:

    Great work. I’ve needed a way to implement a full REST API in AS3 for awhile. I’m using the TLSSocket as the underlying data transport mechanism to achieve that. One thing though, I keep getting an EOF error from TLSEngine. It seems to be where you’re pulling the server’s cypher suite from the ServerHello handshake (line 434). For testing, I just make sure to set the position of the ByteArray to 39 before reading the cypher suite. That seems to work with all of the services I’ve hit so far; not sure if it would work in the wide world though.

  20. OJDX Says:

    Is there a way to allow self signed certs to work on localhost for dev purposes?

  21. Jacob Says:

    It’s quite a lib you have there :) . I’ve a question bout it. Do you support only unsigned keys without passphrase for RSA? We’ve encrypted asset and actually we’re stuck on trying to decode it. Even though key seems to be working good now, while using ‘decrypt’ i get : PKCS#1 unpad: i=0, expected b[i]==[0,1,2], got b[i]=12 . Probably i’m doing something way off line here.

    I’ve encrypted asset in base64, as i encode it with ‘decodeToByteArray’ and pass it to ‘decrypt’ i still get an error. Any clues ?

    Thanks a bunch in advance!

  22. Andy L. Says:

    There’s a bug in the handshake parsing routine (at least that’s the only place I’ve seen it) where you determine the length of the session, and then read the session from the record ByteArray into a new ByteArray using the current position as the offset and the session length as the number of bytes to read. The problem is, if the session length is 0, the default behavior of readBytes is to read from the current position to the end of the array. Obviously, that’s not the intended behavior, but that’s what’s happening. (TLSEngine, line 424-426)

    Great work all around though! Very useful stuff, now if Adobe hadn’t gone and made it near impossible to use sockets from web delivered apps, we could have full HTTP support.

  23. Cameron Says:

    I’m running into an error while trying to establish a connection to the del.icio.us API. Gabe, the helpful guy behind as3httpclient, said “it
    looks like as3crypto doesn’t support the TLS client key exchange (only
    RSA is supported)” and suggested I ask here for help.

    My knowledge of the intricacies of TLS/SSL is non-existent and I’m unsure what the actual problem is!

    Here’s sample code which demonstrates the problem;

    var t:TLSSocket = new TLSSocket;
    t.connect(”api.del.icio.us”, 443);
    t.writeUTFBytes(”GET /v1/tags/get HTTP/1.0\nHost: api.del.icio.us\n\n”);
    t.addEventListener(Event.CLOSE, function(e:*):void {
    var s:String = t.readUTFBytes(t.bytesAvailable);
    trace(”Response: “+s);
    });

    and the error itself;

    [trace] Error: Error #2030: End of file was encountered.
    [trace] at flash.utils::ByteArray/readShort()
    [trace] at com.hurlant.crypto.tls::TLSEngine/parseHandshakeHello()
    [trace] at com.hurlant.crypto.tls::TLSEngine/parseHandshake()
    [trace] at com.hurlant.crypto.tls::TLSEngine/parseOneRecord()
    [trace] at com.hurlant.crypto.tls::TLSEngine/parseRecord()
    [trace] at com.hurlant.crypto.tls::TLSEngine/dataAvailable()

    Thanks for any help :)

  24. Simon Chen Says:

    Hello, everyone:
    I am testing the AS3Crypto lib now. I find it gives the error said “TLSEngine shutdown triggered by Error: Cannot verify certificate” when I use TLSSocket to connect OpenSSL TLS Server. Is there anyone having the same problem or having any solution or having any hint to solute this problem. Please email me or post the solution. Thanks!

  25. Simon Chen Says:

    The function “firstCert.isSigned(_store, _config.CAStore)” in the TLSEngine seems to have problems when parsing some certficate. For example, it will return “TLSEngine shutdown triggered by Error: Cannot verify certificate” when it access www.openssl.org. Are there soutions? thanks!

  26. Szabolcs Nagy Says:

    Hi, your library is very promising, altough I’ve ran into errors when tried to using it.

    First I’ve tried to connect to an openssl server using openssl self-signed certificates.
    Openssl server reports “bad certificate” error and shuts down the connection. I think the problem is, that the client cannot fully verify the server certificate ’cause the CA certificate not in the client’s cert store. (hostname and CN are equal)
    So ‘ve tried to add the CA certificate to the client’s store. No error building the client but the server still reports “bad certificate” error.
    Here’s my code-snippet, can you give me any suggestion what did I wrong?

    public function testSocket():void {

    testHost(”opensslsrv”);
    }

    private function testHost(host:String):void {
    if (host==null) return;
    var t1:int = getTimer();
    var host:String = host;
    var t:TLSSocket = new TLSSocket;
    t.connect(host, 443);
    // var s:Socket = new Socket(”login.yahoo.com”, 443);

    var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT);
    // var client:TLSEngine = new TLSEngine(clientConfig, t, t);

    // put the server cert in the client’s trusted store, to keep things happy.
    clientConfig.CAStore = new X509CertificateCollection;
    var x509:X509Certificate = new X509Certificate(PEM.readCertIntoArray(”—–BEGIN CERTIFICATE—–\n”+
    “MIICOzCCAaQCAxAAATANBgkqhkiG9w0BAQQFADCBgDEQMA4GA1UEChMHT3BlbklU\n”+
    “eTEhMB8GCSqGSIb3DQEJARYSb3Blbml0eUBvcGVuaXR5Lmh1MQ0wCwYDVQQHEwRH\n”+
    “eW9yMRMwEQYDVQQIEwpHeW9yLU1vc29uMQswCQYDVQQGEwJIVTEYMBYGA1UEAxMP\n”+
    “T3BlbklUeSBDQSBSb290MB4XDTA4MDQxNzIzMDU1N1oXDTA5MDQxNzIzMDU1N1ow\n”+
    “STELMAkGA1UEBhMCSFUxEzARBgNVBAgTCkd5b3ItTW9zb24xEDAOBgNVBAoTB09w\n”+
    “ZW5JVHkxEzARBgNVBAMTCm9wZW5zc2xzcnYwgZ8wDQYJKoZIhvcNAQEBBQADgY0A\n”+
    “MIGJAoGBALy2QYbD1eUevQeZ69P3oSDs76ubfszBLCaMRrofgGhQiuLTjomSN6Fh\n”+
    “bAxbYya+AkqVBx61F4AP1+c/a6n4FkgBjiPVLwL4I+YHdLq04h5tzA0zZuuiUKAF\n”+
    “nHOhZq/yxeQuYajGV1KfHOukD41PMdI/XgsEJlYMxOL9Gkc8hwJ7AgMBAAEwDQYJ\n”+
    “KoZIhvcNAQEEBQADgYEAdGiZjLr2lbtMdn+iDf5WrorLJeFZIek8nTfmEPHEmOy6\n”+
    “2DiVS4BpvFpzFiHeg54neEEdCFBjl68mwtjhtazMdQb28SZPxjxrYo2Tdj1hz7jV\n”+
    “y8oySz5gvQM7tzRw27moeHQV4sTwaooHvggiIglVDz6OafZihoRC92y1lcrvh1s=\n”+
    “—–END CERTIFICATE—–”));

    clientConfig.CAStore.addCertificate(x509);

    t.writeUTFBytes(”GET /test.png HTTP/1.0\r\nHost: “+host+”\r\n\r\n”);
    t.addEventListener(Event.CLOSE, function(e:*):void {
    var s:String = t.readUTFBytes(t.bytesAvailable);
    Text1.text += “Response from “+host+”: “+s.length+” characters” + s +”\n”;
    Text1.text += “Time used = “+(getTimer()-t1)+”ms” + “\n”;
    });
    }

  27. Szabo Jean Says:

    I try your exemple for reading public RSA Key, but I have this error :

    I DONT KNOW HOW TO HANDLE DER stuff of TYPE 24

    the code in test :

    public function testPEM2():void {
    var pem:String = “—–BEGIN PUBLIC KEY—–\n” + “MCwwDQYJKoZIhvcNAQEBBQADGwAwGAIRAMkbduS4H0h7uM6V1BNV3M8CAwEAAQ==\n” +
    “—–END PUBLIC KEY—–”;
    var rsa:RSAKey = PEM.readRSAPublicKey(pem);
    //trace(rsa.dump());
    }

  28. Mauricio Says:

    I have a requirement to encrypt a string using the Rijndael algorithm in Actionscript 3, I was wondering if your AES implementation could do it. The customer sent me a key and an IV, both with 16 chars (hex). I am still studying this and your library, maybe I will need to implement this algorithm myself?

  29. Tracy Spratt Says:

    Mauricio, I have almost successfully used this library for straight DES encryption. What I did was to take the Demo app code and clip out the necessary lines, hard code some values and such.

    What is odd is it works for text values (eg. “MyString”), but does not work for values that look like numbers (eg. “2008″). If anyone has any idea about this please post.

    I will post my encryption function below for your convenience.

    Tracy

    private function encrypt(sClear:String):String
    {
    var baKey:ByteArray = Hex.toArray(Hex.fromString(_sPrivateKey));;
    var baData:ByteArray = Hex.toArray(Hex.fromString(sClear));
    var cipher:ICipher = Crypto.getCipher(”des-cbc”, baKey, new PKCS5(8));
    var ivmode:IVMode = cipher as IVMode;
    ivmode.IV = Hex.toArray(Hex.fromString(_sInitVector));
    cipher.encrypt(baData);
    var sEncrypted:String = Hex.toString(Hex.fromArray(baData));
    var oEncoder:Base64Encoder = new Base64Encoder();
    oEncoder.encode(sEncrypted);
    return oEncoder.toString();
    }//encrypt

  30. Bobby Parker Says:

    Hiya,

    As promised earlier, I added SSL 3.0 support to the As3Crypto library. (Well, did so months ago, but have been busy, haven’t had a chance to get in and actually like, add a comment).

    Anyway, here it is in all it’s unholy glory!

    http://www.stormwind-studios.com/public/As3Crypto-With-SSL30.zip

    Do have a blast. Feel free to complain if something doesn’t work quite right…

    Also, note that I added a function that releases the hold on the raw socket (i.e. collapses SSL, but leaves the underlying connection intact). This was necessary to support something specific for my purposes, so feel free to strip it if you don’t need it.

  31. andi Says:

    Hi,

    thanks for your great linrary. I’m trying to use the blowfish algorithm, but unfortunately the decrypt won’t work. Now I found out, that on your demo page, the same exception occurs if you click decrypt.

    It would be great if you can try it and give me a hint for that.

    Thanks, Andi

  32. andi Says:

    Sorry for asking dump questions (my previous comment). It took some time, but finally I found out, that there is a problem if the encrypted string will be used without base64 encoding. Same thing happens on your demo page.

    As soon as the output encoding is set to base64, all works very well.

  33. Mike Says:

    I haven’t been able to perform a SHA1withRSA signing such that the signed data would be successfully validated server-side (in this case, Google’s OAuth). Here is how I’m doing it:

    //hash the base string using SHA1
    var sha1:SHA1 = new SHA1();
    var btBase:ByteArray = Hex.toArray(Hex.fromString(sBaseString));
    var btHashed:ByteArray = sha1.hash(btBase);

    //sign via RSAKey
    var rsa:RSAKey = PEM.readRSAPrivateString(PRIVATE_KEY_);
    var dst:ByteArray = new ByteArray();
    rsa.sign(btHashed, dst, src.length);

    //assign to OAuth field
    urlVars.oauth_signature = Base64.encode(Hex.fromArray(dst));

    I’ve compared the results of each phase (hashing and signing) with OpenSSL results and found that the hashing does match OpenSSL’s results. However, I can’t get the signing to work. What am I doing wrong?

    Thanks,
    Mike

  34. Milos Says:

    Hi, thank you for this great library.

    I’m writting AIR smtp client and I implemented TLS authentification
    in smtpMailer (http://www.bytearray.org/?p=27) and it works fine, but I have problems with sending mails that are greater than 16834bytes. It seams the problem is somewhere in the mail fragmentation, maybe in sendApplicationData function in TLSEngine. So if you could help me about this I’ll appreciate it very much. Thanks.

Comment: