Add support for OpenSSL ENGINE for keystore

keystore now has an OpenSSL ENGINE frontend that can be used to ask for
private keys or public keys to be loaded and also signing operations to
take place. Use that instead of the crazy byte-array marshalling of the
private key material that is used for the "privsep" stuff.

Change-Id: I6171ca1fb0e77e338c19f04d8c34ad7744984b63
diff --git a/Android.mk b/Android.mk
index 3a1c65f..c7ac4d7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -62,7 +62,7 @@
 
 LOCAL_SHARED_LIBRARIES := libcutils libcrypto
 
-LOCAL_CFLAGS := -DANDROID_CHANGES -DHAVE_CONFIG_H
+LOCAL_CFLAGS := -DANDROID_CHANGES -DHAVE_CONFIG_H -DHAVE_OPENSSL_ENGINE_H
 
 LOCAL_CFLAGS += -Wno-sign-compare -Wno-missing-field-initializers
 
@@ -78,7 +78,7 @@
 	src/libipsec/pfkey.c \
 	src/libipsec/ipsec_strerror.c
 
-LOCAL_CFLAGS := -DHAVE_CONFIG_H
+LOCAL_CFLAGS := -DHAVE_CONFIG_H -DHAVE_OPENSSL_ENGINE_H
 
 LOCAL_CFLAGS += -Wno-sign-compare -Wno-missing-field-initializers
 
diff --git a/main.c b/main.c
index 2976ecc..d2e815e 100644
--- a/main.c
+++ b/main.c
@@ -27,6 +27,8 @@
 
 #ifdef ANDROID_CHANGES
 
+#include <openssl/engine.h>
+
 #include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -156,9 +158,17 @@
 {
 #ifdef ANDROID_CHANGES
     int control = android_get_control_and_arguments(&argc, &argv);
+    ENGINE *e;
     if (control != -1) {
         pname = "%p";
         monitor_fd(control, NULL);
+
+        ENGINE_load_dynamic();
+        e = ENGINE_by_id("keystore");
+        if (!e || !ENGINE_init(e)) {
+            do_plog(LLV_ERROR, "ipsec-tools: cannot load keystore engine");
+            exit(1);
+        }
     }
 #endif
 
@@ -194,6 +204,12 @@
             }
         }
     }
+#ifdef ANDROID_CHANGES
+    if (e) {
+        ENGINE_finish(e);
+        ENGINE_free(e);
+    }
+#endif
     return 0;
 }
 
diff --git a/src/racoon/oakley.c b/src/racoon/oakley.c
index 183ac2f..c446bbb 100644
--- a/src/racoon/oakley.c
+++ b/src/racoon/oakley.c
@@ -40,6 +40,9 @@
 
 #include <openssl/pkcs7.h>
 #include <openssl/x509.h>
+#ifdef ANDROID_CHANGES
+#include <openssl/engine.h>
+#endif
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -1799,6 +1802,44 @@
 }
 #endif
 
+#ifdef ANDROID_CHANGES
+static vchar_t* keystore_sign(vchar_t* src, const char* path) {
+	vchar_t* sig = NULL;
+
+	ENGINE* e = ENGINE_by_id("keystore");
+	if (!e) {
+		return NULL;
+	}
+
+	if (!ENGINE_init(e)) {
+		ENGINE_free(e);
+		return NULL;
+	}
+
+	const char *key_id;
+	if (sscanf(path, pname, &key_id) != 1) {
+		do_plog(LLV_ERROR, "couldn't read private key info\n");
+		return NULL;
+	}
+
+	EVP_PKEY* evp = ENGINE_load_private_key(e, key_id, NULL, NULL);
+	if (!evp) {
+		do_plog(LLV_ERROR, "couldn't retrieve private key");
+		ERR_clear_error();
+		return NULL;
+	}
+
+	sig = eay_rsa_sign(src, evp->pkey.rsa);
+
+	EVP_PKEY_free(evp);
+
+	ENGINE_finish(e);
+	ENGINE_free(e);
+
+	return sig;
+}
+#endif
+
 /* get signature */
 int
 oakley_getsign(iph1)
@@ -1820,6 +1861,9 @@
 		getpathname(path, sizeof(path),
 			LC_PATHTYPE_CERT,
 			iph1->rmconf->myprivfile);
+#ifdef ANDROID_CHANGES
+		iph1->sig = keystore_sign(iph1->hash, path);
+#else
 		privkey = privsep_eay_get_pkcs1privkey(path);
 		if (privkey == NULL) {
 			plog(LLV_ERROR, LOCATION, NULL,
@@ -1830,6 +1874,7 @@
 		plogdump(LLV_DEBUG2, privkey->v, privkey->l);
 
 		iph1->sig = eay_get_x509sign(iph1->hash, privkey);
+#endif
 		break;
 #ifndef ANDROID_PATCHED
 	case ISAKMP_CERT_PLAINRSA: