X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=blobdiff_plain;f=saml%2Fsaml2%2Fcore%2Fimpl%2FAssertions.cpp;h=5e075024598c730dbff5105a59d0230377d29f7f;hp=d87a9db8b788fc382faf737a8fe56e29f39ac9b0;hb=1462057b3b9ae7e165d34d988e30b14c213672ca;hpb=0f6286d0ffd9371c187ecb1775cbd199ed051af5 diff --git a/saml/saml2/core/impl/Assertions.cpp b/saml/saml2/core/impl/Assertions.cpp index d87a9db..5e07502 100644 --- a/saml/saml2/core/impl/Assertions.cpp +++ b/saml/saml2/core/impl/Assertions.cpp @@ -1,17 +1,21 @@ -/* - * 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 +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. * - * http://www.apache.org/licenses/LICENSE-2.0 + * UCAID licenses this file to you 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 * - * 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. + * 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. */ /** @@ -30,8 +34,14 @@ #include "saml2/metadata/MetadataCredentialCriteria.h" #include +#include #include #include +#include +#include +#include + +#include using namespace opensaml::saml2md; using namespace opensaml::saml2; @@ -48,28 +58,73 @@ void EncryptedElementType::encrypt( const XMLCh* algorithm ) { + XMLToolingConfig& conf = XMLToolingConfig::getConfig(); + // 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(KEK->getCredentalContext()); - if (metaCtx) { - const vector encMethods = metaCtx->getKeyDescriptor().getEncryptionMethods(); - if (!encMethods.empty()) - algorithm = encMethods.front()->getAlgorithm(); + // Get the key encryption key to use. To make use of EncryptionMethod, we have + // to examine each possible credential in conjunction with the algorithms we + // support. + criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL); + vector creds; + if (metadataProvider.resolve(creds, &criteria) == 0) + throw EncryptionException("No peer encryption credential found."); + + const XMLCh* dataalg; + const XMLCh* keyalg; + const Credential* KEK = nullptr; + + for (vector::const_iterator c = creds.begin(); !KEK && c != creds.end(); ++c) { + // Try and find EncryptionMethod information surrounding the credential. + // All we're doing if they're present is setting algorithms where possible to + // the algorithms preferred by the credential, if we support them. + // The problem is that if we don't support them, the only case we can detect + // is if neither algorithm type is set *and* there's an EncryptionMethod present. + dataalg = keyalg = nullptr; + const MetadataCredentialContext* metaCtx = dynamic_cast((*c)->getCredentalContext()); + if (metaCtx) { + const vector& encMethods = metaCtx->getKeyDescriptor().getEncryptionMethods(); + for (vector::const_iterator meth = encMethods.begin(); meth != encMethods.end(); ++meth) { + if ((*meth)->getAlgorithm()) { + if (!dataalg && conf.isXMLAlgorithmSupported((*meth)->getAlgorithm(), XMLToolingConfig::ALGTYPE_ENCRYPT)) + dataalg = (*meth)->getAlgorithm(); + else if (!keyalg && conf.isXMLAlgorithmSupported((*meth)->getAlgorithm(), XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + keyalg = (*meth)->getAlgorithm(); + } + } + + if (!dataalg && !keyalg && !encMethods.empty()) { + // We know nothing, and something was specified that we don't support, so keep looking. + continue; + } + } + + if (!keyalg && !(keyalg = Encrypter::getKeyTransportAlgorithm(*(*c), algorithm ? algorithm : dataalg))) { + // We can't derive a supported algorithm from the credential, so it will fail later anyway. + continue; + } + + // Use this key. + KEK = *c; } - if (!algorithm || !*algorithm) - algorithm = DSIGConstants::s_unicodeStrURIAES256_CBC; + if (!KEK) + throw EncryptionException("No supported peer encryption credential found."); + + // Passed in algorithm takes precedence. + if (algorithm && *algorithm) + dataalg = algorithm; + if (!dataalg) { +#ifdef XSEC_OPENSSL_HAVE_AES + dataalg = DSIGConstants::s_unicodeStrURIAES256_CBC; +#else + dataalg = DSIGConstants::s_unicodeStrURI3DES_CBC; +#endif + } Encrypter encrypter; - Encrypter::EncryptionParams ep(algorithm, NULL, 0, NULL, compact); - Encrypter::KeyEncryptionParams kep(*KEK); - setEncryptedData(encrypter.encryptElement(xmlObject.getDOM(),ep,&kep)); + Encrypter::EncryptionParams ep(dataalg, nullptr, 0, nullptr, compact); + Encrypter::KeyEncryptionParams kep(*KEK, keyalg); + setEncryptedData(encrypter.encryptElement(xmlObject.marshall(), ep, &kep)); } void EncryptedElementType::encrypt( @@ -81,16 +136,21 @@ void EncryptedElementType::encrypt( { // 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) + if (!algorithm || !*algorithm) { +#ifdef XSEC_OPENSSL_HAVE_AES algorithm = DSIGConstants::s_unicodeStrURIAES256_CBC; +#else + algorithm = DSIGConstants::s_unicodeStrURI3DES_CBC; +#endif + } // 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)); + Encrypter::EncryptionParams ep(algorithm, keyBuffer, 32, nullptr, compact); + setEncryptedData(encrypter.encryptElement(xmlObject.marshall(), ep)); getEncryptedData()->setId(SAMLConfig::getConfig().generateIdentifier()); // Generate a uniquely named KeyInfo. @@ -104,23 +164,58 @@ void EncryptedElementType::encrypt( // Now we encrypt the key for each recipient. for (vector< pair >::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); + // Get key encryption keys to use. + r->second->setUsage(Credential::ENCRYPTION_CREDENTIAL); + vector creds; + if (r->first->resolve(creds, r->second) == 0) { + auto_ptr_char name(dynamic_cast(r->second->getRole().getParent())->getEntityID()); + logging::Category::getInstance(SAML_LOGCAT ".Encryption").warn("No key encryption credentials found for (%s).", name.get()); + continue; + } + + const XMLCh* keyalg; + const Credential* KEK = nullptr; + + for (vector::const_iterator c = creds.begin(); !KEK && c != creds.end(); ++c) { + // Try and find EncryptionMethod information surrounding the credential. + // All we're doing if they're present is setting algorithms where possible to + // the algorithms preferred by the credential, if we support them. + // The problem is that if we don't support them, the only case we can detect + // is if neither algorithm type is set *and* there's an EncryptionMethod present. + keyalg = nullptr; + const MetadataCredentialContext* metaCtx = dynamic_cast((*c)->getCredentalContext()); + if (metaCtx) { + const vector& encMethods = metaCtx->getKeyDescriptor().getEncryptionMethods(); + for (vector::const_iterator meth = encMethods.begin(); meth != encMethods.end(); ++meth) { + if ((*meth)->getAlgorithm()) { + if (!keyalg && XMLToolingConfig::getConfig().isXMLAlgorithmSupported((*meth)->getAlgorithm(), XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + keyalg = (*meth)->getAlgorithm(); + } + } + } + + if (!keyalg && !(keyalg = Encrypter::getKeyTransportAlgorithm(*(*c), algorithm))) { + // We can't derive a supported algorithm from the credential, so it will fail later anyway. + continue; + } + + // Use this key. + KEK = *c; + } + if (!KEK) { auto_ptr_char name(dynamic_cast(r->second->getRole().getParent())->getEntityID()); - logging::Category::getInstance(SAML_LOGCAT".Encryption").warn("No key encryption credential found for (%s).", name.get()); + logging::Category::getInstance(SAML_LOGCAT ".Encryption").warn("no supported 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(r->second->getRole().getParent())->getEntityID() + *KEK, keyalg, dynamic_cast(r->second->getRole().getParent())->getEntityID() ); EncryptedKey* encryptedKey = encrypter.encryptKey(keyBuffer, ep.m_keyBufferSize, kep, compact); keys.push_back(encryptedKey); - if (keys.size()>1) { + if (keys.size() > 1) { // Copy details from the other key. encryptedKey->setCarriedKeyName(keys.front()->getCarriedKeyName()->cloneCarriedKeyName()); encryptedKey->setReferenceList(keys.front()->getReferenceList()->cloneReferenceList()); @@ -146,19 +241,32 @@ void EncryptedElementType::encrypt( } } -XMLObject* EncryptedElementType::decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const +XMLObject* EncryptedElementType::decrypt( + const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria, bool requireAuthenticatedCipher + ) const { if (!getEncryptedData()) throw DecryptionException("No encrypted data present."); - EncryptedKeyResolver ekr(*this); - Decrypter decrypter(&credResolver, criteria, &ekr); + opensaml::EncryptedKeyResolver ekr(*this); + Decrypter decrypter(&credResolver, criteria, &ekr, requireAuthenticatedCipher); 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 newdoc(XMLToolingConfig::getConfig().getParser().newDocument()); - DOMElement* treecopy = static_cast(newdoc->importNode(plaintext, true)); + DOMElement* treecopy; + try { + treecopy = static_cast(newdoc->importNode(plaintext, true)); + } + catch (XMLException& ex) { + frag->release(); + auto_ptr_char temp(ex.getMessage()); + throw DecryptionException( + string("Error importing decypted DOM into new document: ") + (temp.get() ? temp.get() : "no message") + ); + } + frag->release(); newdoc->appendChild(treecopy); auto_ptr ret(XMLObjectBuilder::buildOneFromElement(treecopy, true)); newdoc.release();