security: in tpm::BackEndOsx, unwrap the key before importing it

We use our own openssl-based routines for the PKCS#8 decoding/decryption,
as they support a much wider range of algorithms than macOS's Keychain.

Change-Id: Ia841e7681a47563c696d054d46fe523f427c99cb
Refs: #4450
diff --git a/tests/unit-tests/security/tpm/back-end.t.cpp b/tests/unit-tests/security/tpm/back-end.t.cpp
index 6880a0b..5512ebd 100644
--- a/tests/unit-tests/security/tpm/back-end.t.cpp
+++ b/tests/unit-tests/security/tpm/back-end.t.cpp
@@ -20,14 +20,16 @@
  */
 
 #include "security/tpm/back-end.hpp"
-#include "security/tpm/back-end-mem.hpp"
-#include "security/tpm/key-handle.hpp"
-#include "security/tpm/tpm.hpp"
-#include "security/transform.hpp"
-#include "security/transform/public-key.hpp"
-#include "security/transform/private-key.hpp"
+
 #include "encoding/buffer-stream.hpp"
 #include "security/pib/key.hpp"
+#include "security/tpm/key-handle.hpp"
+#include "security/tpm/tpm.hpp"
+#include "security/transform/bool-sink.hpp"
+#include "security/transform/buffer-source.hpp"
+#include "security/transform/private-key.hpp"
+#include "security/transform/public-key.hpp"
+#include "security/transform/verifier-filter.hpp"
 
 #include "back-end-wrapper-file.hpp"
 #include "back-end-wrapper-mem.hpp"
@@ -90,9 +92,8 @@
   T wrapper;
   BackEnd& tpm = wrapper.getTpm();
 
-  // create an rsa key
+  // create an RSA key
   Name identity("/Test/KeyName");
-
   unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
   Name keyName = key->getKeyName();
 
@@ -121,9 +122,8 @@
   T wrapper;
   BackEnd& tpm = wrapper.getTpm();
 
-  // create an rsa key
+  // create an RSA key
   Name identity("/Test/KeyName");
-
   unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
   Name keyName = key->getKeyName();
 
@@ -134,7 +134,6 @@
   pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
 
   ConstBufferPtr cipherText = pubKey.encrypt(content, sizeof(content));
-
   ConstBufferPtr plainText = key->decrypt(cipherText->data(), cipherText->size());
 
   BOOST_CHECK_EQUAL_COLLECTIONS(content, content + sizeof(content),
@@ -149,9 +148,8 @@
   T wrapper;
   BackEnd& tpm = wrapper.getTpm();
 
-  // create an ec key
+  // create an EC key
   Name identity("/Test/Ec/KeyName");
-
   unique_ptr<KeyHandle> key = tpm.createKey(identity, EcKeyParams());
   Name ecKeyName = key->getKeyName();
 
@@ -177,7 +175,7 @@
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(ImportExport, T, TestBackEnds)
 {
-  const std::string privateKeyPkcs1 =
+  const std::string privKeyPkcs1 =
     "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n"
     "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n"
     "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n"
@@ -203,42 +201,58 @@
     "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n"
     "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n"
     "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n";
+  const std::string password("password");
+  const std::string wrongPassword("wrong");
 
   T wrapper;
   BackEnd& tpm = wrapper.getTpm();
 
   Name keyName("/Test/KeyName/KEY/1");
   tpm.deleteKey(keyName);
-  BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+  BOOST_REQUIRE_EQUAL(tpm.hasKey(keyName), false);
 
   transform::PrivateKey sKey;
-  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.c_str()), privateKeyPkcs1.size());
-
-  std::string password("password");
+  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privKeyPkcs1.data()), privKeyPkcs1.size());
   OBufferStream os;
-  sKey.savePkcs8(os, password.c_str(), password.size());
-  ConstBufferPtr privateKeyBuffer = os.buf();
+  sKey.savePkcs8(os, password.data(), password.size());
+  auto pkcs8 = os.buf();
 
-  tpm.importKey(keyName, privateKeyBuffer->data(), privateKeyBuffer->size(), password.c_str(), password.size());
+  // import with wrong password
+  BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), wrongPassword.data(), wrongPassword.size()),
+                    BackEnd::Error);
+  BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+
+  // import with correct password
+  tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size());
   BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
-  BOOST_CHECK_THROW(tpm.importKey(keyName, privateKeyBuffer->data(), privateKeyBuffer->size(), password.c_str(), password.size()),
+
+  // import already present key
+  BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size()),
                     BackEnd::Error);
 
-  ConstBufferPtr exportedKey = tpm.exportKey(keyName, password.c_str(), password.size());
+  // test derivePublicKey with the imported key
+  auto keyHdl = tpm.getKeyHandle(keyName);
+  auto pubKey = keyHdl->derivePublicKey();
+  BOOST_CHECK(pubKey != nullptr);
+
+  // export
+  auto exportedKey = tpm.exportKey(keyName, password.data(), password.size());
   BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
 
   transform::PrivateKey sKey2;
-  sKey2.loadPkcs8(exportedKey->data(), exportedKey->size(), password.c_str(), password.size());
+  sKey2.loadPkcs8(exportedKey->data(), exportedKey->size(), password.data(), password.size());
   OBufferStream os2;
   sKey.savePkcs1Base64(os2);
-  ConstBufferPtr pkcs1Buffer = os2.buf();
+  auto pkcs1 = os2.buf();
 
-  BOOST_CHECK_EQUAL_COLLECTIONS(privateKeyPkcs1.begin(), privateKeyPkcs1.end(),
-                                pkcs1Buffer->begin(), pkcs1Buffer->end());
+  // verify that the exported key is identical to the key that was imported
+  BOOST_CHECK_EQUAL_COLLECTIONS(privKeyPkcs1.begin(), privKeyPkcs1.end(),
+                                pkcs1->begin(), pkcs1->end());
 
+  // export nonexistent key
   tpm.deleteKey(keyName);
   BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
-  BOOST_CHECK_THROW(tpm.exportKey(keyName, password.c_str(), password.size()), BackEnd::Error);
+  BOOST_CHECK_THROW(tpm.exportKey(keyName, password.data(), password.size()), BackEnd::Error);
 }
 
 BOOST_AUTO_TEST_CASE(RandomKeyId)