[cpp-xmltooling] branch master updated: SSPCPP-775 - Client-side session storage
Scott Cantor
cantor.2 at osu.edu
Wed Mar 7 13:59:56 EST 2018
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository cpp-xmltooling.
View the commit online:
http://git.shibboleth.net/view/?p=cpp-xmltooling.git;a=commit;h=d05ef36e2e4906109a753567a7eaf59c5d77b437
The following commit(s) were added to refs/heads/master by this push:
new d05ef36 SSPCPP-775 - Client-side session storage
d05ef36 is described below
commit d05ef36e2e4906109a753567a7eaf59c5d77b437
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Mar 7 13:58:43 2018 -0500
SSPCPP-775 - Client-side session storage
https://issues.shibboleth.net/jira/browse/SSPCPP-775
Encryption added to DataSealer.
---
xmltooling/security/DataSealer.h | 4 +-
xmltooling/security/impl/DataSealer.cpp | 179 ++++++++++++++++++++++++++------
xmltoolingtest/DataSealerTest.h | 6 +-
3 files changed, 157 insertions(+), 32 deletions(-)
diff --git a/xmltooling/security/DataSealer.h b/xmltooling/security/DataSealer.h
index 47eccf7..775b566 100644
--- a/xmltooling/security/DataSealer.h
+++ b/xmltooling/security/DataSealer.h
@@ -32,7 +32,7 @@
#include <ctime>
#include <string>
-#include <xsec/enc/XSECCryptoSymmetricKey.hpp>
+class XSECCryptoSymmetricKey;
namespace xmltooling {
@@ -120,7 +120,7 @@ namespace xmltooling {
virtual std::string unwrap(const char* s) const;
private:
- const DataSealerKeyStrategy* m_strategy;
+ const DataSealerKeyStrategy* m_strategy;
};
};
diff --git a/xmltooling/security/impl/DataSealer.cpp b/xmltooling/security/impl/DataSealer.cpp
index 16ed0c1..2df326a 100644
--- a/xmltooling/security/impl/DataSealer.cpp
+++ b/xmltooling/security/impl/DataSealer.cpp
@@ -33,9 +33,19 @@
#include <sstream>
#include <xercesc/util/Base64.hpp>
#include <xercesc/util/XMLDateTime.hpp>
+#include <xsec/framework/XSECAlgorithmHandler.hpp>
+#include <xsec/framework/XSECAlgorithmMapper.hpp>
+#include <xsec/framework/XSECEnv.hpp>
+#include <xsec/framework/XSECException.hpp>
+#include <xsec/transformers/TXFMChain.hpp>
+#include <xsec/transformers/TXFMBase64.hpp>
+#include <xsec/transformers/TXFMSB.hpp>
+#include <xsec/xenc/XENCEncryptionMethod.hpp>
using namespace xmltooling;
using xercesc::Base64;
+using xercesc::DOMDocument;
+using xercesc::Janitor;
using xercesc::XMLDateTime;
using namespace std;
@@ -69,10 +79,34 @@ DataSealer::~DataSealer()
{
}
-// TODO: add encryption ;-)
-
string DataSealer::wrap(const char* s, time_t exp) const
{
+ // Get default key to use.
+ pair<string,const XSECCryptoSymmetricKey*> defaultKey = m_strategy->getDefaultKey();
+
+ const XMLCh* algorithm = nullptr;
+ switch (defaultKey.second->getSymmetricKeyType()) {
+ case XSECCryptoSymmetricKey::SymmetricKeyType::KEY_AES_128:
+ algorithm = DSIGConstants::s_unicodeStrURIAES128_GCM;
+ break;
+
+ case XSECCryptoSymmetricKey::SymmetricKeyType::KEY_AES_192:
+ algorithm = DSIGConstants::s_unicodeStrURIAES192_GCM;
+ break;
+
+ case XSECCryptoSymmetricKey::SymmetricKeyType::KEY_AES_256:
+ algorithm = DSIGConstants::s_unicodeStrURIAES256_GCM;
+ break;
+
+ default:
+ throw XMLSecurityException("Unknown key type.");
+ }
+
+ const XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
+ if (!handler) {
+ throw XMLSecurityException("Unable to obtain algorithm handler.");
+ }
+
#ifndef HAVE_GMTIME_R
struct tm* ptime = gmtime(&exp);
#else
@@ -82,47 +116,134 @@ string DataSealer::wrap(const char* s, time_t exp) const
char timebuf[32];
strftime(timebuf, 32, "%Y-%m-%dT%H:%M:%SZ", ptime);
- string towrap(timebuf);
- towrap += s;
+ // The data format of the plaintext packet is:
+ // PLAINTEXT := KEYLABEL + ':' + ISOEXPTIME + DATA
+ // The plaintext is zipped, encrypted, base64'd, and prefixed with the
+ // KEYLABEL and a colon on the outside, as a key hint.
+ // Construct the plaintext packet.
+ string sb(defaultKey.first);
+ sb = sb + ':' + timebuf + s;
+
+ // zip the plaintext packet
unsigned int len;
- char* deflated = XMLHelper::deflate(const_cast<char*>(towrap.c_str()), towrap.length(), &len);
- if (!deflated)
+ char* deflated = XMLHelper::deflate(const_cast<char*>(sb.c_str()), sb.length(), &len);
+ if (!deflated || !len)
throw IOException("Failed to deflate data.");
- XMLSize_t xlen;
- XMLByte* encoded = Base64::encode(reinterpret_cast<XMLByte*>(deflated), len, &xlen);
- delete[] deflated;
- if (!encoded)
- throw IOException("Base64 encoding of deflated data failed.");
+ // Finally we encrypt the data. We have to hack this a bit to reuse the xmlsec routines.
- string wrapped;
- for (const XMLByte* xb = encoded; *xb; ++xb) {
- if (!isspace(*xb))
- wrapped += *xb;
- }
- XMLString::release((char**)&encoded);
+ DOMDocument* dummydoc = XMLToolingConfig::getConfig().getParser().newDocument();
+ Janitor<DOMDocument> docjan(dummydoc);
+ auto_ptr<XSECEnv> env(new XSECEnv(dummydoc));
- return wrapped;
+ safeBuffer plaintext;
+ plaintext.sbMemcpyIn(deflated, len);
+ delete[] deflated;
+ TXFMSB* sbt = new TXFMSB(dummydoc);
+ sbt->setInput(plaintext, len);
+ TXFMChain tx(sbt);
+
+ safeBuffer ciphertext;
+ try {
+ auto_ptr<XENCEncryptionMethod> method(XENCEncryptionMethod::create(env.get(), algorithm));
+ if (!handler->encryptToSafeBuffer(&tx, method.get(), defaultKey.second, dummydoc, ciphertext)) {
+ throw XMLSecurityException("Data encryption failed.");
+ }
+ }
+ catch (XSECException& ex) {
+ auto_ptr_char msg(ex.getMsg());
+ throw XMLSecurityException(msg.get());
+ }
+
+ defaultKey.first.append(":");
+ defaultKey.first.append(ciphertext.rawCharBuffer(), ciphertext.sbRawBufferSize());
+ return defaultKey.first;
}
string DataSealer::unwrap(const char* s) const
{
- XMLSize_t x;
- XMLByte* decoded = Base64::decode(reinterpret_cast<const XMLByte*>(s), &x);
- if (!decoded)
- throw IOException("Unable to decode base64 data.");
+ // The data format of the plaintext packet is:
+ // PLAINTEXT := KEYLABEL + ':' + ISOEXPTIME + DATA
+ // The plaintext is zipped, encrypted, base64'd, and prefixed with the
+ // KEYLABEL and a colon on the outside, as a key hint.
+
+ // First extract the key label up to the first colon.
+ pair<string, const XSECCryptoSymmetricKey*> requiredKey = make_pair(string(), nullptr);
+ const char* delim = strchr(s ? s : "", ':');
+ if (delim && delim > s) {
+ requiredKey.first.append(s, delim - s);
+ requiredKey.second = m_strategy->getKey(requiredKey.first.c_str());
+ }
+ if (!requiredKey.second)
+ throw IOException("Required decryption key not available.");
+
+ const XMLCh* algorithm = nullptr;
+ switch (requiredKey.second->getSymmetricKeyType()) {
+ case XSECCryptoSymmetricKey::SymmetricKeyType::KEY_AES_128:
+ algorithm = DSIGConstants::s_unicodeStrURIAES128_GCM;
+ break;
+
+ case XSECCryptoSymmetricKey::SymmetricKeyType::KEY_AES_192:
+ algorithm = DSIGConstants::s_unicodeStrURIAES192_GCM;
+ break;
+
+ case XSECCryptoSymmetricKey::SymmetricKeyType::KEY_AES_256:
+ algorithm = DSIGConstants::s_unicodeStrURIAES256_GCM;
+ break;
+
+ default:
+ throw XMLSecurityException("Unknown key type.");
+ }
+
+ const XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
+ if (!handler) {
+ throw XMLSecurityException("Unable to obtain algorithm handler.");
+ }
+
+ DOMDocument* dummydoc = XMLToolingConfig::getConfig().getParser().newDocument();
+ Janitor<DOMDocument> docjan(dummydoc);
+ auto_ptr<XSECEnv> env(new XSECEnv(dummydoc));
+
+ safeBuffer ciphertext;
+ ciphertext.sbStrcpyIn(++delim);
+ TXFMSB* sbt = new TXFMSB(dummydoc);
+ sbt->setInput(ciphertext, ciphertext.sbStrlen());
+ TXFMChain tx(sbt);
+ TXFMBase64* b64 = new TXFMBase64(dummydoc, true); // decodes
+ tx.appendTxfm(b64);
+
+ unsigned int len = 0;
+ safeBuffer plaintext;
+ try {
+ auto_ptr<XENCEncryptionMethod> method(XENCEncryptionMethod::create(env.get(), algorithm));
+ len = handler->decryptToSafeBuffer(&tx, method.get(), requiredKey.second, dummydoc, plaintext);
+ }
+ catch (XSECException& ex) {
+ auto_ptr_char msg(ex.getMsg());
+ throw XMLSecurityException(msg.get());
+ }
+
+ if (len == 0)
+ throw XMLSecurityException("No decrypted data available.");
// Now we have to inflate it.
- stringstream in;
- if (XMLHelper::inflate(reinterpret_cast<char*>(decoded), x, in) == 0) {
- XMLString::release((char**)&decoded);
+ stringstream out;
+ if (XMLHelper::inflate(const_cast<char*>(plaintext.rawCharBuffer()), len, out) == 0) {
throw IOException("Unable to inflate wrapped data.");
}
- XMLString::release((char**)&decoded);
- string decrypted = in.str();
- string dstr = decrypted.substr(0, 20);
+ string decrypted = out.str();
+
+ // Pull off the key label to verify it.
+ size_t i = decrypted.find(':');
+ if (i == string::npos)
+ throw IOException("Unable to verify key used to decrypt data.");
+ string keyLabel = decrypted.substr(0, i);
+ if (keyLabel != requiredKey.first)
+ throw IOException("Embedded key label does not match key used to decrypt data.");
+
+ string dstr = decrypted.substr(++i, 20);
auto_ptr_XMLCh expstr(dstr.c_str());
XMLDateTime exp(expstr.get());
exp.parseDateTime();
@@ -130,5 +251,5 @@ string DataSealer::unwrap(const char* s) const
throw IOException("Decrypted data has expired.");
}
- return decrypted.substr(20);
+ return decrypted.substr(i + 20);
}
diff --git a/xmltoolingtest/DataSealerTest.h b/xmltoolingtest/DataSealerTest.h
index 1672698..1ee35b0 100644
--- a/xmltoolingtest/DataSealerTest.h
+++ b/xmltoolingtest/DataSealerTest.h
@@ -68,5 +68,9 @@ public:
wrapped = sealer->wrap(data.c_str(), time(nullptr) - 500);
TSM_ASSERT_THROWS("DataSealer did not throw on expired data.", sealer->unwrap(wrapped.c_str()), IOException);
- }
+
+ wrapped = sealer->wrap(data.c_str(), time(nullptr) - 500);
+ wrapped.insert(0, "invalid");
+ TSM_ASSERT_THROWS("DataSealer did not throw on wrong key label.", sealer->unwrap(wrapped.c_str()), IOException);
+ }
};
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list