Multi-line svn commit, see body.
authorScott Cantor <cantor.2@osu.edu>
Fri, 20 Apr 2007 03:21:34 +0000 (03:21 +0000)
committerScott Cantor <cantor.2@osu.edu>
Fri, 20 Apr 2007 03:21:34 +0000 (03:21 +0000)
Added uni/multicast encrypting methods.
Moved decryption method to base class.

saml/Makefile.am
saml/binding/MessageEncoder.h
saml/saml.vcproj
saml/saml2/binding/impl/SAML2RedirectEncoder.cpp
saml/saml2/core/Assertions.h
saml/saml2/core/impl/Assertions.cpp [new file with mode: 0644]
saml/saml2/core/impl/Assertions20Impl.cpp
saml/saml2/core/impl/Protocols20Impl.cpp

index 3b25823..4453d9f 100644 (file)
@@ -132,6 +132,7 @@ libsaml_la_SOURCES = \
        saml1/binding/impl/SAML1MessageRule.cpp \
        saml1/profile/AssertionValidator.cpp \
        saml1/profile/BrowserSSOProfileValidator.cpp \
+       saml2/core/impl/Assertions.cpp \
        saml2/core/impl/Assertions20Impl.cpp \
        saml2/core/impl/Assertions20SchemaValidators.cpp \
        saml2/core/impl/Protocols20Impl.cpp \
index ad87a08..0bb70ee 100644 (file)
@@ -46,6 +46,15 @@ namespace opensaml {
         virtual ~MessageEncoder() {}
 
         /**
+         * Indicates whether the encoding format requires that messages be as compact as possible.
+         *
+         * @return  true iff the encoding has size constraints
+         */
+        virtual bool isCompact() const {
+            return false;
+        }
+
+        /**
          * Interface to caller-supplied artifact generation mechanism.
          * 
          * Generating an artifact for storage and retrieval requires knowledge of
index 17cfdeb..9c0f39e 100644 (file)
                                                Name="impl"\r
                                                >\r
                                                <File\r
+                                                       RelativePath=".\saml2\core\impl\Assertions.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml2\core\impl\Assertions20Impl.cpp"\r
                                                        >\r
                                                </File>\r
index c450177..6360fca 100644 (file)
@@ -48,6 +48,10 @@ namespace opensaml {
         public:
             SAML2RedirectEncoder(const DOMElement* e) {}
             virtual ~SAML2RedirectEncoder() {}
+
+            bool isCompact() const {
+                return true;
+            }
             
             long encode(
                 GenericResponse& genericResponse,
index 0d6b59d..a5a7fb7 100644 (file)
 
 namespace opensaml {
 
+    namespace saml2md {
+        class SAML_API MetadataProvider;
+        class SAML_API MetadataCredentialCriteria;
+    };
+
     /**
      * @namespace opensaml::saml2
      * SAML 2.0 assertion namespace
@@ -47,6 +52,16 @@ namespace opensaml {
         // Forward references
         class SAML_API Assertion;
         class SAML_API EncryptedAssertion;
+
+        /**
+         * Marker interface for SAML types that can be encrypted.
+         */
+        class SAML_API EncryptableObject : public virtual xmltooling::XMLObject
+        {
+        protected:
+            EncryptableObject() {}
+            virtual ~EncryptableObject() {}
+        };
         
         DECL_XMLOBJECT_SIMPLE(SAML_API,AssertionIDRef,AssertionID,SAML 2.0 AssertionIDRef element);
         DECL_XMLOBJECT_SIMPLE(SAML_API,AssertionURIRef,AssertionURI,SAML 2.0 AssertionURIRef element);
@@ -62,6 +77,40 @@ namespace opensaml {
             static const XMLCh TYPE_NAME[];
             
             /**
+             * Encrypts an object to a single recipient using this object as a container.
+             * 
+             * @param xmlObject         object to encrypt
+             * @param metadataProvider  a locked MetadataProvider to supply encryption keys
+             * @param criteria          metadata-based CredentialCriteria to use
+             * @param compact           true iff compact KeyInfo should be used
+             * @param algorithm         optionally specifies data encryption algorithm if none can be determined from metadata
+             * @return  the encrypted object
+             */
+            virtual void encrypt(
+                const EncryptableObject& xmlObject,
+                const saml2md::MetadataProvider& metadataProvider,
+                saml2md::MetadataCredentialCriteria& criteria,
+                bool compact=false,
+                const XMLCh* algorithm=NULL
+                );
+
+            /**
+             * Encrypts an object to multiple recipients using this object as a container.
+             * 
+             * @param recipients    pairs containing a locked MetadataProvider to supply encryption keys,
+             *                      and a metadata-based CredentialCriteria to use
+             * @param compact       true iff compact KeyInfo should be used
+             * @param algorithm     optionally specifies data encryption algorithm if none can be determined from metadata
+             * @return  the encrypted object
+             */
+            virtual void encrypt(
+                const EncryptableObject& xmlObject,
+                const std::vector< std::pair<const saml2md::MetadataProvider*, saml2md::MetadataCredentialCriteria*> >& recipients,
+                bool compact=false,
+                const XMLCh* algorithm=NULL
+                );
+
+            /**
              * Decrypts the element using the supplied CredentialResolver.
              *
              * <p>The object returned will be unmarshalled around the decrypted DOM element in a
@@ -74,13 +123,13 @@ namespace opensaml {
              */
             virtual xmltooling::XMLObject* decrypt(
                 const xmltooling::CredentialResolver& credResolver, const XMLCh* recipient, xmltooling::CredentialCriteria* criteria=NULL
-                ) const=0;
+                ) const;
         END_XMLOBJECT;
 
         BEGIN_XMLOBJECT(SAML_API,EncryptedID,EncryptedElementType,SAML 2.0 EncryptedID element);
         END_XMLOBJECT;
 
-        BEGIN_XMLOBJECT(SAML_API,BaseID,xmltooling::XMLObject,SAML 2.0 BaseID abstract element);
+        BEGIN_XMLOBJECT(SAML_API,BaseID,EncryptableObject,SAML 2.0 BaseID abstract element);
             DECL_STRING_ATTRIB(NameQualifier,NAMEQUALIFIER);
             DECL_STRING_ATTRIB(SPNameQualifier,SPNAMEQUALIFIER);
         END_XMLOBJECT;
@@ -111,7 +160,7 @@ namespace opensaml {
             static const XMLCh TRANSIENT[];
         END_XMLOBJECT;
 
-        BEGIN_XMLOBJECT(SAML_API,NameID,NameIDType,SAML 2.0 NameID element);
+        BEGIN_XMLOBJECT2(SAML_API,NameID,NameIDType,EncryptableObject,SAML 2.0 NameID element);
         END_XMLOBJECT;
 
         BEGIN_XMLOBJECT(SAML_API,Issuer,NameIDType,SAML 2.0 Issuer element);
@@ -266,7 +315,7 @@ namespace opensaml {
         BEGIN_XMLOBJECT(SAML_API,AttributeValue,xmltooling::ElementProxy,SAML 2.0 AttributeValue element);
         END_XMLOBJECT;
 
-        BEGIN_XMLOBJECT(SAML_API,Attribute,xmltooling::AttributeExtensibleXMLObject,SAML 2.0 Attribute element);
+        BEGIN_XMLOBJECT2(SAML_API,Attribute,xmltooling::AttributeExtensibleXMLObject,EncryptableObject,SAML 2.0 Attribute element);
             DECL_STRING_ATTRIB(Name,NAME);
             DECL_STRING_ATTRIB(NameFormat,NAMEFORMAT);
             DECL_STRING_ATTRIB(FriendlyName,FRIENDLYNAME);
@@ -320,7 +369,7 @@ namespace opensaml {
             virtual Issuer* getIssuer() const=0;
         };
 
-        BEGIN_XMLOBJECT2(SAML_API,Assertion,saml2::RootObject,opensaml::Assertion,SAML 2.0 Assertion element);
+        BEGIN_XMLOBJECT3(SAML_API,Assertion,saml2::RootObject,opensaml::Assertion,EncryptableObject,SAML 2.0 Assertion element);
             DECL_INHERITED_STRING_ATTRIB(Version,VER);
             DECL_INHERITED_STRING_ATTRIB(ID,ID);
             DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
@@ -446,7 +495,7 @@ namespace opensaml {
                 throw xmltooling::XMLObjectException("Unable to obtain typed builder for KeyInfoConfirmationDataType.");
             }
         };
-        
+
         /**
          * Registers builders and validators for SAML 2.0 Assertion classes into the runtime.
          */
diff --git a/saml/saml2/core/impl/Assertions.cpp b/saml/saml2/core/impl/Assertions.cpp
new file mode 100644 (file)
index 0000000..585723a
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Assertions.cpp
+ * 
+ * Built-in behavior for SAML 2.0 Assertion interfaces.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml/encryption/EncryptedKeyResolver.h"
+#include "saml2/core/Assertions.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+#include "saml2/metadata/MetadataCredentialContext.h"
+#include "saml2/metadata/MetadataCredentialCriteria.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/encryption/Encrypter.h>
+#include <xmltooling/encryption/Decrypter.h>
+
+using namespace opensaml::saml2md;
+using namespace opensaml::saml2;
+using namespace xmlencryption;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace std;
+
+void EncryptedElementType::encrypt(
+    const EncryptableObject& xmlObject,
+    const MetadataProvider& metadataProvider,
+    MetadataCredentialCriteria& criteria,
+    bool compact,
+    const XMLCh* algorithm
+    )
+{
+    // With one recipient, we let the library generate the encryption key for us.
+    // Get the key encryption key to use.
+    criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
+    const Credential* KEK = metadataProvider.resolve(&criteria);
+    if (!KEK)
+        throw EncryptionException("No key encryption credential found.");
+
+    // Try and find EncryptionMethod information surrounding the credential.
+    const MetadataCredentialContext* metaCtx = dynamic_cast<const MetadataCredentialContext*>(KEK->getCredentalContext());
+    if (metaCtx) {
+        const vector<EncryptionMethod*> encMethods = metaCtx->getKeyDescriptor().getEncryptionMethods();
+        if (!encMethods.empty())
+            algorithm = encMethods.front()->getAlgorithm();
+    }
+
+    if (!algorithm || !*algorithm)
+        algorithm = DSIGConstants::s_unicodeStrURIAES256_CBC;
+
+    Encrypter encrypter;
+    Encrypter::EncryptionParams ep(algorithm, NULL, 0, NULL, compact);
+    Encrypter::KeyEncryptionParams kep(*KEK);
+    setEncryptedData(encrypter.encryptElement(xmlObject.getDOM(),ep,&kep));
+}
+
+void EncryptedElementType::encrypt(
+    const EncryptableObject& xmlObject,
+    const vector< pair<const MetadataProvider*, MetadataCredentialCriteria*> >& recipients,
+    bool compact,
+    const XMLCh* algorithm
+    )
+{
+    if (recipients.size()==1)
+        return encrypt(xmlObject, *recipients.front().first, *recipients.front().second, compact, algorithm);
+
+    // With multiple recipients, we have to generate an encryption key and then multicast it,
+    // so we need to split the encryption and key wrapping steps.
+    if (!algorithm || !*algorithm)
+        algorithm = DSIGConstants::s_unicodeStrURIAES256_CBC;
+
+    // Generate a random key.
+    unsigned char keyBuffer[32];
+    if (XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuffer,32)<32)
+        throw EncryptionException("Unable to generate encryption key; was PRNG seeded?");
+    Encrypter encrypter;
+    Encrypter::EncryptionParams ep(algorithm, keyBuffer, 32, NULL, compact);
+    setEncryptedData(encrypter.encryptElement(xmlObject.getDOM(),ep));
+    getEncryptedData()->setId(SAMLConfig::getConfig().generateIdentifier());
+
+    // Generate a uniquely named KeyInfo.
+    KeyInfo* keyInfo = KeyInfoBuilder::buildKeyInfo();
+    getEncryptedData()->setKeyInfo(keyInfo);
+    KeyName* carriedName = KeyNameBuilder::buildKeyName();
+    keyInfo->getKeyNames().push_back(carriedName);
+    carriedName->setName(SAMLConfig::getConfig().generateIdentifier());
+
+    VectorOf(EncryptedKey) keys = getEncryptedKeys();
+
+    // Now we encrypt the key for each recipient.
+    for (vector< pair<const MetadataProvider*, MetadataCredentialCriteria*> >::const_iterator r = recipients.begin(); r!=recipients.end(); ++r) {
+        // Get key encryption key to use.
+        r->second->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
+        const Credential* KEK = r->first->resolve(r->second);
+        if (!KEK) {
+            auto_ptr_char name(dynamic_cast<const EntityDescriptor*>(r->second->getRole().getParent())->getEntityID());
+            log4cpp::Category::getInstance(SAML_LOGCAT".Encryption").warn("No key encryption credential found for (%s).", name.get());
+            continue;
+        }
+
+        // Encrypt the key and add it to the message.
+        Encrypter::KeyEncryptionParams kep(
+            *KEK, Encrypter::getKeyTransportAlgorithm(*KEK, algorithm),
+            dynamic_cast<const EntityDescriptor*>(r->second->getRole().getParent())->getEntityID()
+            );
+        EncryptedKey* encryptedKey = encrypter.encryptKey(keyBuffer, ep.m_keyBufferSize, kep, compact);
+        keys.push_back(encryptedKey);
+        if (keys.size()>1) {
+            // Copy details from the other key.
+            encryptedKey->setCarriedKeyName(keys.front()->getCarriedKeyName()->cloneCarriedKeyName());
+            encryptedKey->setReferenceList(keys.front()->getReferenceList()->cloneReferenceList());
+        }
+        else {
+            // Attach the carried key name.
+            CarriedKeyName* carried = CarriedKeyNameBuilder::buildCarriedKeyName();
+            carried->setName(carriedName->getName());
+            encryptedKey->setCarriedKeyName(carried);
+
+            // Attach a back-reference to the data.
+            ReferenceList* reflist = ReferenceListBuilder::buildReferenceList();
+            encryptedKey->setReferenceList(reflist);
+            DataReference* dataref = DataReferenceBuilder::buildDataReference();
+            reflist->getDataReferences().push_back(dataref);
+            XMLCh* uri = new XMLCh[XMLString::stringLen(getEncryptedData()->getId()) + 2];
+            *uri = chPound;
+            *(uri+1) = chNull;
+            XMLString::catString(uri, getEncryptedData()->getId());
+            dataref->setURI(uri);
+            delete[] uri;
+        }
+    }
+}
+
+XMLObject* EncryptedElementType::decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const
+{
+    if (!getEncryptedData())
+        throw DecryptionException("No encrypted data present.");
+    EncryptedKeyResolver ekr(*this);
+    Decrypter decrypter(&credResolver, criteria, &ekr);
+    DOMDocumentFragment* frag = decrypter.decryptData(*getEncryptedData(), recipient);
+    if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) {
+        DOMNode* plaintext=frag->getFirstChild();
+        if (plaintext->getNodeType()==DOMNode::ELEMENT_NODE) {
+            // Import the tree into a new Document that we can bind to the unmarshalled object.
+            XercesJanitor<DOMDocument> newdoc(XMLToolingConfig::getConfig().getParser().newDocument());
+            DOMElement* treecopy = static_cast<DOMElement*>(newdoc->importNode(plaintext, true));
+            newdoc->appendChild(treecopy);
+            auto_ptr<XMLObject> ret(XMLObjectBuilder::buildOneFromElement(treecopy, true));
+            newdoc.release();
+            return ret.release();
+        }
+    }
+    frag->release();
+    throw DecryptionException("Decryption did not result in a single element.");
+}
index 3a714b7..4dd9a09 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <xmltooling/AbstractComplexElement.h>
 #include <xmltooling/AbstractSimpleElement.h>
-#include <xmltooling/encryption/Decrypter.h>
 #include <xmltooling/impl/AnyElement.h>
 #include <xmltooling/io/AbstractXMLObjectMarshaller.h>
 #include <xmltooling/io/AbstractXMLObjectUnmarshaller.h>
@@ -52,7 +51,7 @@ using samlconstants::SAML20_NS;
 
 namespace opensaml {
     namespace saml2 {
-    
+
         DECL_XMLOBJECTIMPL_SIMPLE(SAML_DLLLOCAL,AssertionIDRef);
         DECL_XMLOBJECTIMPL_SIMPLE(SAML_DLLLOCAL,AssertionURIRef);
         DECL_XMLOBJECTIMPL_SIMPLE(SAML_DLLLOCAL,Audience);
@@ -191,29 +190,6 @@ namespace opensaml {
                     }
                 }
             }
-    
-            XMLObject* decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const
-            {
-                if (!m_EncryptedData)
-                    throw DecryptionException("No encrypted data present.");
-                EncryptedKeyResolver ekr(*this);
-                Decrypter decrypter(&credResolver, criteria, &ekr);
-                DOMDocumentFragment* frag = decrypter.decryptData(*m_EncryptedData, recipient);
-                if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) {
-                    DOMNode* plaintext=frag->getFirstChild();
-                    if (plaintext->getNodeType()==DOMNode::ELEMENT_NODE) {
-                        // Import the tree into a new Document that we can bind to the unmarshalled object.
-                        XercesJanitor<DOMDocument> newdoc(XMLToolingConfig::getConfig().getParser().newDocument());
-                        DOMElement* treecopy = static_cast<DOMElement*>(newdoc->importNode(plaintext, true));
-                        newdoc->appendChild(treecopy);
-                        auto_ptr<XMLObject> ret(XMLObjectBuilder::buildOneFromElement(treecopy, true));
-                        newdoc.release();
-                        return ret.release();
-                    }
-                }
-                frag->release();
-                throw DecryptionException("Decryption did not result in a single element.");
-            }
         
             IMPL_XMLOBJECT_CLONE(EncryptedElementType);
             IMPL_TYPED_FOREIGN_CHILD(EncryptedData,xmlencryption);
@@ -227,7 +203,6 @@ namespace opensaml {
             }
         };
 
-        //TODO unit test for this 
         class SAML_DLLLOCAL EncryptedIDImpl : public virtual EncryptedID, public EncryptedElementTypeImpl
         {
         public:
index e4b652e..75a7cdc 100644 (file)
 
 #include "internal.h"
 #include "exceptions.h"
-#include "saml/encryption/EncryptedKeyResolver.h"
 #include "saml2/core/Protocols.h"
 
 #include <xmltooling/AbstractComplexElement.h>
 #include <xmltooling/AbstractSimpleElement.h>
-#include <xmltooling/encryption/Decrypter.h>
 #include <xmltooling/impl/AnyElement.h>
 #include <xmltooling/io/AbstractXMLObjectMarshaller.h>
 #include <xmltooling/io/AbstractXMLObjectUnmarshaller.h>
@@ -1288,29 +1286,6 @@ namespace opensaml {
                 }
             }
     
-            XMLObject* decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const
-            {
-                if (!m_EncryptedData)
-                    throw DecryptionException("No encrypted data present.");
-                EncryptedKeyResolver ekr(*this);
-                Decrypter decrypter(&credResolver, criteria, &ekr);
-                DOMDocumentFragment* frag = decrypter.decryptData(*m_EncryptedData, recipient);
-                if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) {
-                    DOMNode* plaintext=frag->getFirstChild();
-                    if (plaintext->getNodeType()==DOMNode::ELEMENT_NODE) {
-                        // Import the tree into a new Document that we can bind to the unmarshalled object.
-                        XercesJanitor<DOMDocument> newdoc(XMLToolingConfig::getConfig().getParser().newDocument());
-                        DOMElement* treecopy = static_cast<DOMElement*>(newdoc->importNode(plaintext, true));
-                        newdoc->appendChild(treecopy);
-                        auto_ptr<XMLObject> ret(XMLObjectBuilder::buildOneFromElement(treecopy, true));
-                        newdoc.release();
-                        return ret.release();
-                    }
-                }
-                frag->release();
-                throw DecryptionException("Decryption did not result in a single element.");
-            }
-        
             IMPL_XMLOBJECT_CLONE(NewEncryptedID);
             EncryptedElementType* cloneEncryptedElementType() const {
                 return new NewEncryptedIDImpl(*this);