IPAd_Tests: add testsuite for an IPAd

With this patch we add a testsuite that can be used to test an IPAd
implementation.

The testsuite emulates the ESipa and the ES10x (pcsc cardreader)
interface and is capable of testing a direct profile download and other
ESipa features like the execution of an eIM package (eCO, PSMO).

Change-Id: Ic9ea8c69e56a2e8ddf0f506861ece6d40cbcb06d
Related: SYS#6564
diff --git a/.checkpatch.conf b/.checkpatch.conf
index 700e952..2317bec 100644
--- a/.checkpatch.conf
+++ b/.checkpatch.conf
@@ -1,2 +1,5 @@
 --exclude ^library/sbcap/.*\.asn$
 --exclude ^library/DIAMETER_Types.ttcn$
+--exclude ^ipad/example_ca/pki/certs_by_serial/.*\.pem$
+--exclude ^ipad/example_ca/pki/issued/.*\.crt$
+--exclude ^ipad/example_ca/vars$
\ No newline at end of file
diff --git a/Makefile b/Makefile
index bd88ca5..d216aab 100644
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,7 @@
 	hnbgw \
 	hnodeb \
 	hss \
+	ipad \
 	mgw \
 	mme \
 	msc \
diff --git a/ipad/IPAd_Tests.cfg b/ipad/IPAd_Tests.cfg
new file mode 100644
index 0000000..ae44ac5
--- /dev/null
+++ b/ipad/IPAd_Tests.cfg
@@ -0,0 +1,23 @@
+[ORDERED_INCLUDE]
+# Common configuration, shared between test suites
+"../Common.cfg"
+# testsuite specific configuration, not expected to change
+"./IPAd_Tests.default"
+
+# Local configuration below
+
+[LOGGING]
+
+[TESTPORT_PARAMETERS]
+system.HTTP_server_port.use_notification_ASPs := "no"
+system.HTTP_server_port.KEYFILE := "./example_ca/pki/private/alttest.key"
+system.HTTP_server_port.CERTIFICATEFILE := "./example_ca/pki/issued/alttest.crt"
+system.HTTP_server_port.PASSWORD := "katinka1"
+system.HTTP_server_port.http_debugging := "yes"
+
+[MODULE_PARAMETERS]
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+IPAd_Tests.control
diff --git a/ipad/IPAd_Tests.default b/ipad/IPAd_Tests.default
new file mode 100644
index 0000000..95b42e9
--- /dev/null
+++ b/ipad/IPAd_Tests.default
@@ -0,0 +1,8 @@
+[LOGGING]
+mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING; // | DEBUG_ENCDEC;
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+
+[EXECUTE]
diff --git a/ipad/IPAd_Tests.ttcn b/ipad/IPAd_Tests.ttcn
new file mode 100644
index 0000000..35ab79f
--- /dev/null
+++ b/ipad/IPAd_Tests.ttcn
@@ -0,0 +1,708 @@
+/* IPAd testsuite in TTCN-3
+ *
+ * Author: Philipp Maier <pmaier@sysmocom.de> / sysmocom - s.f.m.c. GmbH
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+module IPAd_Tests {
+
+import from Misc_Helpers all;
+import from General_Types all;
+import from Osmocom_Types all;
+
+import from SGP32Definitions all;
+import from SGP32Definitions_Types all;
+import from SGP32Definitions_Templates all;
+
+import from RSPDefinitions all;
+import from RSPDefinitions_Types all;
+import from RSPDefinitions_Templates all;
+
+import from PKIX1Explicit88 all;
+import from PKIX1Explicit88_Templates all;
+import from PKIX1Explicit88_Types all;
+
+import from HTTP_Server_Emulation all;
+import from HTTPmsg_Types all;
+
+import from VPCD_Types all;
+import from VPCD_CodecPort all;
+import from VPCD_Adapter all;
+
+modulepar {
+	/* emulated eIM HTTPs server */
+	charstring mp_esipa_ip := "127.0.0.1";
+	integer mp_esipa_port := 4430;
+	boolean mp_esipa_disable_ssl := false;
+	boolean mp_use_vpcd := true;
+	float mp_restart_guardtime := 2.0
+}
+
+/* Altstep to handle card power up/down and ATR transmission */
+private altstep as_vpcd_atr() runs on VPCD_Adapter_CT {
+	[] VPCD.receive(tr_VPCD_Recv(g_vpcd_conn_id, tr_VPCD_CTRL_ATR)) {
+		f_vpcd_send(ts_VPCD_DATA('3B9F96801FC78031A073BE21136743200718000001A5'O));
+		repeat;
+		}
+	[] VPCD.receive(tr_VPCD_Recv(g_vpcd_conn_id, tr_VPCD_CTRL_OFF)) {
+		repeat;
+		}
+	[] VPCD.receive(tr_VPCD_Recv(g_vpcd_conn_id, tr_VPCD_CTRL_ON)) {
+		repeat;
+		}
+}
+
+/* Helper template to format HTTP responses */
+private template (value) HTTPMessage ts_http_resp(template (value) octetstring resp := ''O) := {
+	response_binary := {
+		client_id := omit,
+		version_major := 1,
+		version_minor := 1,
+		statuscode := 200,
+		statustext := "OK",
+		/* See also SGP.32, section 6.1.1 */
+		header := {
+				{
+					header_name := "X-Admin-Protocol",
+					header_value := "gsma/rsp/v1.0.0"
+				},
+				{
+					header_name := "Content-Type",
+					header_value := "application/x-gsma-rsp-asn1"
+				},
+				{
+					header_name := "Content-Length",
+					header_value := int2str(lengthof(resp))
+				}
+		},
+		body := resp
+	}
+}
+
+type component MTC_CT {
+	timer g_Tguard;
+
+	/* HTTP server */
+	var HTTP_Server_Emulation_CT vc_HTTP;
+};
+
+type component IPAd_ConnHdlr extends HTTP_ConnHdlr, VPCD_Adapter_CT {
+	var IPAd_ConnHdlrPars g_pars;
+};
+
+type record IPAd_ConnHdlrPars {
+     /* TODO: add some useful parameters */
+};
+
+private function f_init_pars()
+runs on MTC_CT return IPAd_ConnHdlrPars {
+	var IPAd_ConnHdlrPars pars := {
+	    /* TODO: fill parameters with meaninful values */
+	};
+	return pars;
+}
+
+private altstep as_Tguard() runs on MTC_CT {
+	[] g_Tguard.timeout {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
+	}
+}
+
+private type function void_fn(charstring id) runs on IPAd_ConnHdlr;
+
+private function f_init_handler(void_fn fn, charstring id, IPAd_ConnHdlrPars pars) runs on IPAd_ConnHdlr {
+	g_pars := pars;
+
+	/* Initialize VPDC (virtual smartcard) */
+	if (mp_use_vpcd) {
+		VPCD_Adapter.f_connect();
+		activate(as_vpcd_atr());
+	}
+
+	fn.apply(id);
+}
+
+private function f_start_handler(void_fn fn, IPAd_ConnHdlrPars pars)
+runs on MTC_CT return IPAd_ConnHdlr {
+	var IPAd_ConnHdlr vc_conn;
+	var charstring id := testcasename();
+
+	vc_conn := IPAd_ConnHdlr.create(id);
+
+	if (isbound(vc_HTTP)) {
+		connect(vc_conn:HTTP_SRV, vc_HTTP:CLIENT);
+		connect(vc_conn:HTTP_SRV_PROC, vc_HTTP:CLIENT_PROC);
+	}
+
+	vc_conn.start(f_init_handler(fn, id, pars));
+	return vc_conn;
+}
+
+function f_init_esipa(charstring id) runs on MTC_CT {
+	var HttpServerEmulationCfg http_cfg := {
+		http_bind_ip := mp_esipa_ip,
+		http_bind_port := mp_esipa_port,
+		use_ssl := not mp_esipa_disable_ssl
+	};
+
+	vc_HTTP := HTTP_Server_Emulation_CT.create(id);
+	vc_HTTP.start(HTTP_Server_Emulation.main(http_cfg));
+}
+
+private function f_init(charstring id, float t_guard := 40.0) runs on MTC_CT {
+	/* Ensure a guard time inbetween tests. This is to make sure that the IPAd is able to finish its current poll
+	 * cycle. In practice this means that the IPAd will notice that the connectivity towards the eIM is lost and
+	 * since this is one of the conditions for ending the current poll cycle it will exit. A freshly restarted
+	 * IPAd is a mandatory start condition for the tests since all tests expect the initialization procedure
+	 * (selection of ISD-P etc.) that the IPAd executes on startup. */
+	f_sleep(mp_restart_guardtime);
+
+	g_Tguard.start(t_guard);
+	activate(as_Tguard());
+	f_init_esipa(id);
+}
+
+/* Expect a GetResponse request from IUT and transfer as many response bytes the IUT requests */
+private function f_vpcd_get_response(octetstring response) runs on IPAd_ConnHdlr return integer {
+	var octetstring sw;
+	var VPCD_PDU req;
+	var integer len;
+
+	req := f_vpcd_exp(tr_VPCD_DATA(?));
+	len := oct2int(req.u.data[4]);
+	if (len == 0) {
+		len := 256;
+	}
+
+	/* Make sure that the request APDU is actually a GetResponse request (on logical channel 2) */
+	if (substr(req.u.data, 0, 4) != '01c00000'O) {
+		setverdict(fail, "unexpected APDU, expecting GetResponse");
+		return 0;
+	}
+
+	/* Compute status word, in case the requested data is shorter then the response data we intend to send, we must
+	 * tell the IUT that there is still data available, so that a consecutive GetResponse request can be issued.
+	 * (caller must check return code to determine if a consecutive GetResponse is needed/expected) */
+	if (lengthof(response) > len) {
+		if (lengthof(response) - len > 255) {
+			sw := '6100'O;
+		} else {
+			sw := '61'O & int2oct(lengthof(response) - len, 1);
+		}
+	} else {
+		sw := '9000'O;
+	}
+
+	/* Send response to IUT */
+	f_vpcd_send(ts_VPCD_DATA(substr(response, 0, len) & sw));
+
+	/* Return how many bytes have sent */
+	return len;
+}
+
+/* Expect one or more GetResponse requests from IUT until the full response is transferred */
+private function f_vpcd_get_response_multi(octetstring response) runs on IPAd_ConnHdlr {
+	var integer bytes_sent := 0;
+	var octetstring response_remainder := response;
+
+	while (true) {
+		response_remainder := substr(response_remainder, bytes_sent, lengthof(response_remainder) - bytes_sent);
+		bytes_sent := f_vpcd_get_response(response_remainder);
+
+		/* Check if we reached the last chunk */
+		if (lengthof(response_remainder) <= bytes_sent) {
+			return;
+		}
+	}
+}
+
+/* Expect one or more STORE DATA requests until the IUT has completed the transmision cycle */
+private function f_vpcd_store_data(octetstring exp := ''O) runs on IPAd_ConnHdlr return octetstring {
+
+	var VPCD_PDU req;
+	var octetstring block;
+	var integer len;
+	var octetstring data := ''O;
+
+	while (true) {
+		req := f_vpcd_exp(tr_VPCD_DATA(?));
+
+		/* Make sure that the request APDU is actually a STORE DATA request (on logical channel 1) */
+		if (substr(req.u.data, 0, 3) != '81E291'O and
+		    substr(req.u.data, 0, 3) != '81E211'O) {
+			setverdict(fail, "unexpected APDU, expecting GetResponse");
+			return ''O;
+		}
+
+		if (lengthof(req.u.data) - 5 > 255) {
+			len := 255;
+		} else {
+			len := lengthof(req.u.data) - 5;
+		}
+		block := substr(req.u.data, 5, len);
+		data := data & block;
+
+		/* The final status word contains the length of the response. We can not send it right now
+		 * since the caller must first process the received data block and compute a response. When
+		 * the exact length of the response data is known. The final status word can be sent using
+		 * f_vpcd_store_data_final_ack() */
+		if (substr(req.u.data, 2, 1) == '91'O) {
+			if (exp != ''O and block != exp) {
+				setverdict(fail, "received block contains unexpected data (", block, " != ", exp, ")");
+			}
+			return block;
+		}
+
+		f_vpcd_send(ts_VPCD_DATA('9000'O));
+	}
+
+	setverdict(fail, "no data? (we should not reach this code path)");
+	return ''O;
+}
+
+/* Send a final status word to acknowledge the last block of a STORE DATA transmission. The status word will tell
+ * the IUT how many response bytes are available. (The IUT will immediately begin to fetch the response using
+ * one or more GetResponse requests */
+private function f_vpcd_store_data_final_ack(integer response_len) runs on IPAd_ConnHdlr {
+	var octetstring second_sw_byte;
+	var octetstring first_sw_byte;
+
+	if (response_len > 255) {
+		second_sw_byte := '00'O;
+	} else {
+		second_sw_byte := int2oct(response_len, 1);
+	}
+
+	if (response_len > 0) {
+		first_sw_byte := '61'O; /* 61xx */
+	} else {
+		first_sw_byte := '90'O; /* 9000 */
+	}
+
+	f_vpcd_send(ts_VPCD_DATA(first_sw_byte & second_sw_byte));
+}
+
+/* Expect a pre-defined request (optional), and send a pre-defined response. This is a shortcut that only works in case
+ * the response does not depend on the request. */
+private function f_vpcd_transceive(octetstring response, octetstring expected_request := ''O) runs on IPAd_ConnHdlr {
+
+	/* In case we do not use the VPCD (because we have some other kind of eUICC emulation or even a real card
+	 * present), we just skip. */
+	if (mp_use_vpcd == false) {
+		return;
+	}
+
+	f_vpcd_store_data(expected_request);
+	f_vpcd_store_data_final_ack(lengthof(response));
+	if (response != ''O) {
+		f_vpcd_get_response_multi(response);
+	}
+}
+
+/* Handle the opening of logical channel 1 and the selection of the ISD-R */
+private function f_es10x_init() runs on IPAd_ConnHdlr {
+	var charstring eim_fqdn := mp_esipa_ip & ":" & int2str(mp_esipa_port);
+
+	/* If we decide not to use vpcd, then we must not initialize anything here */
+	if (mp_use_vpcd == false) {
+		return;
+	}
+
+	/* Expect a MANAGE CHANNEL request that opens logical channel 1 */
+	f_vpcd_exp(tr_VPCD_DATA('0070000100'O));
+	f_vpcd_send(ts_VPCD_DATA('9000'O));
+
+	/* Expect selection of ISD-R request */
+	f_vpcd_exp(tr_VPCD_DATA('01a4040410a0000005591010ffffffff8900000100'O));
+	f_vpcd_send(ts_VPCD_DATA('6121'O)); /* 21 bytes of response, which are not requested by the ipad. */
+
+	/* Expect the IPAd to query the eID from the eUICC */
+	f_vpcd_transceive(enc_GetEuiccDataResponse(valueof(ts_getEuiccDataResponse)), 'BF3E035C015A'O);
+
+	/* Expect the IPAd to query the eIM configuration data from the eUICC */
+	f_vpcd_transceive(enc_GetEimConfigurationDataResponse(valueof(ts_getEimConfigurationDataResponse(eim_fqdn))), 'BF5500'O);
+}
+
+/* Handle the closing of logical channel 1 */
+private function f_es10x_close() runs on IPAd_ConnHdlr {
+
+	/* Expect a MANAGE CHANNEL request that closes logical channel 1 */
+	f_vpcd_exp(tr_VPCD_DATA('0070800100'O));
+	f_vpcd_send(ts_VPCD_DATA('9000'O));
+}
+
+/* Receive ESipa HTTP request */
+private function f_esipa_receive() runs on IPAd_ConnHdlr return EsipaMessageFromIpaToEim {
+	var HTTPMessage esipa_req;
+	timer T := 10.0;
+	var EsipaMessageFromIpaToEim request;
+
+	T.start;
+	alt {
+	[] HTTP_SRV.receive({ request_binary := ? }) -> value esipa_req {
+		request := dec_EsipaMessageFromIpaToEim(esipa_req.request_binary.body);
+		}
+	[] T.timeout {
+		setverdict(fail, "no HTTP request received?");
+		}
+	}
+
+	return request;
+}
+
+/* Send ESipa HTTP response */
+private function f_esipa_send(EsipaMessageFromEimToIpa response) runs on IPAd_ConnHdlr  {
+	var octetstring esipa_res;
+	esipa_res := enc_EsipaMessageFromEimToIpa(response);
+	HTTP_SRV.send(ts_http_resp(esipa_res));
+}
+
+/* Perform one ESipa HTTP request/response cycle */
+private function f_esipa_transceive(EsipaMessageFromEimToIpa response) runs on IPAd_ConnHdlr return EsipaMessageFromIpaToEim {
+	var EsipaMessageFromIpaToEim request;
+
+	request := f_esipa_receive();
+	f_esipa_send(response);
+
+	return request;
+}
+
+/* Perform one ESipa HTTP request/response cycle but with an empty response */
+private function f_esipa_transceive_empty_response() runs on IPAd_ConnHdlr return EsipaMessageFromIpaToEim {
+	var EsipaMessageFromIpaToEim request;
+
+	request := f_esipa_receive();
+	HTTP_SRV.send(ts_http_resp(''O));
+	return request;
+}
+
+/* Common Mutual Authentication Procedure, see also: GSMA SGP.22, section 3.0.1 */
+private function f_proc_cmn_mtl_auth() runs on IPAd_ConnHdlr {
+	var EsipaMessageFromIpaToEim esipa_req;
+	var EsipaMessageFromEimToIpa esipa_res;
+
+	/* Step #1 */
+	f_vpcd_transceive(enc_EUICCInfo1(valueof(ts_EUICCInfo1)), 'bf2000'O);
+
+	/* Step #2-#4 */
+	f_vpcd_transceive(enc_GetEuiccChallengeResponse(valueof(ts_GetEuiccChallengeResponse)), 'bf2e00'O);
+
+	/* Step #5-#10 */
+	esipa_req := f_esipa_receive();
+	if (not match(esipa_req, tr_initiateAuthenticationRequestEsipa)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+	esipa_res := valueof(ts_initiateAuthenticationResponseEsipa(euiccChallenge := esipa_req.initiateAuthenticationRequestEsipa.euiccChallenge));
+	f_esipa_send(esipa_res);
+
+	/* Step #11-#14 */
+	f_vpcd_transceive(enc_AuthenticateServerResponse(valueof(ts_authenticateServerResponse)));
+
+	/* Step #15-#17 */
+	esipa_req := f_esipa_transceive(valueof(ts_authenticateClientResponseEsipa_dpe));
+	if (not match(esipa_req, tr_authenticateClientRequestEsipa)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+}
+
+/* ********************************************* */
+/* ********** BELOW ONLY TESTCASES! ************ */
+/* ********************************************* */
+
+
+/* A testcase to try out an the Common Mutual Authentication Procedure */
+private function f_TC_proc_direct_prfle_dwnld(charstring id) runs on IPAd_ConnHdlr {
+	var EsipaMessageFromIpaToEim esipa_req;
+	var EsipaMessageFromEimToIpa esipa_res;
+	var integer i;
+	var charstring eim_fqdn := mp_esipa_ip & ":" & int2str(mp_esipa_port);
+	var BoundProfilePackage boundProfilePackage;
+
+	f_es10x_init();
+	f_http_register();
+
+	/* Prepare direct profile download by responding with a download trigger request */
+	esipa_res := valueof(ts_getEimPackageResponse_dnlTrigReq);
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_getEimPackageRequest)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* Expect the IPAd to query the eIM configuration data from the eUICC */
+	f_vpcd_transceive(enc_GetEimConfigurationDataResponse(valueof(ts_getEimConfigurationDataResponse(eim_fqdn))), 'BF5500'O);
+
+	f_proc_cmn_mtl_auth();
+
+	f_vpcd_transceive(enc_PrepareDownloadResponse(valueof(ts_prepareDownloadResponse)));
+
+	esipa_res := valueof(ts_getBoundProfilePackageResponseEsipa);
+	esipa_req := f_esipa_transceive(esipa_res);
+	boundProfilePackage := esipa_res.getBoundProfilePackageResponseEsipa.getBoundProfilePackageOkEsipa.boundProfilePackage;
+	/* TODO: match response (we do not have a template yet) */
+
+	/* initialiseSecureChannelRequest */
+	f_vpcd_transceive(''O);
+
+	/* Step #3 (ES8+.ConfigureISDP) */
+	for (i := 0; i < sizeof(boundProfilePackage.firstSequenceOf87); i := i + 1) {
+		f_vpcd_transceive(''O);
+	}
+
+	/* Step #4 (ES8+.StoreMetadata) */
+	for (i := 0; i < sizeof(boundProfilePackage.sequenceOf88); i := i + 1) {
+		f_vpcd_transceive(''O);
+	}
+
+	/* Step #5 (ES8+.ReplaceSessionKeys", optional, left out) */
+	if (ispresent(boundProfilePackage.secondSequenceOf87)) {
+		for (i := 0; i < sizeof(boundProfilePackage.secondSequenceOf87); i := i + 1) {
+			f_vpcd_transceive(''O);
+		}
+	}
+
+	/* Step #6 (ES8+.LoadProfileElements) */
+	for (i := 0; i < sizeof(boundProfilePackage.sequenceOf86); i := i + 1) {
+		if (i < sizeof(boundProfilePackage.sequenceOf86) - 1) {
+			f_vpcd_transceive(''O);
+		} else {
+			/* In the last message we send the ProfileInstallationResult */
+			f_vpcd_transceive(enc_ProfileInstallationResult(valueof(ts_profileInstallationResult)));
+		}
+	}
+
+	/* Receive ProfileInstallationResult from iPAD->eIM */
+	esipa_req := f_esipa_transceive_empty_response();
+	/* TODO: match response (we do not have a template yet) */
+
+	/* Receive RemoveNotificationFromList from iPAD->eUICC */
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+
+	/* Wait some time until the the last HTTP response is actually delivered */
+	f_sleep(2.0);
+
+	f_es10x_close();
+
+	setverdict(pass);
+}
+testcase TC_proc_direct_prfle_dwnld() runs on MTC_CT {
+	var charstring id := testcasename();
+	var IPAd_ConnHdlrPars pars := f_init_pars();
+	var IPAd_ConnHdlr vc_conn;
+	f_init(id);
+	vc_conn := f_start_handler(refers(f_TC_proc_direct_prfle_dwnld), pars);
+	vc_conn.done;
+	setverdict(pass);
+}
+
+
+/* A testcase to try out an the Generic eUICC Package Download and Execution Procedure */
+private function f_TC_proc_euicc_pkg_dwnld_exec(charstring id) runs on IPAd_ConnHdlr {
+	var EsipaMessageFromIpaToEim esipa_req;
+	var EsipaMessageFromEimToIpa esipa_res;
+
+	f_es10x_init();
+	f_http_register();
+
+	/* Step #1-#2 */
+	esipa_res := valueof(ts_getEimPackageResponse_euiccPkgReq);
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_getEimPackageRequest)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* Step #3-#8 */
+	f_vpcd_transceive(enc_EuiccPackageResult(valueof(ts_euiccPackageResult)));
+
+	/* Step #9 */
+	f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
+
+	/* Step #10-14 */
+	esipa_res := valueof(ts_provideEimPackageResultResponse_eimAck(eimAcknowledgements := {1,2,3,4}));
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_provideEimPackageResult_ePRAndNotif)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* Step #15-17 */
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+
+	/* Wait some time until the the last HTTP response is actually delivered */
+	f_sleep(2.0);
+
+	f_es10x_close();
+
+	setverdict(pass);
+}
+
+testcase TC_proc_euicc_pkg_dwnld_exec() runs on MTC_CT {
+	var charstring id := testcasename();
+	var IPAd_ConnHdlrPars pars := f_init_pars();
+	var IPAd_ConnHdlr vc_conn;
+	f_init(id);
+	vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec), pars);
+	vc_conn.done;
+	setverdict(pass);
+}
+
+
+/* A testcase to try out an the Generic eUICC Package Download and Execution Procedure, but this time we force a rollback meneuver */
+private function f_TC_proc_euicc_pkg_dwnld_exec_rollback(charstring id) runs on IPAd_ConnHdlr {
+	var EsipaMessageFromIpaToEim esipa_req;
+	var EsipaMessageFromEimToIpa esipa_res;
+
+	f_es10x_init();
+	f_http_register();
+
+	/* Step #1-#2 */
+	esipa_res := valueof(ts_getEimPackageResponse_euiccPkgReq);
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_getEimPackageRequest)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* Step #3-#8 */
+	f_vpcd_transceive(enc_EuiccPackageResult(valueof(ts_euiccPackageResult)));
+
+	/* Step #9 */
+	f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
+
+	/* We now ignore the response from the IPAd. The IPAd will interpret this as a disturbed IP connection. */
+	f_esipa_receive();
+
+	/* To fix the problem, the IPAd will now try a profile rollback meneuver. */
+	f_vpcd_transceive(enc_ProfileRollbackResponse(valueof(ts_profileRollbackResponse)),
+			  enc_ProfileRollbackRequest(valueof(ts_profileRollbackRequest)));
+
+	/* At this point the old profile is active again. The IPAd is now expected to start at Step #9 again
+	 * to continue the procedure normally. */
+
+	/* Step #9 */
+	f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
+
+	/* Step #10-14 */
+	esipa_res := valueof(ts_provideEimPackageResultResponse_eimAck(eimAcknowledgements := {1,2,3,4}));
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_provideEimPackageResult_ePRAndNotif)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* Step #15-17 */
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+	f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
+
+	/* Wait some time until the the last HTTP response is actually delivered */
+	f_sleep(2.0);
+
+	f_es10x_close();
+
+	setverdict(pass);
+}
+
+testcase TC_proc_euicc_pkg_dwnld_exec_rollback() runs on MTC_CT {
+	var charstring id := testcasename();
+	var IPAd_ConnHdlrPars pars := f_init_pars();
+	var IPAd_ConnHdlr vc_conn;
+	f_init(id);
+	vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_rollback), pars);
+	vc_conn.done;
+	setverdict(pass);
+}
+
+
+/* A testcase to try out an IpaEuiccDataRequest */
+private function f_TC_proc_euicc_data_req(charstring id) runs on IPAd_ConnHdlr {
+	var EsipaMessageFromIpaToEim esipa_req;
+	var EsipaMessageFromEimToIpa esipa_res;
+	var charstring eim_fqdn := mp_esipa_ip & ":" & int2str(mp_esipa_port);
+
+	f_es10x_init();
+	f_http_register();
+
+	/* IPAd requests a package, we tell it to execute an ipaEuiccDataRequest */
+	esipa_res := valueof(ts_getEimPackageResponse_euiccDataReq);
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_getEimPackageRequest)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* IPAd will obtain the data from the eUICC */
+	f_vpcd_transceive(enc_EuiccConfiguredAddressesResponse(valueof(ts_euiccConfiguredAddressesResponse)));
+	f_vpcd_transceive(enc_EUICCInfo1(valueof(ts_EUICCInfo1)));
+	f_vpcd_transceive(enc_EUICCInfo2(valueof(ts_EUICCInfo2)));
+	f_vpcd_transceive(enc_GetEimConfigurationDataResponse(valueof(ts_getEimConfigurationDataResponse(eim_fqdn))));
+	f_vpcd_transceive(enc_GetCertsResponse(valueof(ts_getCertsResponse)));
+	f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
+
+	/* IPAd will return the data to us */
+	esipa_res := valueof(ts_provideEimPackageResultResponse_eimAck(eimAcknowledgements := {1,2,3,4}));
+	esipa_req := f_esipa_transceive(esipa_res);
+
+	/* Wait some time until the the last HTTP response is actually delivered */
+	f_sleep(2.0);
+
+	f_es10x_close();
+
+	setverdict(pass);
+}
+testcase TC_proc_euicc_data_req() runs on MTC_CT {
+	var charstring id := testcasename();
+	var IPAd_ConnHdlrPars pars := f_init_pars();
+	var IPAd_ConnHdlr vc_conn;
+	f_init(id);
+	vc_conn := f_start_handler(refers(f_TC_proc_euicc_data_req), pars);
+	vc_conn.done;
+	setverdict(pass);
+}
+
+/* A testcase to try out what happens when the eIM package request is rejected */
+private function f_TC_get_eim_pkg_req_rej(charstring id) runs on IPAd_ConnHdlr {
+	var EsipaMessageFromIpaToEim esipa_req;
+	var EsipaMessageFromEimToIpa esipa_res;
+
+	f_es10x_init();
+	f_http_register();
+
+	/* IPAd requests a package, we respond with an eimPackageError code 127 (undefined error) */
+	esipa_res := valueof(ts_getEimPackageResponse_eimPkgErrUndef);
+	esipa_req := f_esipa_transceive(esipa_res);
+	if (not match(esipa_req, tr_getEimPackageRequest)) {
+		setverdict(fail, "unexpected message from IPAd");
+	}
+
+	/* Wait some time until the the last HTTP response is actually delivered */
+	f_sleep(2.0);
+
+	f_es10x_close();
+
+	setverdict(pass);
+}
+testcase TC_get_eim_pkg_req_rej() runs on MTC_CT {
+	var charstring id := testcasename();
+	var IPAd_ConnHdlrPars pars := f_init_pars();
+	var IPAd_ConnHdlr vc_conn;
+	f_init(id);
+	vc_conn := f_start_handler(refers(f_TC_get_eim_pkg_req_rej), pars);
+	vc_conn.done;
+	setverdict(pass);
+}
+
+control {
+	execute ( TC_proc_direct_prfle_dwnld() );
+	execute ( TC_proc_euicc_pkg_dwnld_exec() );
+	execute ( TC_proc_euicc_pkg_dwnld_exec_rollback() );
+	execute ( TC_proc_euicc_data_req() );
+	execute ( TC_get_eim_pkg_req_rej() );
+}
+
+}
diff --git a/ipad/example_ca/pki/ca.crt b/ipad/example_ca/pki/ca.crt
new file mode 100644
index 0000000..4dfdf16
--- /dev/null
+++ b/ipad/example_ca/pki/ca.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDTTCCAjWgAwIBAgIUZjLnFa4g4tdrDjujUMElWkVpFKAwDQYJKoZIhvcNAQEL
+BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwIBcNMjQwNDI1MTUzMzU2WhgPMzAy
+MzA4MjcxNTMzNTZaMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnR8Y1ESTRhfjVNZ0+nuhQsvkMhZnOMpaEoJz
+pCzHV0Cj6Mi814gPanvflAX/9F+4IjQ2evm7pNKNUpt1vf6kKTmco0EX672spP4p
+8KOQaki/+I/AMYCwAGOvmCMYpHMzNTkV9PZIUUyzLG5YaigiMtJpWY+ji/G+kxAg
+YzPr4WhTjG+mEoPjfc9LQH5dh/dP0cdkoZuIHWx6kFxAw/Okb1EF/oGrUT4pOLzg
+/Z5wkOYZhlK0bicCqvYfsUjJ4y0ftCXfjQUtAYfQ4gq6revQ7eHCNKixh+BB8yXO
+7/z6qrTfMTmN2Ekdo5nAyAMOeugaExaSLwYti3afX71RuqrtTwIDAQABo4GQMIGN
+MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFNtLqZUsrQWfz8g83jssJ4HXKGVIMFEG
+A1UdIwRKMEiAFNtLqZUsrQWfz8g83jssJ4HXKGVIoRqkGDAWMRQwEgYDVQQDDAtF
+YXN5LVJTQSBDQYIUZjLnFa4g4tdrDjujUMElWkVpFKAwCwYDVR0PBAQDAgEGMA0G
+CSqGSIb3DQEBCwUAA4IBAQAADFdB7R2mwfMWj3vUR77v9f3wqJdKgUyleXGKu6ot
+9YL8vYAJUL9sojZ8KeR47PDVpOs7v0Ll3RcfqRrDWQ9/MiMqSMcxh/i9dvyf5d9s
+o2kxqiPaMVPkLzGKE04I0XtAlszqOBYsGO83D2FuJsIWglvvOjNYvJ05LMVJObnq
+gpwY3TwhoKeWAQg6U5Yv6dLDjvbYPTwgArNpY97BxY0GZNyiyJgyag21cVui+tsd
+uLKVKhmW/EhCC52wsEMwLAsiOjNpVXwAkPWaWAbUJIJTyuc2ZFpx9D2T40H1U8Pj
+6UXwCkZ7C9qwKKyusG8duf/Xsdsft3Pm8XykSWWya6Um
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/certs_by_serial/2AA3F8FFC3B562AFC67845389A5F2C5A.pem b/ipad/example_ca/pki/certs_by_serial/2AA3F8FFC3B562AFC67845389A5F2C5A.pem
new file mode 100644
index 0000000..14904d1
--- /dev/null
+++ b/ipad/example_ca/pki/certs_by_serial/2AA3F8FFC3B562AFC67845389A5F2C5A.pem
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            2a:a3:f8:ff:c3:b5:62:af:c6:78:45:38:9a:5f:2c:5a
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Easy-RSA CA
+        Validity
+            Not Before: Apr 25 15:34:30 2024 GMT
+            Not After : Aug 27 15:34:30 3023 GMT
+        Subject: CN=testsuite
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:bc:0d:37:f1:b1:2d:4c:0e:af:a1:51:85:92:1f:
+                    1b:3c:ef:04:18:24:d1:d6:0e:eb:73:64:86:da:c6:
+                    65:e2:b2:74:fb:6e:c0:b9:5d:fe:67:61:44:3a:bf:
+                    20:6e:a7:53:9c:7b:8e:6b:ec:c4:55:ec:0b:f9:44:
+                    08:6a:54:35:59:82:9a:63:60:0b:37:dd:22:5d:e3:
+                    43:81:4e:51:ae:0a:67:31:bb:b1:d3:70:0e:a8:46:
+                    2f:11:ec:b6:e9:58:25:0a:c9:72:4a:97:f1:d5:7a:
+                    0d:68:90:eb:73:c2:e1:81:12:cd:08:1b:21:e9:ce:
+                    58:3e:dc:81:de:b7:65:31:bd:c4:8b:5a:d1:06:9b:
+                    c0:ea:b7:63:8f:fb:a5:67:37:7e:d5:69:07:56:67:
+                    f3:e7:37:5d:84:86:52:25:94:9e:6a:60:a2:5c:bf:
+                    5e:0b:cb:c8:83:1a:17:51:84:f1:16:f0:83:46:b6:
+                    bb:97:f3:4f:ba:41:1f:30:a8:d5:ee:4e:2e:78:00:
+                    9b:25:fd:0c:ec:cc:57:a3:82:b5:54:56:fd:25:f9:
+                    ff:b8:5f:1b:55:ae:57:16:35:0d:cc:9a:cf:d0:2c:
+                    4a:dd:d5:ae:2a:7e:76:73:af:b8:d9:a0:35:61:82:
+                    3d:a0:d1:ce:a3:d8:82:1b:0c:9a:bc:a5:0b:2d:00:
+                    d0:e9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                20:11:06:2E:BB:B0:0B:05:D4:CE:4F:BC:5F:51:39:E7:96:94:4F:26
+            X509v3 Authority Key Identifier: 
+                keyid:DB:4B:A9:95:2C:AD:05:9F:CF:C8:3C:DE:3B:2C:27:81:D7:28:65:48
+                DirName:/CN=Easy-RSA CA
+                serial:66:32:E7:15:AE:20:E2:D7:6B:0E:3B:A3:50:C1:25:5A:45:69:14:A0
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+            X509v3 Subject Alternative Name: 
+                DNS:testsuite
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        78:b1:28:25:f5:17:7a:c2:a0:2e:b8:bb:15:dc:aa:e8:8f:aa:
+        ae:f3:48:0e:46:29:71:d7:24:6b:cd:da:4e:b1:8c:1a:40:01:
+        79:03:ca:2d:45:76:c9:08:61:50:eb:03:9c:82:9f:d6:37:d8:
+        60:42:fc:59:35:b7:42:69:fd:36:45:93:a3:17:df:dd:5d:84:
+        19:04:70:4f:c8:5f:3e:96:27:49:03:81:a7:55:2c:16:7e:be:
+        65:26:71:48:eb:5b:36:38:c1:a9:87:f0:ad:2e:40:5b:e8:12:
+        39:f5:d0:60:71:55:d7:4b:fb:d0:bf:35:11:fb:2e:9c:4f:e6:
+        b1:35:c6:45:b4:73:68:99:d9:27:fa:4e:98:25:7d:6e:7c:1b:
+        22:e8:c2:83:6f:3b:1f:4c:27:70:94:1a:ef:fb:2b:fd:9d:3c:
+        a2:ce:f2:4b:d1:8e:e7:6d:db:ec:22:1c:b9:b4:c1:bc:17:82:
+        ea:e1:1f:76:1a:4a:d6:59:b3:24:e5:e4:67:b9:ce:d3:73:67:
+        dd:48:82:04:bc:8f:50:34:c0:0e:42:6e:7e:63:ac:e6:ab:71:
+        b7:79:5b:f7:8e:8c:48:ac:ef:ae:c6:b0:e9:ae:d7:94:9b:58:
+        e9:2b:e8:40:93:1b:62:51:2d:06:a4:ca:8c:e6:7e:8c:5a:d0:
+        6d:69:86:6f
+-----BEGIN CERTIFICATE-----
+MIIDbzCCAlegAwIBAgIQKqP4/8O1Yq/GeEU4ml8sWjANBgkqhkiG9w0BAQsFADAW
+MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTAgFw0yNDA0MjUxNTM0MzBaGA8zMDIzMDgy
+NzE1MzQzMFowFDESMBAGA1UEAwwJdGVzdHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAvA038bEtTA6voVGFkh8bPO8EGCTR1g7rc2SG2sZl4rJ0
++27AuV3+Z2FEOr8gbqdTnHuOa+zEVewL+UQIalQ1WYKaY2ALN90iXeNDgU5Rrgpn
+Mbux03AOqEYvEey26VglCslySpfx1XoNaJDrc8LhgRLNCBsh6c5YPtyB3rdlMb3E
+i1rRBpvA6rdjj/ulZzd+1WkHVmfz5zddhIZSJZSeamCiXL9eC8vIgxoXUYTxFvCD
+Rra7l/NPukEfMKjV7k4ueACbJf0M7MxXo4K1VFb9Jfn/uF8bVa5XFjUNzJrP0CxK
+3dWuKn52c6+42aA1YYI9oNHOo9iCGwyavKULLQDQ6QIDAQABo4G4MIG1MAkGA1Ud
+EwQCMAAwHQYDVR0OBBYEFCARBi67sAsF1M5PvF9ROeeWlE8mMFEGA1UdIwRKMEiA
+FNtLqZUsrQWfz8g83jssJ4HXKGVIoRqkGDAWMRQwEgYDVQQDDAtFYXN5LVJTQSBD
+QYIUZjLnFa4g4tdrDjujUMElWkVpFKAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYD
+VR0PBAQDAgWgMBQGA1UdEQQNMAuCCXRlc3RzdWl0ZTANBgkqhkiG9w0BAQsFAAOC
+AQEAeLEoJfUXesKgLri7Fdyq6I+qrvNIDkYpcdcka83aTrGMGkABeQPKLUV2yQhh
+UOsDnIKf1jfYYEL8WTW3Qmn9NkWToxff3V2EGQRwT8hfPpYnSQOBp1UsFn6+ZSZx
+SOtbNjjBqYfwrS5AW+gSOfXQYHFV10v70L81EfsunE/msTXGRbRzaJnZJ/pOmCV9
+bnwbIujCg287H0wncJQa7/sr/Z08os7yS9GO523b7CIcubTBvBeC6uEfdhpK1lmz
+JOXkZ7nO03Nn3UiCBLyPUDTADkJufmOs5qtxt3lb946MSKzvrsaw6a7XlJtY6Svo
+QJMbYlEtBqTKjOZ+jFrQbWmGbw==
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/certs_by_serial/FAEE71AC9CF85B804DCE4BD357F83209.pem b/ipad/example_ca/pki/certs_by_serial/FAEE71AC9CF85B804DCE4BD357F83209.pem
new file mode 100644
index 0000000..070adb2
--- /dev/null
+++ b/ipad/example_ca/pki/certs_by_serial/FAEE71AC9CF85B804DCE4BD357F83209.pem
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            fa:ee:71:ac:9c:f8:5b:80:4d:ce:4b:d3:57:f8:32:09
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Easy-RSA CA
+        Validity
+            Not Before: Apr 25 15:34:18 2024 GMT
+            Not After : Aug 27 15:34:18 3023 GMT
+        Subject: CN=alttest
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:94:f6:7e:2b:41:ee:00:d6:f5:2f:54:66:f4:41:
+                    39:69:ee:64:0b:15:46:59:ce:00:b6:bf:2a:aa:f7:
+                    0e:75:c4:e5:a1:b7:b3:86:1c:24:06:fa:91:41:f1:
+                    0b:87:3a:ee:26:27:28:62:1d:ac:35:54:e5:a3:ac:
+                    48:a7:9a:aa:be:2e:60:52:7c:de:cf:c3:28:11:42:
+                    57:52:9d:44:24:8f:b0:b6:fb:36:ef:4f:aa:7e:2c:
+                    57:5e:07:8a:03:fc:18:03:e8:58:6b:88:98:a8:93:
+                    ac:69:01:b1:9c:ef:3b:fe:04:47:9e:28:e2:c6:15:
+                    f9:5c:df:de:24:1e:2f:a4:e0:b2:01:94:7e:b8:00:
+                    76:b0:dd:36:55:22:f2:2d:3a:c7:b1:d8:67:7e:ca:
+                    2d:22:b8:dc:9d:87:34:0c:c1:11:c7:72:2b:b8:ed:
+                    1b:d8:75:6d:0d:49:e1:f6:bf:12:dd:19:84:87:2e:
+                    6d:c6:7d:7e:42:33:2a:05:a2:ff:5d:07:10:83:a4:
+                    c0:35:a9:f8:00:96:29:9f:bc:53:6c:81:18:7b:e4:
+                    c6:41:54:7f:12:a3:5a:77:cb:0f:cf:52:8c:83:9a:
+                    30:03:ca:77:65:b2:c0:0b:00:67:86:50:77:b1:f5:
+                    79:b7:20:62:25:f8:3b:ca:cd:c4:da:d1:c0:81:fd:
+                    db:8b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                04:2E:A0:68:00:D7:DB:D3:E5:73:93:FC:1C:E5:30:78:D1:5B:24:E8
+            X509v3 Authority Key Identifier: 
+                keyid:DB:4B:A9:95:2C:AD:05:9F:CF:C8:3C:DE:3B:2C:27:81:D7:28:65:48
+                DirName:/CN=Easy-RSA CA
+                serial:66:32:E7:15:AE:20:E2:D7:6B:0E:3B:A3:50:C1:25:5A:45:69:14:A0
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+            X509v3 Subject Alternative Name: 
+                DNS:localhost, IP Address:127.0.0.1
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        41:35:5e:7e:14:46:96:3e:c9:8e:fe:88:f8:d6:07:6b:8b:b7:
+        8e:02:c4:63:97:79:ec:4a:46:cc:72:4d:7a:cc:9b:13:d9:6b:
+        5c:f9:b5:b6:c8:04:cf:f9:e0:23:b2:4e:ec:b0:80:85:84:be:
+        a9:1d:8d:4e:8b:26:09:d1:50:83:df:a2:d6:cc:ec:8c:36:b0:
+        c4:a9:cb:14:ba:2d:e2:f3:93:9a:e5:ae:fe:a6:b7:37:c2:17:
+        52:17:b2:f3:4e:3a:04:88:9b:50:7e:c5:73:6f:63:5c:ab:32:
+        47:0d:1c:b4:63:d4:de:c0:6b:ce:ec:26:8d:8c:40:83:c1:c2:
+        29:48:f8:0f:a1:b1:f9:5e:2b:91:fb:0d:32:26:db:73:ef:36:
+        03:d1:24:3e:59:8d:39:09:29:61:85:64:69:be:ee:ec:6d:dd:
+        6d:7c:93:22:b5:44:19:ed:11:f5:46:7d:f5:be:74:ce:46:85:
+        5d:24:9f:4e:b8:27:4b:7f:ba:72:5c:f7:24:10:b6:7b:fb:cb:
+        a0:d1:59:5b:d3:5f:e9:a3:e9:fd:c3:36:2f:b6:b5:eb:e6:1d:
+        9b:71:d6:53:26:95:26:64:14:25:47:b8:3b:d4:96:be:51:98:
+        e5:4d:cf:47:66:e8:fc:e9:bc:e6:6c:2b:e6:87:d8:cb:64:82:
+        d8:63:31:c9
+-----BEGIN CERTIFICATE-----
+MIIDdDCCAlygAwIBAgIRAPrucayc+FuATc5L01f4MgkwDQYJKoZIhvcNAQELBQAw
+FjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwIBcNMjQwNDI1MTUzNDE4WhgPMzAyMzA4
+MjcxNTM0MThaMBIxEDAOBgNVBAMMB2FsdHRlc3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCU9n4rQe4A1vUvVGb0QTlp7mQLFUZZzgC2vyqq9w51xOWh
+t7OGHCQG+pFB8QuHOu4mJyhiHaw1VOWjrEinmqq+LmBSfN7PwygRQldSnUQkj7C2
++zbvT6p+LFdeB4oD/BgD6FhriJiok6xpAbGc7zv+BEeeKOLGFflc394kHi+k4LIB
+lH64AHaw3TZVIvItOsex2Gd+yi0iuNydhzQMwRHHciu47RvYdW0NSeH2vxLdGYSH
+Lm3GfX5CMyoFov9dBxCDpMA1qfgAlimfvFNsgRh75MZBVH8So1p3yw/PUoyDmjAD
+yndlssALAGeGUHex9Xm3IGIl+DvKzcTa0cCB/duLAgMBAAGjgb4wgbswCQYDVR0T
+BAIwADAdBgNVHQ4EFgQUBC6gaADX29Plc5P8HOUweNFbJOgwUQYDVR0jBEowSIAU
+20uplSytBZ/PyDzeOywngdcoZUihGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENB
+ghRmMucVriDi12sOO6NQwSVaRWkUoDATBgNVHSUEDDAKBggrBgEFBQcDATALBgNV
+HQ8EBAMCBaAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
+CwUAA4IBAQBBNV5+FEaWPsmO/oj41gdri7eOAsRjl3nsSkbMck16zJsT2Wtc+bW2
+yATP+eAjsk7ssICFhL6pHY1OiyYJ0VCD36LWzOyMNrDEqcsUui3i85Oa5a7+prc3
+whdSF7LzTjoEiJtQfsVzb2NcqzJHDRy0Y9TewGvO7CaNjECDwcIpSPgPobH5XiuR
++w0yJttz7zYD0SQ+WY05CSlhhWRpvu7sbd1tfJMitUQZ7RH1Rn31vnTORoVdJJ9O
+uCdLf7pyXPckELZ7+8ug0Vlb01/po+n9wzYvtrXr5h2bcdZTJpUmZBQlR7g71Ja+
+UZjlTc9HZuj86bzmbCvmh9jLZILYYzHJ
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/index.txt b/ipad/example_ca/pki/index.txt
new file mode 100644
index 0000000..dd39679
--- /dev/null
+++ b/ipad/example_ca/pki/index.txt
@@ -0,0 +1,2 @@
+V	30230827153418Z		FAEE71AC9CF85B804DCE4BD357F83209	unknown	/CN=alttest
+V	30230827153430Z		2AA3F8FFC3B562AFC67845389A5F2C5A	unknown	/CN=testsuite
diff --git a/ipad/example_ca/pki/index.txt.attr b/ipad/example_ca/pki/index.txt.attr
new file mode 100644
index 0000000..3a7e39e
--- /dev/null
+++ b/ipad/example_ca/pki/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = no
diff --git a/ipad/example_ca/pki/index.txt.attr.old b/ipad/example_ca/pki/index.txt.attr.old
new file mode 100644
index 0000000..3a7e39e
--- /dev/null
+++ b/ipad/example_ca/pki/index.txt.attr.old
@@ -0,0 +1 @@
+unique_subject = no
diff --git a/ipad/example_ca/pki/index.txt.old b/ipad/example_ca/pki/index.txt.old
new file mode 100644
index 0000000..605de4c
--- /dev/null
+++ b/ipad/example_ca/pki/index.txt.old
@@ -0,0 +1 @@
+V	30230827153418Z		FAEE71AC9CF85B804DCE4BD357F83209	unknown	/CN=alttest
diff --git a/ipad/example_ca/pki/issued/alttest.cabundle b/ipad/example_ca/pki/issued/alttest.cabundle
new file mode 100644
index 0000000..c7a4426
--- /dev/null
+++ b/ipad/example_ca/pki/issued/alttest.cabundle
@@ -0,0 +1,42 @@
+-----BEGIN CERTIFICATE-----
+MIIDdDCCAlygAwIBAgIRAPrucayc+FuATc5L01f4MgkwDQYJKoZIhvcNAQELBQAw
+FjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwIBcNMjQwNDI1MTUzNDE4WhgPMzAyMzA4
+MjcxNTM0MThaMBIxEDAOBgNVBAMMB2FsdHRlc3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCU9n4rQe4A1vUvVGb0QTlp7mQLFUZZzgC2vyqq9w51xOWh
+t7OGHCQG+pFB8QuHOu4mJyhiHaw1VOWjrEinmqq+LmBSfN7PwygRQldSnUQkj7C2
++zbvT6p+LFdeB4oD/BgD6FhriJiok6xpAbGc7zv+BEeeKOLGFflc394kHi+k4LIB
+lH64AHaw3TZVIvItOsex2Gd+yi0iuNydhzQMwRHHciu47RvYdW0NSeH2vxLdGYSH
+Lm3GfX5CMyoFov9dBxCDpMA1qfgAlimfvFNsgRh75MZBVH8So1p3yw/PUoyDmjAD
+yndlssALAGeGUHex9Xm3IGIl+DvKzcTa0cCB/duLAgMBAAGjgb4wgbswCQYDVR0T
+BAIwADAdBgNVHQ4EFgQUBC6gaADX29Plc5P8HOUweNFbJOgwUQYDVR0jBEowSIAU
+20uplSytBZ/PyDzeOywngdcoZUihGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENB
+ghRmMucVriDi12sOO6NQwSVaRWkUoDATBgNVHSUEDDAKBggrBgEFBQcDATALBgNV
+HQ8EBAMCBaAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
+CwUAA4IBAQBBNV5+FEaWPsmO/oj41gdri7eOAsRjl3nsSkbMck16zJsT2Wtc+bW2
+yATP+eAjsk7ssICFhL6pHY1OiyYJ0VCD36LWzOyMNrDEqcsUui3i85Oa5a7+prc3
+whdSF7LzTjoEiJtQfsVzb2NcqzJHDRy0Y9TewGvO7CaNjECDwcIpSPgPobH5XiuR
++w0yJttz7zYD0SQ+WY05CSlhhWRpvu7sbd1tfJMitUQZ7RH1Rn31vnTORoVdJJ9O
+uCdLf7pyXPckELZ7+8ug0Vlb01/po+n9wzYvtrXr5h2bcdZTJpUmZBQlR7g71Ja+
+UZjlTc9HZuj86bzmbCvmh9jLZILYYzHJ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDTTCCAjWgAwIBAgIUZjLnFa4g4tdrDjujUMElWkVpFKAwDQYJKoZIhvcNAQEL
+BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwIBcNMjQwNDI1MTUzMzU2WhgPMzAy
+MzA4MjcxNTMzNTZaMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnR8Y1ESTRhfjVNZ0+nuhQsvkMhZnOMpaEoJz
+pCzHV0Cj6Mi814gPanvflAX/9F+4IjQ2evm7pNKNUpt1vf6kKTmco0EX672spP4p
+8KOQaki/+I/AMYCwAGOvmCMYpHMzNTkV9PZIUUyzLG5YaigiMtJpWY+ji/G+kxAg
+YzPr4WhTjG+mEoPjfc9LQH5dh/dP0cdkoZuIHWx6kFxAw/Okb1EF/oGrUT4pOLzg
+/Z5wkOYZhlK0bicCqvYfsUjJ4y0ftCXfjQUtAYfQ4gq6revQ7eHCNKixh+BB8yXO
+7/z6qrTfMTmN2Ekdo5nAyAMOeugaExaSLwYti3afX71RuqrtTwIDAQABo4GQMIGN
+MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFNtLqZUsrQWfz8g83jssJ4HXKGVIMFEG
+A1UdIwRKMEiAFNtLqZUsrQWfz8g83jssJ4HXKGVIoRqkGDAWMRQwEgYDVQQDDAtF
+YXN5LVJTQSBDQYIUZjLnFa4g4tdrDjujUMElWkVpFKAwCwYDVR0PBAQDAgEGMA0G
+CSqGSIb3DQEBCwUAA4IBAQAADFdB7R2mwfMWj3vUR77v9f3wqJdKgUyleXGKu6ot
+9YL8vYAJUL9sojZ8KeR47PDVpOs7v0Ll3RcfqRrDWQ9/MiMqSMcxh/i9dvyf5d9s
+o2kxqiPaMVPkLzGKE04I0XtAlszqOBYsGO83D2FuJsIWglvvOjNYvJ05LMVJObnq
+gpwY3TwhoKeWAQg6U5Yv6dLDjvbYPTwgArNpY97BxY0GZNyiyJgyag21cVui+tsd
+uLKVKhmW/EhCC52wsEMwLAsiOjNpVXwAkPWaWAbUJIJTyuc2ZFpx9D2T40H1U8Pj
+6UXwCkZ7C9qwKKyusG8duf/Xsdsft3Pm8XykSWWya6Um
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/issued/alttest.crt b/ipad/example_ca/pki/issued/alttest.crt
new file mode 100644
index 0000000..070adb2
--- /dev/null
+++ b/ipad/example_ca/pki/issued/alttest.crt
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            fa:ee:71:ac:9c:f8:5b:80:4d:ce:4b:d3:57:f8:32:09
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Easy-RSA CA
+        Validity
+            Not Before: Apr 25 15:34:18 2024 GMT
+            Not After : Aug 27 15:34:18 3023 GMT
+        Subject: CN=alttest
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:94:f6:7e:2b:41:ee:00:d6:f5:2f:54:66:f4:41:
+                    39:69:ee:64:0b:15:46:59:ce:00:b6:bf:2a:aa:f7:
+                    0e:75:c4:e5:a1:b7:b3:86:1c:24:06:fa:91:41:f1:
+                    0b:87:3a:ee:26:27:28:62:1d:ac:35:54:e5:a3:ac:
+                    48:a7:9a:aa:be:2e:60:52:7c:de:cf:c3:28:11:42:
+                    57:52:9d:44:24:8f:b0:b6:fb:36:ef:4f:aa:7e:2c:
+                    57:5e:07:8a:03:fc:18:03:e8:58:6b:88:98:a8:93:
+                    ac:69:01:b1:9c:ef:3b:fe:04:47:9e:28:e2:c6:15:
+                    f9:5c:df:de:24:1e:2f:a4:e0:b2:01:94:7e:b8:00:
+                    76:b0:dd:36:55:22:f2:2d:3a:c7:b1:d8:67:7e:ca:
+                    2d:22:b8:dc:9d:87:34:0c:c1:11:c7:72:2b:b8:ed:
+                    1b:d8:75:6d:0d:49:e1:f6:bf:12:dd:19:84:87:2e:
+                    6d:c6:7d:7e:42:33:2a:05:a2:ff:5d:07:10:83:a4:
+                    c0:35:a9:f8:00:96:29:9f:bc:53:6c:81:18:7b:e4:
+                    c6:41:54:7f:12:a3:5a:77:cb:0f:cf:52:8c:83:9a:
+                    30:03:ca:77:65:b2:c0:0b:00:67:86:50:77:b1:f5:
+                    79:b7:20:62:25:f8:3b:ca:cd:c4:da:d1:c0:81:fd:
+                    db:8b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                04:2E:A0:68:00:D7:DB:D3:E5:73:93:FC:1C:E5:30:78:D1:5B:24:E8
+            X509v3 Authority Key Identifier: 
+                keyid:DB:4B:A9:95:2C:AD:05:9F:CF:C8:3C:DE:3B:2C:27:81:D7:28:65:48
+                DirName:/CN=Easy-RSA CA
+                serial:66:32:E7:15:AE:20:E2:D7:6B:0E:3B:A3:50:C1:25:5A:45:69:14:A0
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+            X509v3 Subject Alternative Name: 
+                DNS:localhost, IP Address:127.0.0.1
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        41:35:5e:7e:14:46:96:3e:c9:8e:fe:88:f8:d6:07:6b:8b:b7:
+        8e:02:c4:63:97:79:ec:4a:46:cc:72:4d:7a:cc:9b:13:d9:6b:
+        5c:f9:b5:b6:c8:04:cf:f9:e0:23:b2:4e:ec:b0:80:85:84:be:
+        a9:1d:8d:4e:8b:26:09:d1:50:83:df:a2:d6:cc:ec:8c:36:b0:
+        c4:a9:cb:14:ba:2d:e2:f3:93:9a:e5:ae:fe:a6:b7:37:c2:17:
+        52:17:b2:f3:4e:3a:04:88:9b:50:7e:c5:73:6f:63:5c:ab:32:
+        47:0d:1c:b4:63:d4:de:c0:6b:ce:ec:26:8d:8c:40:83:c1:c2:
+        29:48:f8:0f:a1:b1:f9:5e:2b:91:fb:0d:32:26:db:73:ef:36:
+        03:d1:24:3e:59:8d:39:09:29:61:85:64:69:be:ee:ec:6d:dd:
+        6d:7c:93:22:b5:44:19:ed:11:f5:46:7d:f5:be:74:ce:46:85:
+        5d:24:9f:4e:b8:27:4b:7f:ba:72:5c:f7:24:10:b6:7b:fb:cb:
+        a0:d1:59:5b:d3:5f:e9:a3:e9:fd:c3:36:2f:b6:b5:eb:e6:1d:
+        9b:71:d6:53:26:95:26:64:14:25:47:b8:3b:d4:96:be:51:98:
+        e5:4d:cf:47:66:e8:fc:e9:bc:e6:6c:2b:e6:87:d8:cb:64:82:
+        d8:63:31:c9
+-----BEGIN CERTIFICATE-----
+MIIDdDCCAlygAwIBAgIRAPrucayc+FuATc5L01f4MgkwDQYJKoZIhvcNAQELBQAw
+FjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwIBcNMjQwNDI1MTUzNDE4WhgPMzAyMzA4
+MjcxNTM0MThaMBIxEDAOBgNVBAMMB2FsdHRlc3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCU9n4rQe4A1vUvVGb0QTlp7mQLFUZZzgC2vyqq9w51xOWh
+t7OGHCQG+pFB8QuHOu4mJyhiHaw1VOWjrEinmqq+LmBSfN7PwygRQldSnUQkj7C2
++zbvT6p+LFdeB4oD/BgD6FhriJiok6xpAbGc7zv+BEeeKOLGFflc394kHi+k4LIB
+lH64AHaw3TZVIvItOsex2Gd+yi0iuNydhzQMwRHHciu47RvYdW0NSeH2vxLdGYSH
+Lm3GfX5CMyoFov9dBxCDpMA1qfgAlimfvFNsgRh75MZBVH8So1p3yw/PUoyDmjAD
+yndlssALAGeGUHex9Xm3IGIl+DvKzcTa0cCB/duLAgMBAAGjgb4wgbswCQYDVR0T
+BAIwADAdBgNVHQ4EFgQUBC6gaADX29Plc5P8HOUweNFbJOgwUQYDVR0jBEowSIAU
+20uplSytBZ/PyDzeOywngdcoZUihGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENB
+ghRmMucVriDi12sOO6NQwSVaRWkUoDATBgNVHSUEDDAKBggrBgEFBQcDATALBgNV
+HQ8EBAMCBaAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
+CwUAA4IBAQBBNV5+FEaWPsmO/oj41gdri7eOAsRjl3nsSkbMck16zJsT2Wtc+bW2
+yATP+eAjsk7ssICFhL6pHY1OiyYJ0VCD36LWzOyMNrDEqcsUui3i85Oa5a7+prc3
+whdSF7LzTjoEiJtQfsVzb2NcqzJHDRy0Y9TewGvO7CaNjECDwcIpSPgPobH5XiuR
++w0yJttz7zYD0SQ+WY05CSlhhWRpvu7sbd1tfJMitUQZ7RH1Rn31vnTORoVdJJ9O
+uCdLf7pyXPckELZ7+8ug0Vlb01/po+n9wzYvtrXr5h2bcdZTJpUmZBQlR7g71Ja+
+UZjlTc9HZuj86bzmbCvmh9jLZILYYzHJ
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/issued/alttest.notes b/ipad/example_ca/pki/issued/alttest.notes
new file mode 100644
index 0000000..6daca26
--- /dev/null
+++ b/ipad/example_ca/pki/issued/alttest.notes
@@ -0,0 +1,8 @@
+This certificate is suitable for tests on any machine where testsuite and IPAd
+run on the same host.
+
+The alttest.crt certificate has been created using the following commandline:
+./easyrsa --subject-alt-name="DNS:localhost,IP:127.0.0.1" build-server-full alttest nopass
+
+The alttest.cabundle file has been created manually (alttest certificate at the
+top, ca certificate at the bottom).
diff --git a/ipad/example_ca/pki/issued/testsuite.cabundle b/ipad/example_ca/pki/issued/testsuite.cabundle
new file mode 100644
index 0000000..9768a94
--- /dev/null
+++ b/ipad/example_ca/pki/issued/testsuite.cabundle
@@ -0,0 +1,42 @@
+-----BEGIN CERTIFICATE-----
+MIIDbzCCAlegAwIBAgIQKqP4/8O1Yq/GeEU4ml8sWjANBgkqhkiG9w0BAQsFADAW
+MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTAgFw0yNDA0MjUxNTM0MzBaGA8zMDIzMDgy
+NzE1MzQzMFowFDESMBAGA1UEAwwJdGVzdHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAvA038bEtTA6voVGFkh8bPO8EGCTR1g7rc2SG2sZl4rJ0
++27AuV3+Z2FEOr8gbqdTnHuOa+zEVewL+UQIalQ1WYKaY2ALN90iXeNDgU5Rrgpn
+Mbux03AOqEYvEey26VglCslySpfx1XoNaJDrc8LhgRLNCBsh6c5YPtyB3rdlMb3E
+i1rRBpvA6rdjj/ulZzd+1WkHVmfz5zddhIZSJZSeamCiXL9eC8vIgxoXUYTxFvCD
+Rra7l/NPukEfMKjV7k4ueACbJf0M7MxXo4K1VFb9Jfn/uF8bVa5XFjUNzJrP0CxK
+3dWuKn52c6+42aA1YYI9oNHOo9iCGwyavKULLQDQ6QIDAQABo4G4MIG1MAkGA1Ud
+EwQCMAAwHQYDVR0OBBYEFCARBi67sAsF1M5PvF9ROeeWlE8mMFEGA1UdIwRKMEiA
+FNtLqZUsrQWfz8g83jssJ4HXKGVIoRqkGDAWMRQwEgYDVQQDDAtFYXN5LVJTQSBD
+QYIUZjLnFa4g4tdrDjujUMElWkVpFKAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYD
+VR0PBAQDAgWgMBQGA1UdEQQNMAuCCXRlc3RzdWl0ZTANBgkqhkiG9w0BAQsFAAOC
+AQEAeLEoJfUXesKgLri7Fdyq6I+qrvNIDkYpcdcka83aTrGMGkABeQPKLUV2yQhh
+UOsDnIKf1jfYYEL8WTW3Qmn9NkWToxff3V2EGQRwT8hfPpYnSQOBp1UsFn6+ZSZx
+SOtbNjjBqYfwrS5AW+gSOfXQYHFV10v70L81EfsunE/msTXGRbRzaJnZJ/pOmCV9
+bnwbIujCg287H0wncJQa7/sr/Z08os7yS9GO523b7CIcubTBvBeC6uEfdhpK1lmz
+JOXkZ7nO03Nn3UiCBLyPUDTADkJufmOs5qtxt3lb946MSKzvrsaw6a7XlJtY6Svo
+QJMbYlEtBqTKjOZ+jFrQbWmGbw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDTTCCAjWgAwIBAgIUZjLnFa4g4tdrDjujUMElWkVpFKAwDQYJKoZIhvcNAQEL
+BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwIBcNMjQwNDI1MTUzMzU2WhgPMzAy
+MzA4MjcxNTMzNTZaMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnR8Y1ESTRhfjVNZ0+nuhQsvkMhZnOMpaEoJz
+pCzHV0Cj6Mi814gPanvflAX/9F+4IjQ2evm7pNKNUpt1vf6kKTmco0EX672spP4p
+8KOQaki/+I/AMYCwAGOvmCMYpHMzNTkV9PZIUUyzLG5YaigiMtJpWY+ji/G+kxAg
+YzPr4WhTjG+mEoPjfc9LQH5dh/dP0cdkoZuIHWx6kFxAw/Okb1EF/oGrUT4pOLzg
+/Z5wkOYZhlK0bicCqvYfsUjJ4y0ftCXfjQUtAYfQ4gq6revQ7eHCNKixh+BB8yXO
+7/z6qrTfMTmN2Ekdo5nAyAMOeugaExaSLwYti3afX71RuqrtTwIDAQABo4GQMIGN
+MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFNtLqZUsrQWfz8g83jssJ4HXKGVIMFEG
+A1UdIwRKMEiAFNtLqZUsrQWfz8g83jssJ4HXKGVIoRqkGDAWMRQwEgYDVQQDDAtF
+YXN5LVJTQSBDQYIUZjLnFa4g4tdrDjujUMElWkVpFKAwCwYDVR0PBAQDAgEGMA0G
+CSqGSIb3DQEBCwUAA4IBAQAADFdB7R2mwfMWj3vUR77v9f3wqJdKgUyleXGKu6ot
+9YL8vYAJUL9sojZ8KeR47PDVpOs7v0Ll3RcfqRrDWQ9/MiMqSMcxh/i9dvyf5d9s
+o2kxqiPaMVPkLzGKE04I0XtAlszqOBYsGO83D2FuJsIWglvvOjNYvJ05LMVJObnq
+gpwY3TwhoKeWAQg6U5Yv6dLDjvbYPTwgArNpY97BxY0GZNyiyJgyag21cVui+tsd
+uLKVKhmW/EhCC52wsEMwLAsiOjNpVXwAkPWaWAbUJIJTyuc2ZFpx9D2T40H1U8Pj
+6UXwCkZ7C9qwKKyusG8duf/Xsdsft3Pm8XykSWWya6Um
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/issued/testsuite.crt b/ipad/example_ca/pki/issued/testsuite.crt
new file mode 100644
index 0000000..14904d1
--- /dev/null
+++ b/ipad/example_ca/pki/issued/testsuite.crt
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            2a:a3:f8:ff:c3:b5:62:af:c6:78:45:38:9a:5f:2c:5a
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Easy-RSA CA
+        Validity
+            Not Before: Apr 25 15:34:30 2024 GMT
+            Not After : Aug 27 15:34:30 3023 GMT
+        Subject: CN=testsuite
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:bc:0d:37:f1:b1:2d:4c:0e:af:a1:51:85:92:1f:
+                    1b:3c:ef:04:18:24:d1:d6:0e:eb:73:64:86:da:c6:
+                    65:e2:b2:74:fb:6e:c0:b9:5d:fe:67:61:44:3a:bf:
+                    20:6e:a7:53:9c:7b:8e:6b:ec:c4:55:ec:0b:f9:44:
+                    08:6a:54:35:59:82:9a:63:60:0b:37:dd:22:5d:e3:
+                    43:81:4e:51:ae:0a:67:31:bb:b1:d3:70:0e:a8:46:
+                    2f:11:ec:b6:e9:58:25:0a:c9:72:4a:97:f1:d5:7a:
+                    0d:68:90:eb:73:c2:e1:81:12:cd:08:1b:21:e9:ce:
+                    58:3e:dc:81:de:b7:65:31:bd:c4:8b:5a:d1:06:9b:
+                    c0:ea:b7:63:8f:fb:a5:67:37:7e:d5:69:07:56:67:
+                    f3:e7:37:5d:84:86:52:25:94:9e:6a:60:a2:5c:bf:
+                    5e:0b:cb:c8:83:1a:17:51:84:f1:16:f0:83:46:b6:
+                    bb:97:f3:4f:ba:41:1f:30:a8:d5:ee:4e:2e:78:00:
+                    9b:25:fd:0c:ec:cc:57:a3:82:b5:54:56:fd:25:f9:
+                    ff:b8:5f:1b:55:ae:57:16:35:0d:cc:9a:cf:d0:2c:
+                    4a:dd:d5:ae:2a:7e:76:73:af:b8:d9:a0:35:61:82:
+                    3d:a0:d1:ce:a3:d8:82:1b:0c:9a:bc:a5:0b:2d:00:
+                    d0:e9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                20:11:06:2E:BB:B0:0B:05:D4:CE:4F:BC:5F:51:39:E7:96:94:4F:26
+            X509v3 Authority Key Identifier: 
+                keyid:DB:4B:A9:95:2C:AD:05:9F:CF:C8:3C:DE:3B:2C:27:81:D7:28:65:48
+                DirName:/CN=Easy-RSA CA
+                serial:66:32:E7:15:AE:20:E2:D7:6B:0E:3B:A3:50:C1:25:5A:45:69:14:A0
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+            X509v3 Subject Alternative Name: 
+                DNS:testsuite
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        78:b1:28:25:f5:17:7a:c2:a0:2e:b8:bb:15:dc:aa:e8:8f:aa:
+        ae:f3:48:0e:46:29:71:d7:24:6b:cd:da:4e:b1:8c:1a:40:01:
+        79:03:ca:2d:45:76:c9:08:61:50:eb:03:9c:82:9f:d6:37:d8:
+        60:42:fc:59:35:b7:42:69:fd:36:45:93:a3:17:df:dd:5d:84:
+        19:04:70:4f:c8:5f:3e:96:27:49:03:81:a7:55:2c:16:7e:be:
+        65:26:71:48:eb:5b:36:38:c1:a9:87:f0:ad:2e:40:5b:e8:12:
+        39:f5:d0:60:71:55:d7:4b:fb:d0:bf:35:11:fb:2e:9c:4f:e6:
+        b1:35:c6:45:b4:73:68:99:d9:27:fa:4e:98:25:7d:6e:7c:1b:
+        22:e8:c2:83:6f:3b:1f:4c:27:70:94:1a:ef:fb:2b:fd:9d:3c:
+        a2:ce:f2:4b:d1:8e:e7:6d:db:ec:22:1c:b9:b4:c1:bc:17:82:
+        ea:e1:1f:76:1a:4a:d6:59:b3:24:e5:e4:67:b9:ce:d3:73:67:
+        dd:48:82:04:bc:8f:50:34:c0:0e:42:6e:7e:63:ac:e6:ab:71:
+        b7:79:5b:f7:8e:8c:48:ac:ef:ae:c6:b0:e9:ae:d7:94:9b:58:
+        e9:2b:e8:40:93:1b:62:51:2d:06:a4:ca:8c:e6:7e:8c:5a:d0:
+        6d:69:86:6f
+-----BEGIN CERTIFICATE-----
+MIIDbzCCAlegAwIBAgIQKqP4/8O1Yq/GeEU4ml8sWjANBgkqhkiG9w0BAQsFADAW
+MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTAgFw0yNDA0MjUxNTM0MzBaGA8zMDIzMDgy
+NzE1MzQzMFowFDESMBAGA1UEAwwJdGVzdHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAvA038bEtTA6voVGFkh8bPO8EGCTR1g7rc2SG2sZl4rJ0
++27AuV3+Z2FEOr8gbqdTnHuOa+zEVewL+UQIalQ1WYKaY2ALN90iXeNDgU5Rrgpn
+Mbux03AOqEYvEey26VglCslySpfx1XoNaJDrc8LhgRLNCBsh6c5YPtyB3rdlMb3E
+i1rRBpvA6rdjj/ulZzd+1WkHVmfz5zddhIZSJZSeamCiXL9eC8vIgxoXUYTxFvCD
+Rra7l/NPukEfMKjV7k4ueACbJf0M7MxXo4K1VFb9Jfn/uF8bVa5XFjUNzJrP0CxK
+3dWuKn52c6+42aA1YYI9oNHOo9iCGwyavKULLQDQ6QIDAQABo4G4MIG1MAkGA1Ud
+EwQCMAAwHQYDVR0OBBYEFCARBi67sAsF1M5PvF9ROeeWlE8mMFEGA1UdIwRKMEiA
+FNtLqZUsrQWfz8g83jssJ4HXKGVIoRqkGDAWMRQwEgYDVQQDDAtFYXN5LVJTQSBD
+QYIUZjLnFa4g4tdrDjujUMElWkVpFKAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYD
+VR0PBAQDAgWgMBQGA1UdEQQNMAuCCXRlc3RzdWl0ZTANBgkqhkiG9w0BAQsFAAOC
+AQEAeLEoJfUXesKgLri7Fdyq6I+qrvNIDkYpcdcka83aTrGMGkABeQPKLUV2yQhh
+UOsDnIKf1jfYYEL8WTW3Qmn9NkWToxff3V2EGQRwT8hfPpYnSQOBp1UsFn6+ZSZx
+SOtbNjjBqYfwrS5AW+gSOfXQYHFV10v70L81EfsunE/msTXGRbRzaJnZJ/pOmCV9
+bnwbIujCg287H0wncJQa7/sr/Z08os7yS9GO523b7CIcubTBvBeC6uEfdhpK1lmz
+JOXkZ7nO03Nn3UiCBLyPUDTADkJufmOs5qtxt3lb946MSKzvrsaw6a7XlJtY6Svo
+QJMbYlEtBqTKjOZ+jFrQbWmGbw==
+-----END CERTIFICATE-----
diff --git a/ipad/example_ca/pki/issued/testsuite.notes b/ipad/example_ca/pki/issued/testsuite.notes
new file mode 100644
index 0000000..55594a6
--- /dev/null
+++ b/ipad/example_ca/pki/issued/testsuite.notes
@@ -0,0 +1,8 @@
+This certificate is suitable for tests where the testsuite runs on a separate
+machine or VM that has the hostname "testsuite"
+
+The testsuite.crt certificate has been created using the following commandline:
+./easyrsa --subject-alt-name="DNS:testsuite" build-server-full testsuite nopass
+
+The testsuite.cabundle file has been created manually (alttest certificate at the
+top, ca certificate at the bottom).
diff --git a/ipad/example_ca/pki/openssl-easyrsa.cnf b/ipad/example_ca/pki/openssl-easyrsa.cnf
new file mode 100644
index 0000000..928b195
--- /dev/null
+++ b/ipad/example_ca/pki/openssl-easyrsa.cnf
@@ -0,0 +1,143 @@
+# For use with Easy-RSA 3.0+ and OpenSSL or LibreSSL
+
+####################################################################
+[ ca ]
+default_ca	= CA_default		# The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir		= $ENV::EASYRSA_PKI	# Where everything is kept
+certs		= $dir			# Where the issued certs are kept
+crl_dir		= $dir			# Where the issued crl are kept
+database	= $dir/index.txt	# database index file.
+new_certs_dir	= $dir/certs_by_serial	# default place for new certs.
+
+certificate	= $dir/ca.crt	 	# The CA certificate
+serial		= $dir/serial 		# The current serial number
+crl		= $dir/crl.pem 		# The current CRL
+private_key	= $dir/private/ca.key	# The private key
+RANDFILE	= $dir/.rand		# private random number file
+
+x509_extensions	= basic_exts		# The extensions to add to the cert
+
+# A placeholder to handle the --copy-ext feature:
+#%COPY_EXTS%	# Do NOT remove or change this line as --copy-ext support requires it
+
+# This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA
+# is designed for will. In return, we get the Issuer attached to CRLs.
+crl_extensions	= crl_ext
+
+default_days	= $ENV::EASYRSA_CERT_EXPIRE	# how long to certify for
+default_crl_days	= $ENV::EASYRSA_CRL_DAYS	# how long before next CRL
+default_md	= $ENV::EASYRSA_DIGEST		# use public key default MD
+preserve	= no			# keep passed DN ordering
+
+# This allows to renew certificates which have not been revoked
+unique_subject	= no
+
+# A few different ways of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy		= policy_anything
+
+# For the 'anything' policy, which defines allowed DN fields
+[ policy_anything ]
+countryName		= optional
+stateOrProvinceName	= optional
+localityName		= optional
+organizationName	= optional
+organizationalUnitName	= optional
+commonName		= supplied
+name			= optional
+emailAddress		= optional
+
+####################################################################
+# Easy-RSA request handling
+# We key off $DN_MODE to determine how to format the DN
+[ req ]
+default_bits		= $ENV::EASYRSA_KEY_SIZE
+default_keyfile 	= privkey.pem
+default_md		= $ENV::EASYRSA_DIGEST
+distinguished_name	= $ENV::EASYRSA_DN
+x509_extensions		= easyrsa_ca	# The extensions to add to the self signed cert
+
+# A placeholder to handle the $EXTRA_EXTS feature:
+#%EXTRA_EXTS%	# Do NOT remove or change this line as $EXTRA_EXTS support requires it
+
+####################################################################
+# Easy-RSA DN (Subject) handling
+
+# Easy-RSA DN for cn_only support:
+[ cn_only ]
+commonName		= Common Name (eg: your user, host, or server name)
+commonName_max		= 64
+commonName_default	= $ENV::EASYRSA_REQ_CN
+
+# Easy-RSA DN for org support:
+[ org ]
+countryName			= Country Name (2 letter code)
+countryName_default		= $ENV::EASYRSA_REQ_COUNTRY
+countryName_min			= 2
+countryName_max			= 2
+
+stateOrProvinceName		= State or Province Name (full name)
+stateOrProvinceName_default	= $ENV::EASYRSA_REQ_PROVINCE
+
+localityName			= Locality Name (eg, city)
+localityName_default		= $ENV::EASYRSA_REQ_CITY
+
+0.organizationName		= Organization Name (eg, company)
+0.organizationName_default	= $ENV::EASYRSA_REQ_ORG
+
+organizationalUnitName		= Organizational Unit Name (eg, section)
+organizationalUnitName_default	= $ENV::EASYRSA_REQ_OU
+
+commonName			= Common Name (eg: your user, host, or server name)
+commonName_max			= 64
+commonName_default		= $ENV::EASYRSA_REQ_CN
+
+emailAddress			= Email Address
+emailAddress_default		= $ENV::EASYRSA_REQ_EMAIL
+emailAddress_max		= 64
+
+####################################################################
+# Easy-RSA cert extension handling
+
+# This section is effectively unused as the main script sets extensions
+# dynamically. This core section is left to support the odd usecase where
+# a user calls openssl directly.
+[ basic_exts ]
+basicConstraints	= CA:FALSE
+subjectKeyIdentifier	= hash
+authorityKeyIdentifier	= keyid,issuer:always
+
+# The Easy-RSA CA extensions
+[ easyrsa_ca ]
+
+# PKIX recommendations:
+
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This could be marked critical, but it's nice to support reading by any
+# broken clients who attempt to do so.
+basicConstraints = CA:true
+
+# Limit key usage to CA tasks. If you really want to use the generated pair as
+# a self-signed cert, comment this out.
+keyUsage = cRLSign, keyCertSign
+
+# nsCertType omitted by default. Let's try to let the deprecated stuff die.
+# nsCertType = sslCA
+
+# A placeholder to handle the $X509_TYPES and CA extra extensions $EXTRA_EXTS:
+#%CA_X509_TYPES_EXTRA_EXTS%	# Do NOT remove or change this line as $X509_TYPES and EXTRA_EXTS demands it
+
+# CRL extensions.
+[ crl_ext ]
+
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/ipad/example_ca/pki/private/alttest.key b/ipad/example_ca/pki/private/alttest.key
new file mode 100644
index 0000000..c334f49
--- /dev/null
+++ b/ipad/example_ca/pki/private/alttest.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCU9n4rQe4A1vUv
+VGb0QTlp7mQLFUZZzgC2vyqq9w51xOWht7OGHCQG+pFB8QuHOu4mJyhiHaw1VOWj
+rEinmqq+LmBSfN7PwygRQldSnUQkj7C2+zbvT6p+LFdeB4oD/BgD6FhriJiok6xp
+AbGc7zv+BEeeKOLGFflc394kHi+k4LIBlH64AHaw3TZVIvItOsex2Gd+yi0iuNyd
+hzQMwRHHciu47RvYdW0NSeH2vxLdGYSHLm3GfX5CMyoFov9dBxCDpMA1qfgAlimf
+vFNsgRh75MZBVH8So1p3yw/PUoyDmjADyndlssALAGeGUHex9Xm3IGIl+DvKzcTa
+0cCB/duLAgMBAAECggEACbh+yeqG0iiKM3PPNsfoK+YnQnnkRLP8DpuG+Jp1UnDD
+iLwTdlWbxut5qH3xrKTHKazge8FH8ur+rqGYKX0fAJjHfFqIXQfKiOXKtlTA6kne
+KZ1XG7gX03Kn+ODbvCAqnlv+eSCe0FFirNo0HEjtofPm4IahKx//98mRa3X00fjQ
+41+pwrtj5TBeHc8V9QiHDDTfAtUcRKbA3yPyla0xdHektCDak1U6CMoR/p55l+rM
+2ffBHJA+wNc28NfxV+ZY1VbpZ0qszAp3/U+gQRn0P9+2scIAWzRBlmQ37EfAMmM8
+ciembbDpoi7/tMQ0UhrhCR/o5hatQwS8ACEuLC3ucQKBgQDLBGSvuGBvWYget/2+
+jhCjYyH5s0Pye0iCcUlZDIsi1RjtgQfXNo5J1yP7uaPHJ/3Saoohb844CD0+kLjS
+tYpGSePL+q8HGnjfutjy0Xstew5peD6quc15G6gyfCBKdC39R9BfuC2emw9eZeiG
+qRmGpFKwD3PDS5ZNz3HJ/WG41QKBgQC71rlMXGsnq63OVcKvw32Kn6XVsHXhoxFd
+DWy43QbGqVV2Lk36/mr8iotBOV4BsofWD8Fx8447lhERuTi9NHSlIaAldnng0Eok
+RoW+Lr6QbQanuLjM+NLhPcdrhZPrp4pHFUgnj2PjmLAngmvyaa4l/m88UvYVWPyK
+vxUzNtNy3wKBgQCL9ZpoXib1fPbPnq6rOQuVaFla6NBWEdH6Q5l6b6BYQiruSb8b
+CnxrwYsIFoInYZWmA1b5GDhF/sAiKumQMiGCtZv62vbhYcmlDA5W0D4oK6bS5Vfm
+oTNbY8rACzzDt3ahH2ozIykoJ+QfgwgcFeYIIa7zu6NmJu0W9YWP6EP/hQKBgApq
+Y6f6T+7JNEAGvV7lpiZzp8xrln3GfwX74pV1nBST+yssciKCzQfn3sTlG3NYpPOX
+uBBLgw2GyreC38SODhHCBZFOOn/ezN2qE2xyRxrXENFoCsdC3N6kgFRT+dnNVnuO
+kIuxBcbvBoWKU9YDSibNLvnXV9HjN02yPsiyN5NdAoGAZj0u++sJWrYzBeGDO0ew
+a0GJnQK8/4NR+vJz/vvmL/lidfKOFJ5/lNANRha7ep89ig7G96ejabEitghIH9I7
+0+OxHz5uk+lidlTPxTg64ELlJnbsPzdI6QygeFVp8QqxEYgzB3zi8ropSoVIKVkB
+2+9FJlDHUFB+PG7cbfR70a8=
+-----END PRIVATE KEY-----
diff --git a/ipad/example_ca/pki/private/ca.key b/ipad/example_ca/pki/private/ca.key
new file mode 100644
index 0000000..ca1c505
--- /dev/null
+++ b/ipad/example_ca/pki/private/ca.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCdHxjURJNGF+NU
+1nT6e6FCy+QyFmc4yloSgnOkLMdXQKPoyLzXiA9qe9+UBf/0X7giNDZ6+buk0o1S
+m3W9/qQpOZyjQRfrvayk/inwo5BqSL/4j8AxgLAAY6+YIxikczM1ORX09khRTLMs
+blhqKCIy0mlZj6OL8b6TECBjM+vhaFOMb6YSg+N9z0tAfl2H90/Rx2Shm4gdbHqQ
+XEDD86RvUQX+gatRPik4vOD9nnCQ5hmGUrRuJwKq9h+xSMnjLR+0Jd+NBS0Bh9Di
+Crqt69Dt4cI0qLGH4EHzJc7v/PqqtN8xOY3YSR2jmcDIAw566BoTFpIvBi2Ldp9f
+vVG6qu1PAgMBAAECggEAAdFyJRuDuPn5DU961Xm3muSjvdXmUhfBj2NFsOE8Zy5w
+rQQGEN7yI1qEjaWvSM/1eyVRUVY+yDSW5b7r8Wa8Jwun4ruGQbTi3VdhRZlT/gKm
+qPyRR0FeBKWpZZ62I0nd+jLLYoNj6Q1Zyxzu7e5+icMRc3BWIE7qTbDTgM1SAjxm
+OhNnQmWVq/E4wP4JXkjy2zxZZPjbq5awhvPzeApq/QspKNp9PE9rOHRbyi5kknYO
+nYc4hn2McHegsfyN0gXsLkDgwKqFG84HZRKOjnDUm8EOCC0L0Zhs2lYmpemeKP+f
+4ro5mhvJQ8Xe3iUcfAAQypRUyOyCXVJY7A0yzSWrEQKBgQDO2CoimFzktgHQwN7x
+HriYg4Ass1Y/gZq2N7APqbFJZIeJlouKqlZ6uF+eWqMZf96XidOC37BMH2R0yAvP
+vPHTGycSZozE0tGNscLxQ8nGYu2tDzryCBrjpNUaKY5HVYK/9D1toSnvOWJAZlHN
+lOx5sDOlwCpXR1DANUZtsVRCCQKBgQDCde3B59fW4FbB7+hk0qLxhKnlIt0UFOuB
+4Kg/UZZYvJA1bGW1LZGVNXpMIyRpPODW5B979Eb/azF6LtW/MzwZ2ZM9aXKRFA0S
++J2whjdBebWG/PuwEwKHo/wfzEJLeVW2VOEUknirn5PnI4is2LiTCfnls8PlkSzF
+klK/7K6qlwKBgEIPse1Yohp9sri8ULfLqwMyxIYCROKFfycBRB7MgI3DKLKdvTVt
+T69kIU3O/tZPC4V0hHQBAypcwFW36mXPn6BfxKvQyta1yi2p/2vUzaWpxOUHvzi7
+s/LOmyz+5q0Lt3WdCN1xopX/ysxsoWW6UYhP6T7fz+YOJdEtcq/n+dQZAoGAAhR6
+15EgSOcbZnWnebSbE5REsPO/g6B5qGj7w7merxJNRJUFPXvgS8VHqprRn+KL0SCd
+iZjiTYca/2CS3rmwkeI25fhDxnN9dE9+eE3nN2cS3v/DvW1moIbLgpePufjxRsL/
+qVWrvsI1Ncq2gorK5p+7sY5LsR/tZ6uaAP2KHL8CgYEAsPllojZVSxcWuWN8YD6U
+hPTsmH9EwxN6kqB2Ai2ZN3i5kmRnZNv8xBJcf9bJY5YlV7ycyPf3RXfNLVlA/8Ox
+Tnyn+hpNDDXNnOaiOYjlG0NC1XYesJDN2WyaRNIrXpWXGWD28VGK4sKVNdxV6lOC
+fLxfcjGPfAqfHtUoOiQofXU=
+-----END PRIVATE KEY-----
diff --git a/ipad/example_ca/pki/private/testsuite.key b/ipad/example_ca/pki/private/testsuite.key
new file mode 100644
index 0000000..0587614
--- /dev/null
+++ b/ipad/example_ca/pki/private/testsuite.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC8DTfxsS1MDq+h
+UYWSHxs87wQYJNHWDutzZIbaxmXisnT7bsC5Xf5nYUQ6vyBup1Oce45r7MRV7Av5
+RAhqVDVZgppjYAs33SJd40OBTlGuCmcxu7HTcA6oRi8R7LbpWCUKyXJKl/HVeg1o
+kOtzwuGBEs0IGyHpzlg+3IHet2UxvcSLWtEGm8Dqt2OP+6VnN37VaQdWZ/PnN12E
+hlIllJ5qYKJcv14Ly8iDGhdRhPEW8INGtruX80+6QR8wqNXuTi54AJsl/QzszFej
+grVUVv0l+f+4XxtVrlcWNQ3Mms/QLErd1a4qfnZzr7jZoDVhgj2g0c6j2IIbDJq8
+pQstANDpAgMBAAECggEAAq7WTAU+iGz8ttd3iWrjcl8vUfHDiYzsSv8/PwBd4rbW
+VuIago9VK/zEcqlrqs+wShJUT4g6hS0BS9QB4gd6L+ERkOALy1Prhu1xQ8p+Fv0C
+KI120OjfcqmDevT2p2j49VJdf+b/t3XR2pqXtPuUSIL5lSQmKJehGDuAtSPGpprt
+Ri47/bstEZ9l6xweRUbWtLY7v3Ul+nMZO1HDl+MMY2Cy1Ou6JFuJfEyWYWzs4Uor
+b47b0uH/8b0STXX4xw4s5o/0NuSQPIsOM/LN6vZIEM3euYqeLsi/VKXFrTjyrLed
+WjldhwwJdxUV6Pr+2s3CFXPqfaJ8amFe1cf/gEk4MQKBgQDeBYr9oyHQ9fER1B7o
+ob5LY+37BfaEcQnnuscBDGHJteYamlc+XXHa2UAOoNYUC6SMjzupMNdV6u6JEvP5
+35sGZtP+tKLRxElMD9XBc7m17cWUbjWlplgCLVdly7bgprYPANHEr9djwuq9oppq
+clsklx7NawpTYFBg+zrzxBYP0QKBgQDY1Mi4x2JdMtFM+X00MyFjQq3lHexSo5XF
+rMgU2A145zAlXiuEVkyqR+Pv3hwm38qqoUAkyIDhXth3C7f75gcQgsgthJJbU6LM
+jKhh+/PSg4x3/YmBWQfRiHv9KstAvX7y2oaZIBfBK9ZuPID0QY2RIfUA5KYdBkOP
+9urhR3fNmQKBgFMpeFpxFGWU+etXrQwuKX1LvQRdw2zwemlWSNxXqvlHLR2h2jP+
+BHuZDKluDUIM6mHL9Oj25nHEQf0OIFzkKMlJEvdA6gvwnhPjiomfs1w15+AlN+sI
+V8bY/PegSqvzRhZwlCI8S02O4SaPFY/xrboS8PK4uXFpjjIFaJuOQ0VBAoGAblbp
+xc4Aqjif9bHIGvYh+WcHIt61UeBY6Pzh3GmNgYb0Iy/mqTNZVBW9UmUOomGjumzQ
+PWei3gzrzrix6YfG9In43+DksYDACaNSVHpoOyoiIzVr8dyic+gmYFCUmd9UaLT3
+ZZjFPdHXDsXPQXzSU5aaHNg+B+sWGn6mS/mYZ5ECgYAHCvNEO4NHf5AfpAIeZyD5
+1x3hWR3LtI6qkD5LmVhxi6S4pjzQj+T5ZC+iiz0ZZ6GoA2n+UDX4kF1aSgEJry1i
+P5ByLciv7hbYWZtpOAy0Z+MtKOFB5Wj4WsvWCAZnL/5qk9zRyoNuKWYrs3FQlmEt
+WIxjZC8intDxtAv4KiJdGQ==
+-----END PRIVATE KEY-----
diff --git a/ipad/example_ca/pki/reqs/alttest.req b/ipad/example_ca/pki/reqs/alttest.req
new file mode 100644
index 0000000..c3a3241
--- /dev/null
+++ b/ipad/example_ca/pki/reqs/alttest.req
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIChDCCAWwCAQAwEjEQMA4GA1UEAwwHYWx0dGVzdDCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAJT2fitB7gDW9S9UZvRBOWnuZAsVRlnOALa/Kqr3DnXE
+5aG3s4YcJAb6kUHxC4c67iYnKGIdrDVU5aOsSKeaqr4uYFJ83s/DKBFCV1KdRCSP
+sLb7Nu9Pqn4sV14HigP8GAPoWGuImKiTrGkBsZzvO/4ER54o4sYV+Vzf3iQeL6Tg
+sgGUfrgAdrDdNlUi8i06x7HYZ37KLSK43J2HNAzBEcdyK7jtG9h1bQ1J4fa/Et0Z
+hIcubcZ9fkIzKgWi/10HEIOkwDWp+ACWKZ+8U2yBGHvkxkFUfxKjWnfLD89SjIOa
+MAPKd2WywAsAZ4ZQd7H1ebcgYiX4O8rNxNrRwIH924sCAwEAAaAtMCsGCSqGSIb3
+DQEJDjEeMBwwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
+CwUAA4IBAQBgx4vAKtNXLloRv+cmqTdtNSrTeUz4gR2OB96tv7/Y8nPInDuOS5YA
+H0y/4d9WjybeeKtSGEWfcxWTPtEvye4HdEP5S4ajmDzAVngfqBBtOZ2a9YXYndwf
+Y/tG6AeaJZs7r4LAnRaLFJKwf+P+SL4Sz1ygZZnolUgI3KCH5iJFfWXIKcFvsp8Z
+QjtFaKTLnODI9DbyBZg4bJUyddRfEvQCBnd4E7BKaIJif32nUaV18YZ027onUONj
+IBaPqbMBHbVb5gXAIqc3u39Ut9dtD/XXxGMAkK3vjEGfPBoNqwVQAj5NxK/+CEwZ
++gdlC3YXEn0Bp/QTwGPtkpaiqClqVZiG
+-----END CERTIFICATE REQUEST-----
diff --git a/ipad/example_ca/pki/reqs/testsuite.req b/ipad/example_ca/pki/reqs/testsuite.req
new file mode 100644
index 0000000..877c3a2
--- /dev/null
+++ b/ipad/example_ca/pki/reqs/testsuite.req
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICgDCCAWgCAQAwFDESMBAGA1UEAwwJdGVzdHN1aXRlMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAvA038bEtTA6voVGFkh8bPO8EGCTR1g7rc2SG2sZl
+4rJ0+27AuV3+Z2FEOr8gbqdTnHuOa+zEVewL+UQIalQ1WYKaY2ALN90iXeNDgU5R
+rgpnMbux03AOqEYvEey26VglCslySpfx1XoNaJDrc8LhgRLNCBsh6c5YPtyB3rdl
+Mb3Ei1rRBpvA6rdjj/ulZzd+1WkHVmfz5zddhIZSJZSeamCiXL9eC8vIgxoXUYTx
+FvCDRra7l/NPukEfMKjV7k4ueACbJf0M7MxXo4K1VFb9Jfn/uF8bVa5XFjUNzJrP
+0CxK3dWuKn52c6+42aA1YYI9oNHOo9iCGwyavKULLQDQ6QIDAQABoCcwJQYJKoZI
+hvcNAQkOMRgwFjAUBgNVHREEDTALggl0ZXN0c3VpdGUwDQYJKoZIhvcNAQELBQAD
+ggEBAA8Se8HfjHNH9UgQFYE2/elUr0QiPoI5EFEswMwO99E1kDM4pq9g/h2wqwW6
+49NkZzzJfuTERM3ZUQC3+AV7pW9rDEQFf5GGUeM5VmBYiFgPK7FoVJkRJ4MroPti
+72uADGBXexYFUsbf6V09T0B80yarmNHNCFUChNY5lhcWEYpJuGXnbpGhzZXTPplw
+GZmWDUFVHKSPJX2GZw2AF+MfnyNOCRu+VkU4vjbCm8LQENQBDq1HZ5nYi2eHlW5w
+x/rmHZx8wv+ipY3DsG8bCho6fuaSvQI9fHi1UVRJcP1bdocCjFk+N1yj+i58TPRK
+FoU4y2362LU2nc1mOPeGuQu11Wk=
+-----END CERTIFICATE REQUEST-----
diff --git a/ipad/example_ca/pki/safessl-easyrsa.cnf b/ipad/example_ca/pki/safessl-easyrsa.cnf
new file mode 100644
index 0000000..d42bba9
--- /dev/null
+++ b/ipad/example_ca/pki/safessl-easyrsa.cnf
@@ -0,0 +1,143 @@
+# For use with Easy-RSA 3.0+ and OpenSSL or LibreSSL
+
+####################################################################
+[ ca ]
+default_ca	= CA_default		# The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir		= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki	# Where everything is kept
+certs		= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki			# Where the issued certs are kept
+crl_dir		= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki			# Where the issued crl are kept
+database	= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/index.txt	# database index file.
+new_certs_dir	= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/certs_by_serial	# default place for new certs.
+
+certificate	= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/ca.crt	 	# The CA certificate
+serial		= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/serial 		# The current serial number
+crl		= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/crl.pem 		# The current CRL
+private_key	= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/private/ca.key	# The private key
+RANDFILE	= /home/user/work/ttcn3/testsuite/osmo-ttcn3-hacks/ipad/example_ca/pki/.rand		# private random number file
+
+x509_extensions	= basic_exts		# The extensions to add to the cert
+
+# A placeholder to handle the --copy-ext feature:
+#%COPY_EXTS%	# Do NOT remove or change this line as --copy-ext support requires it
+
+# This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA
+# is designed for will. In return, we get the Issuer attached to CRLs.
+crl_extensions	= crl_ext
+
+default_days	= 365000	# how long to certify for
+default_crl_days	= 180	# how long before next CRL
+default_md	= sha256		# use public key default MD
+preserve	= no			# keep passed DN ordering
+
+# This allows to renew certificates which have not been revoked
+unique_subject	= no
+
+# A few different ways of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy		= policy_anything
+
+# For the 'anything' policy, which defines allowed DN fields
+[ policy_anything ]
+countryName		= optional
+stateOrProvinceName	= optional
+localityName		= optional
+organizationName	= optional
+organizationalUnitName	= optional
+commonName		= supplied
+name			= optional
+emailAddress		= optional
+
+####################################################################
+# Easy-RSA request handling
+# We key off $DN_MODE to determine how to format the DN
+[ req ]
+default_bits		= 2048
+default_keyfile 	= privkey.pem
+default_md		= sha256
+distinguished_name	= cn_only
+x509_extensions		= easyrsa_ca	# The extensions to add to the self signed cert
+
+# A placeholder to handle the $EXTRA_EXTS feature:
+#%EXTRA_EXTS%	# Do NOT remove or change this line as $EXTRA_EXTS support requires it
+
+####################################################################
+# Easy-RSA DN (Subject) handling
+
+# Easy-RSA DN for cn_only support:
+[ cn_only ]
+commonName		= Common Name (eg: your user, host, or server name)
+commonName_max		= 64
+commonName_default	= ChangeMe
+
+# Easy-RSA DN for org support:
+[ org ]
+countryName			= Country Name (2 letter code)
+countryName_default		= US
+countryName_min			= 2
+countryName_max			= 2
+
+stateOrProvinceName		= State or Province Name (full name)
+stateOrProvinceName_default	= California
+
+localityName			= Locality Name (eg, city)
+localityName_default		= San Francisco
+
+0.organizationName		= Organization Name (eg, company)
+0.organizationName_default	= Copyleft Certificate Co
+
+organizationalUnitName		= Organizational Unit Name (eg, section)
+organizationalUnitName_default	= My Organizational Unit
+
+commonName			= Common Name (eg: your user, host, or server name)
+commonName_max			= 64
+commonName_default		= ChangeMe
+
+emailAddress			= Email Address
+emailAddress_default		= me@example.net
+emailAddress_max		= 64
+
+####################################################################
+# Easy-RSA cert extension handling
+
+# This section is effectively unused as the main script sets extensions
+# dynamically. This core section is left to support the odd usecase where
+# a user calls openssl directly.
+[ basic_exts ]
+basicConstraints	= CA:FALSE
+subjectKeyIdentifier	= hash
+authorityKeyIdentifier	= keyid,issuer:always
+
+# The Easy-RSA CA extensions
+[ easyrsa_ca ]
+
+# PKIX recommendations:
+
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This could be marked critical, but it's nice to support reading by any
+# broken clients who attempt to do so.
+basicConstraints = CA:true
+
+# Limit key usage to CA tasks. If you really want to use the generated pair as
+# a self-signed cert, comment this out.
+keyUsage = cRLSign, keyCertSign
+
+# nsCertType omitted by default. Let's try to let the deprecated stuff die.
+# nsCertType = sslCA
+
+# A placeholder to handle the $X509_TYPES and CA extra extensions $EXTRA_EXTS:
+#%CA_X509_TYPES_EXTRA_EXTS%	# Do NOT remove or change this line as $X509_TYPES and EXTRA_EXTS demands it
+
+# CRL extensions.
+[ crl_ext ]
+
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/ipad/example_ca/pki/serial b/ipad/example_ca/pki/serial
new file mode 100644
index 0000000..ec9e3df
--- /dev/null
+++ b/ipad/example_ca/pki/serial
@@ -0,0 +1 @@
+2AA3F8FFC3B562AFC67845389A5F2C5B
diff --git a/ipad/example_ca/pki/serial.old b/ipad/example_ca/pki/serial.old
new file mode 100644
index 0000000..406eea8
--- /dev/null
+++ b/ipad/example_ca/pki/serial.old
@@ -0,0 +1 @@
+2aa3f8ffc3b562afc67845389a5f2c5a
diff --git a/ipad/example_ca/pki/vars b/ipad/example_ca/pki/vars
new file mode 100644
index 0000000..4cb08cd
--- /dev/null
+++ b/ipad/example_ca/pki/vars
@@ -0,0 +1,235 @@
+# Easy-RSA 3 parameter settings
+
+# NOTE: If you installed Easy-RSA from your package manager, do not edit
+# this file in place -- instead, you should copy the entire easy-rsa directory
+# to another location so future upgrades do not wipe out your changes.
+
+# HOW TO USE THIS FILE
+#
+# vars.example contains built-in examples to Easy-RSA settings. You MUST name
+# this file "vars" if you want it to be used as a configuration file. If you do
+# not, it WILL NOT be automatically read when you call easyrsa commands.
+#
+# It is not necessary to use this config file unless you wish to change
+# operational defaults. These defaults should be fine for many uses without the
+# need to copy and edit the "vars" file.
+#
+# All of the editable settings are shown commented and start with the command
+# "set_var" -- this means any set_var command that is uncommented has been
+# modified by the user. If you are happy with a default, there is no need to
+# define the value to its default.
+
+# NOTES FOR WINDOWS USERS
+#
+# Paths for Windows  *MUST* use forward slashes, or optionally double-escaped
+# backslashes (single forward slashes are recommended.) This means your path to
+# the openssl binary might look like this:
+# "C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
+
+# A little housekeeping: DO NOT EDIT THIS SECTION
+#
+# Easy-RSA 3.x does not source into the environment directly.
+# Complain if a user tries to do this:
+if [ -z "$EASYRSA_CALLER" ]; then
+	echo "You appear to be sourcing an Easy-RSA *vars* file." >&2
+	echo "This is no longer necessary and is disallowed. See the section called" >&2
+	echo "*How to use this file* near the top comments for more details." >&2
+	return 1
+fi
+
+# DO YOUR EDITS BELOW THIS POINT
+
+# This variable is used as the base location of configuration files needed by
+# easyrsa.  More specific variables for specific files (e.g., EASYRSA_SSL_CONF)
+# may override this default.
+#
+# The default value of this variable is the location of the easyrsa script
+# itself, which is also where the configuration files are located in the
+# easy-rsa tree.
+
+#set_var EASYRSA	"${0%/*}"
+
+# If your OpenSSL command is not in the system PATH, you will need to define the
+# path to it here. Normally this means a full path to the executable, otherwise
+# you could have left it undefined here and the shown default would be used.
+#
+# Windows users, remember to use paths with forward-slashes (or escaped
+# back-slashes.) Windows users should declare the full path to the openssl
+# binary here if it is not in their system PATH.
+
+#set_var EASYRSA_OPENSSL	"openssl"
+#
+# This sample is in Windows syntax -- edit it for your path if not using PATH:
+#set_var EASYRSA_OPENSSL	"C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
+
+# Edit this variable to point to your soon-to-be-created key directory.  By
+# default, this will be "$PWD/pki" (i.e. the "pki" subdirectory of the
+# directory you are currently in).
+#
+# WARNING: init-pki will do a rm -rf on this directory so make sure you define
+# it correctly! (Interactive mode will prompt before acting.)
+
+#set_var EASYRSA_PKI		"$PWD/pki"
+
+# Define directory for temporary subdirectories.
+
+#set_var EASYRSA_TEMP_DIR	"$EASYRSA_PKI"
+
+# Define X509 DN mode.
+# This is used to adjust what elements are included in the Subject field as the DN
+# (this is the "Distinguished Name.")
+# Note that in cn_only mode the Organizational fields further below are not used.
+#
+# Choices are:
+#   cn_only  - use just a CN value
+#   org      - use the "traditional" Country/Province/City/Org/OU/email/CN format
+
+#set_var EASYRSA_DN	"cn_only"
+
+# Organizational fields (used with "org" mode and ignored in "cn_only" mode.)
+# These are the default values for fields which will be placed in the
+# certificate.  Do not leave any of these fields blank, although interactively
+# you may omit any specific field by typing the "." symbol (not valid for
+# email.)
+
+# NOTE: The following characters are not supported
+#       in these "Organizational fields" by Easy-RSA:
+#       single quote (')
+#       back-tick (`)
+#       hash (#)
+#       ampersand (&)
+#       dollar sign ($)
+# Use them at your own risk!
+
+#set_var EASYRSA_REQ_COUNTRY	"US"
+#set_var EASYRSA_REQ_PROVINCE	"California"
+#set_var EASYRSA_REQ_CITY	"San Francisco"
+#set_var EASYRSA_REQ_ORG	"Copyleft Certificate Co"
+#set_var EASYRSA_REQ_EMAIL	"me@example.net"
+#set_var EASYRSA_REQ_OU		"My Organizational Unit"
+
+# Choose a size in bits for your keypairs. The recommended value is 2048.  Using
+# 2048-bit keys is considered more than sufficient for many years into the
+# future. Larger keysizes will slow down TLS negotiation and make key/DH param
+# generation take much longer. Values up to 4096 should be accepted by most
+# software. Only used when the crypto alg is rsa (see below.)
+
+#set_var EASYRSA_KEY_SIZE	2048
+
+# The default crypto mode is rsa; ec can enable elliptic curve support.
+# Note that not all software supports ECC, so use care when enabling it.
+# Choices for crypto alg are: (each in lower-case)
+#  * rsa
+#  * ec
+#  * ed
+
+#set_var EASYRSA_ALGO		rsa
+
+# Define the named curve, used in ec & ed modes:
+
+#set_var EASYRSA_CURVE		secp384r1
+
+# In how many days should the root CA key expire?
+
+set_var EASYRSA_CA_EXPIRE	365000
+
+# In how many days should certificates expire?
+
+set_var EASYRSA_CERT_EXPIRE	365000
+
+# How many days until the next CRL publish date?  Note that the CRL can still be
+# parsed after this timeframe passes. It is only used for an expected next
+# publication date.
+#set_var EASYRSA_CRL_DAYS	180
+
+# How many days before its expiration date a certificate is allowed to be
+# renewed?
+#set_var EASYRSA_CERT_RENEW	30
+
+# For fixed certificate start/end dates - Range 1..365
+# If set here then command line option is always in effect.
+# The day number 183 is either July 2nd or 3rd (leap-year)
+# Replace with your chosen day-of-year value:
+#set_var  EASYRSA_FIX_OFFSET 183
+
+# Random serial numbers by default, set to no for the old incremental serial numbers
+#
+#set_var EASYRSA_RAND_SN	"yes"
+
+# Support deprecated "Netscape" extensions? (choices "yes" or "no".) The default
+# is "no" to discourage use of deprecated extensions. If you require this
+# feature to use with --ns-cert-type, set this to "yes" here. This support
+# should be replaced with the more modern --remote-cert-tls feature.  If you do
+# not use --ns-cert-type in your configs, it is safe (and recommended) to leave
+# this defined to "no".  When set to "yes", server-signed certs get the
+# nsCertType=server attribute, and also get any NS_COMMENT defined below in the
+# nsComment field.
+
+#set_var EASYRSA_NS_SUPPORT	"no"
+
+# When NS_SUPPORT is set to "yes", this field is added as the nsComment field.
+# Set this blank to omit it. With NS_SUPPORT set to "no" this field is ignored.
+
+#set_var EASYRSA_NS_COMMENT	"Easy-RSA Generated Certificate"
+
+# A temp file used to stage cert extensions during signing. The default should
+# be fine for most users; however, some users might want an alternative under a
+# RAM-based FS, such as /dev/shm or /tmp on some systems.
+
+#set_var EASYRSA_TEMP_FILE	"$EASYRSA_PKI/extensions.temp"
+
+# !!
+# NOTE: ADVANCED OPTIONS BELOW THIS POINT
+# PLAY WITH THEM AT YOUR OWN RISK
+# !!
+
+# Broken shell command aliases: If you have a largely broken shell that is
+# missing any of these POSIX-required commands used by Easy-RSA, you will need
+# to define an alias to the proper path for the command.  The symptom will be
+# some form of a "command not found" error from your shell. This means your
+# shell is BROKEN, but you can hack around it here if you really need. These
+# shown values are not defaults: it is up to you to know what you are doing if
+# you touch these.
+#
+#alias awk="/alt/bin/awk"
+#alias cat="/alt/bin/cat"
+
+# X509 extensions directory:
+# If you want to customize the X509 extensions used, set the directory to look
+# for extensions here. Each cert type you sign must have a matching filename,
+# and an optional file named "COMMON" is included first when present. Note that
+# when undefined here, default behaviour is to look in $EASYRSA_PKI first, then
+# fallback to $EASYRSA for the "x509-types" dir.  You may override this
+# detection with an explicit dir here.
+#
+#set_var EASYRSA_EXT_DIR	"$EASYRSA/x509-types"
+
+# If you want to generate KDC certificates, you need to set the realm here.
+#set_var EASYRSA_KDC_REALM      "CHANGEME.EXAMPLE.COM"
+
+# OpenSSL config file:
+# If you need to use a specific openssl config file, you can reference it here.
+# Normally this file is auto-detected from a file named openssl-easyrsa.cnf from the
+# EASYRSA_PKI or EASYRSA dir (in that order.) NOTE that this file is Easy-RSA
+# specific and you cannot just use a standard config file, so this is an
+# advanced feature.
+
+#set_var EASYRSA_SSL_CONF	"$EASYRSA_PKI/openssl-easyrsa.cnf"
+
+# Default CN:
+# This is best left alone. Interactively you will set this manually, and BATCH
+# callers are expected to set this themselves.
+
+#set_var EASYRSA_REQ_CN		"ChangeMe"
+
+# Cryptographic digest to use.
+# Do not change this default unless you understand the security implications.
+# Valid choices include: md5, sha1, sha256, sha224, sha384, sha512
+
+#set_var EASYRSA_DIGEST		"sha256"
+
+# Batch mode. Leave this disabled unless you intend to call Easy-RSA explicitly
+# in batch mode without any user input, confirmation on dangerous operations,
+# or most output. Setting this to any non-blank string enables batch mode.
+
+#set_var EASYRSA_BATCH		""
diff --git a/ipad/example_ca/pki/vars.example b/ipad/example_ca/pki/vars.example
new file mode 100644
index 0000000..4eab5d0
--- /dev/null
+++ b/ipad/example_ca/pki/vars.example
@@ -0,0 +1,235 @@
+# Easy-RSA 3 parameter settings
+
+# NOTE: If you installed Easy-RSA from your package manager, do not edit
+# this file in place -- instead, you should copy the entire easy-rsa directory
+# to another location so future upgrades do not wipe out your changes.
+
+# HOW TO USE THIS FILE
+#
+# vars.example contains built-in examples to Easy-RSA settings. You MUST name
+# this file "vars" if you want it to be used as a configuration file. If you do
+# not, it WILL NOT be automatically read when you call easyrsa commands.
+#
+# It is not necessary to use this config file unless you wish to change
+# operational defaults. These defaults should be fine for many uses without the
+# need to copy and edit the "vars" file.
+#
+# All of the editable settings are shown commented and start with the command
+# "set_var" -- this means any set_var command that is uncommented has been
+# modified by the user. If you are happy with a default, there is no need to
+# define the value to its default.
+
+# NOTES FOR WINDOWS USERS
+#
+# Paths for Windows  *MUST* use forward slashes, or optionally double-escaped
+# backslashes (single forward slashes are recommended.) This means your path to
+# the openssl binary might look like this:
+# "C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
+
+# A little housekeeping: DO NOT EDIT THIS SECTION
+#
+# Easy-RSA 3.x does not source into the environment directly.
+# Complain if a user tries to do this:
+if [ -z "$EASYRSA_CALLER" ]; then
+	echo "You appear to be sourcing an Easy-RSA *vars* file." >&2
+	echo "This is no longer necessary and is disallowed. See the section called" >&2
+	echo "*How to use this file* near the top comments for more details." >&2
+	return 1
+fi
+
+# DO YOUR EDITS BELOW THIS POINT
+
+# This variable is used as the base location of configuration files needed by
+# easyrsa.  More specific variables for specific files (e.g., EASYRSA_SSL_CONF)
+# may override this default.
+#
+# The default value of this variable is the location of the easyrsa script
+# itself, which is also where the configuration files are located in the
+# easy-rsa tree.
+
+#set_var EASYRSA	"${0%/*}"
+
+# If your OpenSSL command is not in the system PATH, you will need to define the
+# path to it here. Normally this means a full path to the executable, otherwise
+# you could have left it undefined here and the shown default would be used.
+#
+# Windows users, remember to use paths with forward-slashes (or escaped
+# back-slashes.) Windows users should declare the full path to the openssl
+# binary here if it is not in their system PATH.
+
+#set_var EASYRSA_OPENSSL	"openssl"
+#
+# This sample is in Windows syntax -- edit it for your path if not using PATH:
+#set_var EASYRSA_OPENSSL	"C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
+
+# Edit this variable to point to your soon-to-be-created key directory.  By
+# default, this will be "$PWD/pki" (i.e. the "pki" subdirectory of the
+# directory you are currently in).
+#
+# WARNING: init-pki will do a rm -rf on this directory so make sure you define
+# it correctly! (Interactive mode will prompt before acting.)
+
+#set_var EASYRSA_PKI		"$PWD/pki"
+
+# Define directory for temporary subdirectories.
+
+#set_var EASYRSA_TEMP_DIR	"$EASYRSA_PKI"
+
+# Define X509 DN mode.
+# This is used to adjust what elements are included in the Subject field as the DN
+# (this is the "Distinguished Name.")
+# Note that in cn_only mode the Organizational fields further below are not used.
+#
+# Choices are:
+#   cn_only  - use just a CN value
+#   org      - use the "traditional" Country/Province/City/Org/OU/email/CN format
+
+#set_var EASYRSA_DN	"cn_only"
+
+# Organizational fields (used with "org" mode and ignored in "cn_only" mode.)
+# These are the default values for fields which will be placed in the
+# certificate.  Do not leave any of these fields blank, although interactively
+# you may omit any specific field by typing the "." symbol (not valid for
+# email.)
+
+# NOTE: The following characters are not supported
+#       in these "Organizational fields" by Easy-RSA:
+#       single quote (')
+#       back-tick (`)
+#       hash (#)
+#       ampersand (&)
+#       dollar sign ($)
+# Use them at your own risk!
+
+#set_var EASYRSA_REQ_COUNTRY	"US"
+#set_var EASYRSA_REQ_PROVINCE	"California"
+#set_var EASYRSA_REQ_CITY	"San Francisco"
+#set_var EASYRSA_REQ_ORG	"Copyleft Certificate Co"
+#set_var EASYRSA_REQ_EMAIL	"me@example.net"
+#set_var EASYRSA_REQ_OU		"My Organizational Unit"
+
+# Choose a size in bits for your keypairs. The recommended value is 2048.  Using
+# 2048-bit keys is considered more than sufficient for many years into the
+# future. Larger keysizes will slow down TLS negotiation and make key/DH param
+# generation take much longer. Values up to 4096 should be accepted by most
+# software. Only used when the crypto alg is rsa (see below.)
+
+#set_var EASYRSA_KEY_SIZE	2048
+
+# The default crypto mode is rsa; ec can enable elliptic curve support.
+# Note that not all software supports ECC, so use care when enabling it.
+# Choices for crypto alg are: (each in lower-case)
+#  * rsa
+#  * ec
+#  * ed
+
+#set_var EASYRSA_ALGO		rsa
+
+# Define the named curve, used in ec & ed modes:
+
+#set_var EASYRSA_CURVE		secp384r1
+
+# In how many days should the root CA key expire?
+
+#set_var EASYRSA_CA_EXPIRE	3650
+
+# In how many days should certificates expire?
+
+#set_var EASYRSA_CERT_EXPIRE	825
+
+# How many days until the next CRL publish date?  Note that the CRL can still be
+# parsed after this timeframe passes. It is only used for an expected next
+# publication date.
+#set_var EASYRSA_CRL_DAYS	180
+
+# How many days before its expiration date a certificate is allowed to be
+# renewed?
+#set_var EASYRSA_CERT_RENEW	30
+
+# For fixed certificate start/end dates - Range 1..365
+# If set here then command line option is always in effect.
+# The day number 183 is either July 2nd or 3rd (leap-year)
+# Replace with your chosen day-of-year value:
+#set_var  EASYRSA_FIX_OFFSET 183
+
+# Random serial numbers by default, set to no for the old incremental serial numbers
+#
+#set_var EASYRSA_RAND_SN	"yes"
+
+# Support deprecated "Netscape" extensions? (choices "yes" or "no".) The default
+# is "no" to discourage use of deprecated extensions. If you require this
+# feature to use with --ns-cert-type, set this to "yes" here. This support
+# should be replaced with the more modern --remote-cert-tls feature.  If you do
+# not use --ns-cert-type in your configs, it is safe (and recommended) to leave
+# this defined to "no".  When set to "yes", server-signed certs get the
+# nsCertType=server attribute, and also get any NS_COMMENT defined below in the
+# nsComment field.
+
+#set_var EASYRSA_NS_SUPPORT	"no"
+
+# When NS_SUPPORT is set to "yes", this field is added as the nsComment field.
+# Set this blank to omit it. With NS_SUPPORT set to "no" this field is ignored.
+
+#set_var EASYRSA_NS_COMMENT	"Easy-RSA Generated Certificate"
+
+# A temp file used to stage cert extensions during signing. The default should
+# be fine for most users; however, some users might want an alternative under a
+# RAM-based FS, such as /dev/shm or /tmp on some systems.
+
+#set_var EASYRSA_TEMP_FILE	"$EASYRSA_PKI/extensions.temp"
+
+# !!
+# NOTE: ADVANCED OPTIONS BELOW THIS POINT
+# PLAY WITH THEM AT YOUR OWN RISK
+# !!
+
+# Broken shell command aliases: If you have a largely broken shell that is
+# missing any of these POSIX-required commands used by Easy-RSA, you will need
+# to define an alias to the proper path for the command.  The symptom will be
+# some form of a "command not found" error from your shell. This means your
+# shell is BROKEN, but you can hack around it here if you really need. These
+# shown values are not defaults: it is up to you to know what you are doing if
+# you touch these.
+#
+#alias awk="/alt/bin/awk"
+#alias cat="/alt/bin/cat"
+
+# X509 extensions directory:
+# If you want to customize the X509 extensions used, set the directory to look
+# for extensions here. Each cert type you sign must have a matching filename,
+# and an optional file named "COMMON" is included first when present. Note that
+# when undefined here, default behaviour is to look in $EASYRSA_PKI first, then
+# fallback to $EASYRSA for the "x509-types" dir.  You may override this
+# detection with an explicit dir here.
+#
+#set_var EASYRSA_EXT_DIR	"$EASYRSA/x509-types"
+
+# If you want to generate KDC certificates, you need to set the realm here.
+#set_var EASYRSA_KDC_REALM      "CHANGEME.EXAMPLE.COM"
+
+# OpenSSL config file:
+# If you need to use a specific openssl config file, you can reference it here.
+# Normally this file is auto-detected from a file named openssl-easyrsa.cnf from the
+# EASYRSA_PKI or EASYRSA dir (in that order.) NOTE that this file is Easy-RSA
+# specific and you cannot just use a standard config file, so this is an
+# advanced feature.
+
+#set_var EASYRSA_SSL_CONF	"$EASYRSA_PKI/openssl-easyrsa.cnf"
+
+# Default CN:
+# This is best left alone. Interactively you will set this manually, and BATCH
+# callers are expected to set this themselves.
+
+#set_var EASYRSA_REQ_CN		"ChangeMe"
+
+# Cryptographic digest to use.
+# Do not change this default unless you understand the security implications.
+# Valid choices include: md5, sha1, sha256, sha224, sha384, sha512
+
+#set_var EASYRSA_DIGEST		"sha256"
+
+# Batch mode. Leave this disabled unless you intend to call Easy-RSA explicitly
+# in batch mode without any user input, confirmation on dangerous operations,
+# or most output. Setting this to any non-blank string enables batch mode.
+
+#set_var EASYRSA_BATCH		""
diff --git a/ipad/gen_links.sh b/ipad/gen_links.sh
new file mode 100755
index 0000000..130c68e
--- /dev/null
+++ b/ipad/gen_links.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+BASEDIR=../deps
+
+. ../gen_links.sh.inc
+
+DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
+FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Abstract_Socket/src
+FILES="Abstract_Socket.cc Abstract_Socket.hh "
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.HTTPmsg/src
+FILES="HTTPmsg_MessageLen.ttcn HTTPmsg_MessageLen_Function.cc HTTPmsg_PT.cc HTTPmsg_PT.hh HTTPmsg_PortType.ttcn "
+FILES+="HTTPmsg_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.IPL4asp/src
+FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn "
+FILES+="IPL4asp_discovery.cc IPL4asp_protocol_L234.hh"
+gen_links $DIR $FILES
+
+DIR=../library/euicc
+FILES="PEDefinitions.asn PKIX1Explicit88.asn PKIX1Implicit88.asn RSPDefinitions.asn SGP32Definitions.asn "
+FILES+="PKIX1Explicit88_Templates.ttcn PKIX1Explicit88_Types.ttcn PKIX1Implicit88_Templates.ttcn "
+FILES+="PKIX1Implicit88_Types.ttcn RSPDefinitions_Templates.ttcn RSPDefinitions_Types.ttcn "
+FILES+="SGP32Definitions_Templates.ttcn SGP32Definitions_Types.ttcn "
+FILES+="PKIX1Explicit88_EncDec.cc PKIX1Implicit88_EncDec.cc RSPDefinitions_EncDec.cc SGP32Definitions_EncDec.cc"
+gen_links $DIR $FILES
+
+DIR=../library
+FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc "
+FILES+="VPCD_Types.ttcn VPCD_CodecPort.ttcn VPCD_CodecPort_CtrlFunct.ttcn VPCD_CodecPort_CtrlFunctDef.cc "
+FILES+="VPCD_Adapter.ttcn HTTP_Server_Emulation.ttcn"
+gen_links $DIR $FILES
+
+ignore_pp_results
diff --git a/ipad/regen_makefile.sh b/ipad/regen_makefile.sh
new file mode 100755
index 0000000..9123e43
--- /dev/null
+++ b/ipad/regen_makefile.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+NAME=IPAd_Tests
+
+FILES="
+	*.ttcn
+	*.asn
+	Abstract_Socket.cc
+	HTTPmsg_MessageLen_Function.cc
+	HTTPmsg_PT.cc
+	IPL4asp_PT.cc
+	IPL4asp_discovery.cc
+	Native_FunctionDefs.cc
+	TCCConversion.cc
+	TCCInterface.cc
+	SGP32Definitions_EncDec.cc
+	RSPDefinitions_EncDec.cc
+	PKIX1Explicit88_EncDec.cc
+	PKIX1Implicit88_EncDec.cc
+	VPCD_CodecPort_CtrlFunctDef.cc
+"
+../regen-makefile.sh IPAd_Tests.ttcn $FILES
+
+# required for forkpty(3) used by PIPEasp
+sed -i -e '/^LINUX_LIBS/ s/$/ -lutil/' Makefile
diff --git a/regen-makefile.sh b/regen-makefile.sh
index 09088e0..813b212 100755
--- a/regen-makefile.sh
+++ b/regen-makefile.sh
@@ -41,12 +41,12 @@
 
 sed -i -e 's/# TTCN3_DIR = /TTCN3_DIR = \/usr/' Makefile
 sed -i -e 's/LDFLAGS = /LDFLAGS = -L \/usr\/lib\/titan/' Makefile
-sed -i -e 's/LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lsctp/' Makefile
+sed -i -e 's/LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lsctp -lssl/' Makefile
 #sed -i -e 's/TTCN3_LIB = ttcn3-parallel/TTCN3_LIB = ttcn3/' Makefile
 
 # The -DMAKEDEPEND_RUN is a workaround for Debian packaging issue,
 # see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=879816 for details
-sed -i -e 's/CPPFLAGS = -D$(PLATFORM)/CPPFLAGS = -D$(PLATFORM) -DMAKEDEPEND_RUN -DUSE_SCTP -DLKSCTP_MULTIHOMING_ENABLED/' Makefile
+sed -i -e 's/CPPFLAGS = -D$(PLATFORM)/CPPFLAGS = -D$(PLATFORM) -DMAKEDEPEND_RUN -DUSE_SCTP -DLKSCTP_MULTIHOMING_ENABLED -DAS_USE_SSL/' Makefile
 
 #remove -Wall from CXXFLAGS: we're not interested in generic warnings for autogenerated code cluttering the logs
 sed -i -e 's/-Wall//' Makefile