On Feb 14, 2013, at 4:00 PM, Jonathan Pryor <[email protected]> wrote:
> I'll provide that code in a bit; if that doesn't help you, let's see about 
> getting a full repro...

Bwa-ha-ha-ha-ha-ah-ha *cough* *splutter*

Firstly, the links I previously provided have been invalidated due to 
refactoring (yay). That'll teach me to provide links into "master" instead of a 
proper revision. The mythical processSignJellyBeans() method is now at:

        
http://code.google.com/p/ics-openvpn/source/browse/src/de/blinkt/openvpn/VpnProfile.java?spec=svn77efc1af3b4d7a02864f21eb93a92f8568e9f5f0&r=77efc1af3b4d7a02864f21eb93a92f8568e9f5f0#806

The processSignJellyBeans() method does two things:

1. Extract the "integer pointer to EVP_pkey" from the PrivateKey.
2. Sign data with it.

(1) is reasonably straightforward:

        // ~line by line port of part of processSignJellyBeans():
        // 
http://code.google.com/p/ics-openvpn/source/browse/src/de/blinkt/openvpn/VpnProfile.java?spec=svn77efc1af3b4d7a02864f21eb93a92f8568e9f5f0&r=77efc1af3b4d7a02864f21eb93a92f8568e9f5f0#806
        public static int GetPrivateKeyHandle (IPrivateKey privkey)
        {
            var _privkey                        = 
privkey.JavaCast<Java.Lang.Object>();
            IntPtr privkey_class                = 
_privkey.Class.Superclass.Handle;
            IntPtr getKey                       = JNIEnv.GetMethodID 
(privkey_class, "getOpenSSLKey", 
"()Lorg/apache/harmony/xnet/provider/jsse/OpenSSLKey;");
            IntPtr opensslkey                   = JNIEnv.CallObjectMethod 
(privkey.Handle, getKey);
            IntPtr opensslkey_class             = JNIEnv.GetObjectClass 
(opensslkey);
            IntPtr opensslkey_getPkeyContext    = JNIEnv.GetMethodID 
(opensslkey_class, "getPkeyContext", "()I");
            int pkey                            = JNIEnv.CallIntMethod 
(opensslkey, opensslkey_getPkeyContext);

            JNIEnv.DeleteLocalRef (opensslkey);
            JNIEnv.DeleteLocalRef (opensslkey_class);

            return pkey;
        }

The only "requirement" here is having an Android source checkout to help create 
the JNI method signatures for method lookup.

(2) is the "interesting" bit, and by "interesting" I mean "start praying to 
your favorite deity."

What ics-openvpn's de.blinkt.openvpn.VpnProfile.processSignJellyBeans() method 
does is call the `native` VpnProfile.rsasign() method, which (as mentioned 
earlier) isn't entirely possible right now because JNIEnv.Handle isn't public.

That's actually easily worked around; just use .NET reflection to grab the 
JNIEnv.Handle property value. However, that's not the real problem.

Alternatively, the native VpnProfile.rsasign() function could be ported to C#. 
I don't think this would be too difficult:

        http://code.google.com/p/ics-openvpn/source/browse/jni/jbcrypto.cpp#44

Again, that's not the real problem.

The real problem is that it looks like ics-openvpn works by embedding a COPY of 
openssl into ics-openvpn!

        http://code.google.com/p/ics-openvpn/source/browse#hg%2Fopenssl

We are no longer in the realm of Java vs. C#. We're in the realm of "what 
dependencies do you want your project to have?"

If your app can depend on an ics-openvpn binary/package being installed on the 
target device (can it?), then you should be able to derive a P/Invoke into 
libopvpnutil.so!Java_de_blinkt_openvpn_VpnProfile_rsasign():

        [DllImport 
("/data/data/@TODO_ics-openvpn_PACKAGE_NAME@/lib/libopenvpnutil.so")]
        static extern IntPtr Java_de_blinkt_openvpn_VpnProfile_rsasign (IntPtr 
env, IntPtr klass, IntPtr array, int pkeyRef);

        public static IntPtr GetJniEnvHandle ()
        {
            var handleP = typeof(JNIEnv).GetProperty ("Handle", 
BindingFlags.NonPublic | BindingFlags.Static);
            if (handleP == null)
                throw new NotSupportedException ("This doesn't look like Mono 
for Android...");
            var handle = (IntPtr) handleP.GetValue (null, null);
            if (handle == IntPtr.Zero)
                throw new InvalidOperationException ("Unpossible!");
            return handle;
        }

        ...

        byte[] data = ...
        IntPtr javaData = JNIEnv.NewArray(data);
        IntPtr signedJavaData = Java_de_blinkt_openvpn_VpnProfile_rsasign 
(GetJniEnvHandle (), IntPtr.Zero, javaData, GetPrivateKeyHandle (privkey));
        byte[] signedData = JNIEnv.GetArray<byte>(signedJavaData);
        JNIEnv.DeleteLocalRef(signedJavaData);

If your app can't depend on ics-openvpn being installed...then you need to do 
what they're doing: embed openssl into your app, at which  point you can port 
Java_de_blinkt_openvpn_VpnProfile_rsasign() to C# and just P/Invoke into your 
embedded openssl for the implementation.

What's "interesting" is that stackoverflow suggested that you could use 
libkeystore.so, but I don't see how this would help (particularly as I don't 
see an RSA_sign() export in libkeystore.so):

        http://stackoverflow.com/a/11387344/83444

So I fail to see how libkeystore.so would be useful here. :-/

All of the above makes me wonder if we're missing something. 
android.security.KeyStore looks entirely useless, as you can't get anything out 
of it, so what's the point?

It would appear, then, that using HttpsURLConnection is (hopefully?) the way to 
go.

By any chance could you create a small repro for NullReferenceException? Or 
does it only occur in this environment?

 - Jon

_______________________________________________
Monodroid mailing list
[email protected]

UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid

Reply via email to