session tls: add support for configurable trusted cas 81/43681/13
authorFlorin Coras <[email protected]>
Wed, 10 Sep 2025 03:04:00 +0000 (23:04 -0400)
committerFlorin Coras <[email protected]>
Mon, 15 Sep 2025 02:46:00 +0000 (22:46 -0400)
Type: feature

Change-Id: Ic6727d03a369cf09d4397da6bff998d1811a6a61
Signed-off-by: Florin Coras <[email protected]>
12 files changed:
extras/hs-test/echo_test.go
extras/scripts/host-stack/tls-certs/generate-tls-ca.sh [new file with mode: 0644]
src/plugins/hs_apps/echo_client.c
src/plugins/hs_apps/echo_client.h
src/plugins/tlsopenssl/tls_openssl.c
src/vnet/session/application.h
src/vnet/session/application_crypto.c
src/vnet/session/application_crypto.h
src/vnet/session/transport_types.h
src/vnet/tls/tls.c
src/vnet/tls/tls.h
src/vnet/tls/tls_test.h

index 7353197..b9471ff 100644 (file)
@@ -8,7 +8,7 @@ import (
 )
 
 func init() {
-       RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest, EchoBuiltinRoundtripTest, EchoBuiltinTestbytesTest, EchoBuiltinPeriodicReportTest, EchoBuiltinPeriodicReportTotalTest)
+       RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest, EchoBuiltinRoundtripTest, EchoBuiltinTestbytesTest, EchoBuiltinPeriodicReportTest, EchoBuiltinPeriodicReportTotalTest, TlsSingleConnectionTest)
        RegisterVethMWTests(TcpWithLossTest)
        RegisterSoloVeth6Tests(TcpWithLoss6Test)
 }
@@ -300,3 +300,19 @@ func TcpWithLoss6Test(s *Veths6Suite) {
                s.AssertGreaterEqual(withLoss, uint64(float64(baseline)*0.15))
        }
 }
+
+func TlsSingleConnectionTest(s *VethsSuite) {
+       serverVpp := s.Containers.ServerVpp.VppInstance
+
+       serverVpp.Vppctl("test echo server " +
+               " uri tls://" + s.Interfaces.Server.Ip4AddressString() + "/" + s.Ports.Port1)
+
+       clientVpp := s.Containers.ClientVpp.VppInstance
+
+       o := clientVpp.Vppctl("test echo client uri tls://%s:%s verbose run-time 5", s.Interfaces.Server.Ip4AddressString(), s.Ports.Port1)
+
+       s.Log(o)
+       throughput, err := s.ParseEchoClientTransfer(o)
+       s.AssertNil(err)
+       s.AssertGreaterThan(throughput, uint64(0))
+}
diff --git a/extras/scripts/host-stack/tls-certs/generate-tls-ca.sh b/extras/scripts/host-stack/tls-certs/generate-tls-ca.sh
new file mode 100644 (file)
index 0000000..efecadb
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/bash
+
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) 2025 Cisco Systems, Inc.
+
+# Generate ca private key and certificate
+openssl genrsa -out ca-key.pem 2048
+openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 3650 -subj "/C=US/ST=CA/L=San Jose/O=Cisco/CN=Fd.io Test Root CA"
+
+# Generate intermediate CA key
+openssl genrsa -out intermediate-key.pem 2048
+
+# Create intermediate CA certificate request
+openssl req -new -key intermediate-key.pem -out intermediate.csr -subj "/C=US/ST=CA/L=San Jose/O=Cisco/CN=Fd.io Test Intermediate CA"
+
+# Sign intermediate certificate with root CA
+openssl x509 -req -in intermediate.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out intermediate-cert.pem -days 3650
+
+# Create a chain file (root + intermediate)
+cat ca-cert.pem intermediate-cert.pem > ca-chain.pem
+
+# Create CRL configuration
+cat > crl.conf << EOF
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+database = index.txt
+serial = serial
+crlnumber = crlnumber
+default_crl_days = 30
+default_md = sha256
+EOF
+
+# Initialize files
+touch index.txt
+echo 01 > serial
+echo 01 > crlnumber
+
+# Generate empty CRL
+openssl ca -config crl.conf -gencrl -keyfile ca-key.pem -cert ca-cert.pem -out ca-crl.pem
\ No newline at end of file
index 57f888e..cae7a73 100644 (file)
@@ -1036,6 +1036,7 @@ static clib_error_t *
 ec_attach ()
 {
   vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair;
+  app_ca_trust_add_args_t _ca_args = {}, *ca_args = &_ca_args;
   ec_main_t *ecm = &ec_main;
   vnet_app_attach_args_t _a, *a = &_a;
   u32 prealloc_fifos;
@@ -1083,6 +1084,13 @@ ec_attach ()
   vnet_app_add_cert_key_pair (ck_pair);
   ecm->ckpair_index = ck_pair->index;
 
+  vec_validate (ca_args->ca_chain, test_ca_chain_rsa_len - 1);
+  clib_memcpy (ca_args->ca_chain, test_ca_chain_rsa, test_ca_chain_rsa_len);
+  vec_validate (ca_args->crl, test_ca_crl_len - 1);
+  clib_memcpy (ca_args->crl, test_ca_crl, test_ca_crl_len);
+  app_crypto_add_ca_trust (ecm->app_index, ca_args);
+  ecm->ca_trust_index = ca_args->index;
+
   ecm->test_client_attached = 1;
 
   return 0;
@@ -1147,6 +1155,7 @@ ec_connect_rpc (void *args)
            &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_CRYPTO,
            sizeof (transport_endpt_crypto_cfg_t));
          ext_cfg->crypto.ckpair_index = ecm->ckpair_index;
+         ext_cfg->crypto.ca_trust_index = ecm->ca_trust_index;
        }
 
       rv = vnet_connect (a);
index c88ceb7..17d41c5 100644 (file)
@@ -119,6 +119,7 @@ typedef struct
   u32 no_copy;                         /**< Don't memcpy data to tx fifo */
   u32 quic_streams;                    /**< QUIC streams per connection */
   u32 ckpair_index;                    /**< Cert key pair for tls/quic */
+  u32 ca_trust_index;                  /**< CA trust chain to be used */
   u64 attach_flags;                    /**< App attach flags */
   u8 *appns_id;                                /**< App namespaces id */
   u64 appns_secret;                    /**< App namespace secret */
index 9648d6f..12a4335 100644 (file)
@@ -740,10 +740,6 @@ openssl_set_ckpair (SSL *ssl, u32 ckpair_index,
   app_cert_key_pair_t *ckpair;
   app_certkey_int_ctx_t *cki;
 
-  /* Configure a ckpair index only if non-default/test provided */
-  if (ckpair_index == 0)
-    return 0;
-
   ckpair = app_cert_key_pair_get_if_valid (ckpair_index);
   if (!ckpair)
     return -1;
@@ -772,6 +768,121 @@ openssl_set_ckpair (SSL *ssl, u32 ckpair_index,
   return 0;
 }
 
+static void
+openssl_cleanup_ca_trust_int_ctx (app_crypto_ca_trust_int_ctx_t *cki)
+{
+  X509_STORE_free (cki->ca_store);
+}
+
+static app_crypto_ca_trust_int_ctx_t *
+openssl_init_int_ca_trust_ctx (app_crypto_ca_trust_t *ca_trust,
+                              clib_thread_index_t thread_index)
+{
+  app_crypto_ca_trust_int_ctx_t *cti = 0;
+  X509_STORE *store;
+  X509 *cert;
+  BIO *bio;
+
+  cti = app_crypto_alloc_int_ca_trust (ca_trust, thread_index);
+  store = X509_STORE_new ();
+  if (!store)
+    {
+      clib_warning ("unable to create x509 store");
+      return 0;
+    }
+
+  /* Create BIO from the single PEM string containing multiple certificates */
+  bio = BIO_new (BIO_s_mem ());
+  BIO_write (bio, ca_trust->ca_chain, vec_len (ca_trust->ca_chain));
+
+  /* Read all certificates from the PEM string */
+  while ((cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL)) != NULL)
+    {
+      if (X509_STORE_add_cert (store, cert) != 1)
+       {
+         char buf[512];
+         ERR_error_string (ERR_get_error (), buf);
+         clib_warning ("unable to add certificate to store: %s", buf);
+         X509_free (cert);
+         BIO_free (bio);
+         X509_STORE_free (store);
+         return 0;
+       }
+      X509_free (cert);
+    }
+
+  BIO_free (bio);
+
+  /* Parse and add CRL if present */
+  if (ca_trust->crl && vec_len (ca_trust->crl) > 0)
+    {
+      X509_CRL *crl;
+      bio = BIO_new (BIO_s_mem ());
+      BIO_write (bio, ca_trust->crl, vec_len (ca_trust->crl));
+
+      /* Read all CRLs from the PEM string */
+      while ((crl = PEM_read_bio_X509_CRL (bio, NULL, NULL, NULL)) != NULL)
+       {
+         if (X509_STORE_add_crl (store, crl) != 1)
+           {
+             char buf[512];
+             ERR_error_string (ERR_get_error (), buf);
+             clib_warning ("unable to add CRL to store: %s", buf);
+             X509_CRL_free (crl);
+             BIO_free (bio);
+             X509_STORE_free (store);
+             return 0;
+           }
+         X509_CRL_free (crl);
+       }
+
+      BIO_free (bio);
+
+      /* Enable CRL checking */
+      X509_STORE_set_flags (store,
+                           X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+    }
+
+  cti->ca_store = store;
+  cti->cleanup_cb = openssl_cleanup_ca_trust_int_ctx;
+
+  return cti;
+}
+
+static int
+openssl_set_ca_trust (tls_ctx_t *ctx)
+{
+  openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
+  app_crypto_ca_trust_int_ctx_t *cti;
+  app_crypto_ca_trust_t *ca_trust;
+
+  ca_trust = app_crypto_get_wrk_ca_trust (ctx->parent_app_wrk_index,
+                                         ctx->ca_trust_index);
+  if (!ca_trust)
+    return -1;
+
+  cti = app_crypto_get_int_ca_trust (ca_trust, ctx->c_thread_index);
+  if (!cti || !cti->ca_store)
+    {
+      cti = openssl_init_int_ca_trust_ctx (ca_trust, ctx->c_thread_index);
+      if (!cti)
+       {
+         clib_warning ("unable to initialize certificate/key pair");
+         return -1;
+       }
+    }
+
+  if (SSL_set1_verify_cert_store (oc->ssl, cti->ca_store) != 1)
+    {
+      char buf[512];
+      ERR_error_string (ERR_get_error (), buf);
+      clib_warning ("Failed to set CA trust store: %s", buf);
+      return -1;
+    }
+
+  return 0;
+}
+
 static int
 openssl_init_client_ctx (clib_thread_index_t thread_index,
                         transport_proto_t proto)
@@ -942,9 +1053,23 @@ openssl_ctx_init_client (tls_ctx_t *ctx)
        }
     }
 
-  if (openssl_set_ckpair (oc->ssl, ctx->ckpair_index, ctx->c_thread_index))
+  /* Configure a ckpair index only if non-default/test provided */
+  if (ctx->ckpair_index)
     {
-      TLS_DBG (1, "Couldn't set client certificate-key pair");
+      if (openssl_set_ckpair (oc->ssl, ctx->ckpair_index, ctx->c_thread_index))
+       {
+         TLS_DBG (1, "Couldn't set client certificate-key pair");
+       }
+    }
+
+  /* Configure trusted ca only if non-default*/
+  if (ctx->ca_trust_index)
+    {
+      if (openssl_set_ca_trust (ctx))
+       {
+         TLS_DBG (1, "Couldn't set trusted CA");
+         return -1;
+       }
     }
 
   if (ctx->tls_type == TRANSPORT_PROTO_TLS)
index b16e42d..2876e53 100644 (file)
@@ -180,6 +180,14 @@ app_crypto_wrk_get (application_t *app, clib_thread_index_t thread_index)
   return vec_elt_at_index (app->crypto_ctx.wrk, thread_index);
 }
 
+static inline app_crypto_ca_trust_t *
+app_get_crypto_ca_trust (application_t *app, u32 ca_trust_index)
+{
+  if (pool_is_free_index (app->crypto_ctx.ca_trust_stores, ca_trust_index))
+    return 0;
+  return pool_elt_at_index (app->crypto_ctx.ca_trust_stores, ca_trust_index);
+}
+
 typedef struct app_rx_mq_handle_
 {
   union
index c8d2667..e551895 100644 (file)
@@ -21,6 +21,8 @@ app_cert_key_pair_alloc ()
   pool_get (app_crypto_main.cert_key_pair_store, ckpair);
   clib_memset (ckpair, 0, sizeof (*ckpair));
   ckpair->cert_key_index = ckpair - app_crypto_main.cert_key_pair_store;
+  /* Avoid need for locks when used by workers */
+  vec_validate (ckpair->cki, vlib_num_workers ());
   return ckpair;
 }
 
@@ -45,6 +47,65 @@ app_cert_key_pair_get_default ()
   return app_cert_key_pair_get (0);
 }
 
+static app_crypto_ca_trust_t *
+app_crypto_alloc_ca_trust (application_t *app)
+{
+  app_crypto_ca_trust_t *ca_trust;
+
+  /* first element not used */
+  if (!pool_elts (app->crypto_ctx.ca_trust_stores))
+    pool_get_zero (app->crypto_ctx.ca_trust_stores, ca_trust);
+  pool_get_zero (app->crypto_ctx.ca_trust_stores, ca_trust);
+  ca_trust->ca_trust_index = ca_trust - app->crypto_ctx.ca_trust_stores;
+  /* Avoid need for locks when used by workers */
+  vec_validate (ca_trust->cti, vlib_num_workers ());
+
+  return ca_trust;
+}
+
+int
+app_crypto_add_ca_trust (u32 app_index, app_ca_trust_add_args_t *args)
+{
+  application_t *app;
+  app_crypto_ca_trust_t *ca_trust;
+
+  app = application_get (app_index);
+  ca_trust = app_crypto_alloc_ca_trust (app);
+  ca_trust->ca_chain = args->ca_chain;
+  ca_trust->crl = args->crl;
+  args->index = ca_trust->ca_trust_index;
+
+  return 0;
+}
+
+app_crypto_ca_trust_t *
+app_crypto_get_wrk_ca_trust (u32 app_wrk_index, u32 ca_trust_index)
+{
+  app_worker_t *app_wrk;
+  application_t *app;
+
+  app_wrk = app_worker_get (app_wrk_index);
+  app = application_get (app_wrk->app_index);
+
+  return app_get_crypto_ca_trust (app, ca_trust_index);
+}
+
+app_crypto_ca_trust_int_ctx_t *
+app_crypto_alloc_int_ca_trust (app_crypto_ca_trust_t *ct,
+                              clib_thread_index_t thread_index)
+{
+  return vec_elt_at_index (ct->cti, thread_index);
+}
+
+app_crypto_ca_trust_int_ctx_t *
+app_crypto_get_int_ca_trust (app_crypto_ca_trust_t *ct,
+                            clib_thread_index_t thread_index)
+{
+  if (vec_len (ct->cti) <= thread_index)
+    return 0;
+  return vec_elt_at_index (ct->cti, thread_index);
+}
+
 int
 vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t *a)
 {
@@ -185,11 +246,37 @@ app_crypto_ctx_init (app_crypto_ctx_t *crypto_ctx)
   vec_validate (crypto_ctx->wrk, vlib_num_workers ());
 }
 
+static void
+app_crypto_ca_stores_cleanup (app_crypto_ca_trust_t *ca_stores)
+{
+  app_crypto_ca_trust_int_ctx_t *cti;
+  app_crypto_ca_trust_t *ct;
+
+  pool_foreach (ct, ca_stores)
+    {
+      vec_foreach (cti, ct->cti)
+       {
+         if (cti->cleanup_cb)
+           (cti->cleanup_cb) (cti);
+         cti->ca_store = 0;
+       }
+      vec_free (ct->cti);
+      vec_free (ct->ca_chain);
+      vec_free (ct->crl);
+    }
+}
+
 void
 app_crypto_ctx_free (app_crypto_ctx_t *crypto_ctx)
 {
   app_crypto_wrk_t *crypto_wrk;
 
+  if (crypto_ctx->ca_trust_stores)
+    {
+      app_crypto_ca_stores_cleanup (crypto_ctx->ca_trust_stores);
+      pool_free (crypto_ctx->ca_trust_stores);
+    }
+
   vec_foreach (crypto_wrk, crypto_ctx->wrk)
     pool_free (crypto_wrk->reqs);
   vec_free (crypto_ctx->wrk);
index 743c359..278d2d3 100644 (file)
@@ -21,13 +21,32 @@ typedef struct app_certkey_int_
 
 typedef struct certificate_
 {
-  u32 *app_interests; /* vec of application index asking for deletion cb */
-  u32 cert_key_index; /* index in cert & key pool */
-  u8 *key;
-  u8 *cert;
+  u32 *app_interests; /**< vec of application index asking for deletion cb */
+  u32 cert_key_index; /**< index in cert & key pool */
+  u8 *key;           /**< PEM encoded key */
+  u8 *cert;          /**< PEM encoded cert */
   app_certkey_int_ctx_t *cki; /**< per-thread internal cert/key */
 } app_cert_key_pair_t;
 
+struct app_crypto_ca_trust_int_ctx_;
+
+typedef void (*app_crypto_ca_cleanup_it_ctx_fn) (
+  struct app_crypto_ca_trust_int_ctx_ *cti);
+
+typedef struct app_crypto_ca_trust_int_ctx_
+{
+  void *ca_store; /**< trusted ca, possible format X509_STORE */
+  app_crypto_ca_cleanup_it_ctx_fn cleanup_cb; /**< cleanup callback */
+} app_crypto_ca_trust_int_ctx_t;
+
+typedef struct app_crypto_ca_trust_
+{
+  u8 *ca_chain;                              /**< PEM encoded CA chain */
+  u8 *crl;                           /**< PEM encoded CRL */
+  u32 ca_trust_index;                /**< index in the CA trust pool */
+  app_crypto_ca_trust_int_ctx_t *cti; /**< per-thread internal ca trust */
+} app_crypto_ca_trust_t;
+
 typedef enum crypto_engine_type_
 {
   CRYPTO_ENGINE_NONE,
@@ -47,6 +66,13 @@ typedef struct _vnet_app_add_cert_key_pair_args_
   u32 index;
 } vnet_app_add_cert_key_pair_args_t;
 
+typedef struct app_ca_trust_add_args_
+{
+  u8 *ca_chain;
+  u8 *crl;
+  u32 index;
+} app_ca_trust_add_args_t;
+
 typedef struct crypto_ctx_
 {
   u32 ctx_index;     /**< index in crypto context pool */
@@ -133,6 +159,7 @@ typedef struct app_crypto_wrk_
 typedef struct app_crypto_ctx_
 {
   app_crypto_wrk_t *wrk;
+  app_crypto_ca_trust_t *ca_trust_stores;
 } app_crypto_ctx_t;
 
 void app_crypto_ctx_init (app_crypto_ctx_t *crypto_ctx);
@@ -146,6 +173,16 @@ app_cert_key_pair_t *app_cert_key_pair_get (u32 index);
 app_cert_key_pair_t *app_cert_key_pair_get_if_valid (u32 index);
 app_cert_key_pair_t *app_cert_key_pair_get_default ();
 
+int app_crypto_add_ca_trust (u32 app_index, app_ca_trust_add_args_t *args);
+app_crypto_ca_trust_t *app_crypto_get_wrk_ca_trust (u32 app_wrk_index,
+                                                   u32 ca_trust_index);
+app_crypto_ca_trust_int_ctx_t *
+app_crypto_alloc_int_ca_trust (app_crypto_ca_trust_t *ct,
+                              clib_thread_index_t thread_index);
+app_crypto_ca_trust_int_ctx_t *
+app_crypto_get_int_ca_trust (app_crypto_ca_trust_t *ct,
+                            clib_thread_index_t thread_index);
+
 int vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t *a);
 int vnet_app_add_cert_key_interest (u32 index, u32 app_index);
 int vnet_app_del_cert_key_pair (u32 index);
@@ -163,8 +200,6 @@ static inline app_certkey_int_ctx_t *
 app_certkey_alloc_int_ctx (app_cert_key_pair_t *ck,
                           clib_thread_index_t thread_index)
 {
-  if (!ck->cki)
-    vec_validate (ck->cki, vlib_num_workers () + 1);
   return vec_elt_at_index (ck->cki, thread_index);
 }
 
index d45c376..a2b4bba 100644 (file)
@@ -311,9 +311,10 @@ typedef enum tls_verify_cfg_
 
 typedef struct transport_endpt_crypto_cfg_
 {
-  u32 ckpair_index;  /**< index of ck pair in application crypto layer */
-  u8 alpn_protos[4]; /**< ordered by preference for server */
-  u8 crypto_engine;  /**< crypto engine requested */
+  u32 ckpair_index;   /**< index of ck pair in application crypto layer */
+  u32 ca_trust_index; /**< index of ca trust in application crypto layer */
+  u8 alpn_protos[4];  /**< ordered by preference for server */
+  u8 crypto_engine;   /**< crypto engine requested */
   tls_verify_cfg_t verify_cfg; /**< cert verification mode */
   u8 hostname[256];           /**< full domain len is 255 as per rfc 3986 */
 } transport_endpt_crypto_cfg_t;
index b3c39f1..3cdc4c1 100644 (file)
@@ -715,6 +715,7 @@ tls_connect (transport_endpoint_cfg_t * tep)
   ctx->tcp_is_ip4 = sep->is_ip4;
   ctx->tls_type = sep->transport_proto;
   ctx->ckpair_index = ccfg->ckpair_index;
+  ctx->ca_trust_index = ccfg->ca_trust_index;
   ctx->c_proto = TRANSPORT_PROTO_TLS;
   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
   if (ccfg->hostname[0])
index 768e87b..c575fc7 100644 (file)
@@ -123,6 +123,7 @@ typedef struct tls_ctx_
   tls_conn_flags_t flags;
   u8 *srv_hostname;
   u32 ckpair_index;
+  u32 ca_trust_index;
   transport_proto_t tls_type;
   u8 *alpn_list;
   tls_alpn_proto_t alpn_selected;
index ad9c8ba..d682110 100644 (file)
@@ -76,6 +76,69 @@ static const char test_srv_key_rsa[] =
   "oEjPLVNtx8SOj/M4rhaPT3I=\r\n" "-----END PRIVATE KEY-----\r\n";
 static const u32 test_srv_key_rsa_len = sizeof (test_srv_key_rsa);
 
+/*
+ * TLS test CA to used for testing only
+ */
+static const char test_ca_chain_rsa[] =
+  "-----BEGIN CERTIFICATE-----\r\n"
+  "MIIDlTCCAn2gAwIBAgIUMZO3VeOey8A1oB6tp8gx4FXw62gwDQYJKoZIhvcNAQEL\r\n"
+  "BQAwWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQHDAhTYW4gSm9z\r\n"
+  "ZTEOMAwGA1UECgwFQ2lzY28xGzAZBgNVBAMMEkZkLmlvIFRlc3QgUm9vdCBDQTAe\r\n"
+  "Fw0yNTA5MTEwNjI1MTVaFw0zNTA5MDkwNjI1MTVaMFoxCzAJBgNVBAYTAlVTMQsw\r\n"
+  "CQYDVQQIDAJDQTERMA8GA1UEBwwIU2FuIEpvc2UxDjAMBgNVBAoMBUNpc2NvMRsw\r\n"
+  "GQYDVQQDDBJGZC5pbyBUZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\r\n"
+  "DwAwggEKAoIBAQDHiQEu2NeUzmhTuPAFoJdRs8EyWmLUbu1HCaBGrmRUqLoPbAms\r\n"
+  "GSowFSHJSE/jQ8d84dMZAzHQxybEzlg14eM6JgpMkzUITZj0IhZB58FiPqEOK7hT\r\n"
+  "pV9nKGJkWJMm9srHo5oUwx3L8L3JZu1uaRj00c9GyD5ApvF+vmHnZv88XidR1f+m\r\n"
+  "yIiuw6Pkb2GrbdGaX08WdUXVv5PrRqFAJaqXMgXCijRucbpXRBYwX1oPdrE7U+Ho\r\n"
+  "uIVA6XyTp+3HwkGsV64oH3WTTIDZksgZMVQq8o9CF9eEXRjoPa5PtDRPs9LyGBid\r\n"
+  "tdrHwB+++HdQU2dNbdS08KdMD/UFg4MAJpqvAgMBAAGjUzBRMB0GA1UdDgQWBBRy\r\n"
+  "XX+uRpAbb8FB70rXIxWHbkAt6jAfBgNVHSMEGDAWgBRyXX+uRpAbb8FB70rXIxWH\r\n"
+  "bkAt6jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAEv8yK7WGJ\r\n"
+  "Zinpi5w736eCaCoSJDnIFZlQ6MHI5Jn9SSKudsGaEBSvicGcD5dkJLIdMEqFBJ6/\r\n"
+  "bm8XfiDa9HUR87LfWA0qVO7hiQ0Xvvf9e1lOM/+e0JTcS2nqNajFBzuWD5OA8s8w\r\n"
+  "6BdOerk7IxMw2cpwDmJ+7Nsc0yd7XRgUSyooyo3YcsvhPCg0v/pmGSbVu0nhG7sE\r\n"
+  "M8DaebCc7JVpsKVfY676IwDQejte35H3jzbMOOLlHKaXDhU9Xf3eEDEfSYyM7shK\r\n"
+  "5QHEw0X14TSO29Y832m3rwAizZOwLy0CpVPjIVju4qkGAzEdk4kg06NQHYlHhDA1\r\n"
+  "0WNb4tBLb2N2\r\n"
+  "-----END CERTIFICATE-----\r\n"
+  "-----BEGIN CERTIFICATE-----\r\n"
+  "MIIDQzCCAisCFCfFYwTSvtLo+7AhR/fDRFffGmTaMA0GCSqGSIb3DQEBCwUAMFox\r\n"
+  "CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIU2FuIEpvc2UxDjAM\r\n"
+  "BgNVBAoMBUNpc2NvMRswGQYDVQQDDBJGZC5pbyBUZXN0IFJvb3QgQ0EwHhcNMjUw\r\n"
+  "OTExMDYyNzM5WhcNMzUwOTA5MDYyNzM5WjBiMQswCQYDVQQGEwJVUzELMAkGA1UE\r\n"
+  "CAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQKDAVDaXNjbzEjMCEGA1UE\r\n"
+  "AwwaRmQuaW8gVGVzdCBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\r\n"
+  "A4IBDwAwggEKAoIBAQCrfov0g9Ls1zV0c5tp6oxf+zGIgrd6Jg45KxKZwrRA0EN5\r\n"
+  "kHtyso1OZdQbJETUIj0cs7qLenjCO4r6c0T7cA5a/VqJUgvFhH4N0oMiH5wcL9yZ\r\n"
+  "m1SX5zdz7PhwBAzCyMkbvrz95243D5KLbYAMizMGx0KyHXzrqL6M+Tr1xYs2kjNj\r\n"
+  "6zq2I04FXbyJnwIj+D7yQ7fyvbKiZNWNstbcDhS3DvyHbAsaCv2NiB5Gelp0iEP3\r\n"
+  "HI6D1WEJiEWa8rgOtAP42WKFbjF1N7UbFUINpYvzckBIH0h7x9f/+Ocs2R4KNQLu\r\n"
+  "r8Lj+NGSQkb+KkRwPF9rOy94IViUyp/yfz1B2l4ZAgMBAAEwDQYJKoZIhvcNAQEL\r\n"
+  "BQADggEBAD6Dw0Kv+nnu6I4lmj50zTsArAwlQDfy+pwD3QBByvUVIkGOwWpKrMUC\r\n"
+  "rAb4sNi3LYoAaGCjrFgcArpuAgireirU0ilfovDipwiXKUGLtTzOL0ZqCqi4wynR\r\n"
+  "7UYh3eaHPQ0LkH+WFrrLCfRu/3TngQHDEiKaL7aug7/q/ZXQ88hTWobws7oHBnKc\r\n"
+  "m5ykWmmD2JRRKu7Mg5dyzlqlI2AkMnQMrX0voTR/KE16qhbMyovNSsH+PuwvhbVl\r\n"
+  "vFTyeC/o7Rm+U+JkaFA/wyP/6gzfT1XFSsNY2WAWNzrsWtCf2gVWNxPvGHg6G0Yz\r\n"
+  "TiCarwFKR1qNpR+qibWDni6b2gRZcs0=\r\n"
+  "-----END CERTIFICATE-----\r\n";
+static const u32 test_ca_chain_rsa_len = sizeof (test_ca_chain_rsa);
+
+static const char test_ca_crl[] =
+  "-----BEGIN X509 CRL-----\r\n"
+  "MIIBszCBnAIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzELMAkGA1UE\r\n"
+  "CAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQKDAVDaXNjbzEbMBkGA1UE\r\n"
+  "AwwSRmQuaW8gVGVzdCBSb290IENBFw0yNTA5MTEwNjI4NDhaFw0yNTEwMTEwNjI4\r\n"
+  "NDhaoA4wDDAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAe8YmRs+VOw3M\r\n"
+  "xofJCI40bt6La/1knBd3KSM91pSBAfmZReztoHHxiM0ymViv6ZnKIymn+F1JhhqU\r\n"
+  "OLV7S28oCVkpB2O1zsCv8FyfAegLrvu/ipFGsemRos+YxXtC9mam8WuGFRMFXzjB\r\n"
+  "PBoyZsaWspXoHlMpUqPBfagjciiJdyxCWoCwd8jVA9swgG6dxCLUup98du88ikgA\r\n"
+  "huoi90QF+/qztjwoE8rngGWKdR7Re6qYrZIwGgLupxA3pGonCsTRwPKE/qrbNhMi\r\n"
+  "Pqmuu8zyeaqq/EoKNmuE22AeIn2BsYslJKMKOwQ022CAAtIDjB0boBI6+IeFrStJ\r\n"
+  "41u0xwNSyA==\r\n"
+  "-----END X509 CRL-----\r\n";
+static const u32 test_ca_crl_len = sizeof (test_ca_crl);
+
 #endif /* SRC_VNET_TLS_TLS_TEST_H_ */
 
 /*