From 96a6e5d552a21aca11f201e7b74d7340c88bde2f Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 6 Sep 2010 01:07:05 +0000 Subject: [PATCH] https://issues.shibboleth.net/jira/browse/SSPCPP-304 --- saml/saml2/core/impl/Assertions.cpp | 133 ++++++++++++++++++++++++------ saml/saml2/metadata/impl/MetadataImpl.cpp | 8 +- 2 files changed, 113 insertions(+), 28 deletions(-) diff --git a/saml/saml2/core/impl/Assertions.cpp b/saml/saml2/core/impl/Assertions.cpp index d86d140..89ea4c9 100644 --- a/saml/saml2/core/impl/Assertions.cpp +++ b/saml/saml2/core/impl/Assertions.cpp @@ -54,28 +54,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. + // 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); - 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(); + 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, nullptr, 0, nullptr, 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( @@ -87,8 +132,13 @@ 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]; @@ -96,7 +146,7 @@ void EncryptedElementType::encrypt( throw EncryptionException("Unable to generate encryption key; was PRNG seeded?"); Encrypter encrypter; Encrypter::EncryptionParams ep(algorithm, keyBuffer, 32, nullptr, compact); - setEncryptedData(encrypter.encryptElement(xmlObject.getDOM(),ep)); + setEncryptedData(encrypter.encryptElement(xmlObject.marshall(), ep)); getEncryptedData()->setId(SAMLConfig::getConfig().generateIdentifier()); // Generate a uniquely named KeyInfo. @@ -110,23 +160,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. + // Get key encryption keys to use. r->second->setUsage(Credential::ENCRYPTION_CREDENTIAL); - const Credential* KEK = r->first->resolve(r->second); + 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()); diff --git a/saml/saml2/metadata/impl/MetadataImpl.cpp b/saml/saml2/metadata/impl/MetadataImpl.cpp index 0f99b22..549408a 100644 --- a/saml/saml2/metadata/impl/MetadataImpl.cpp +++ b/saml/saml2/metadata/impl/MetadataImpl.cpp @@ -2696,7 +2696,7 @@ const DigestMethod* RoleDescriptor::getDigestMethod() const for (vector::const_iterator i = exts.begin(); i != exts.end(); ++i) { const opensaml::saml2md::DigestMethod* dm = dynamic_cast(*i); if (dm) { - if (dm->getAlgorithm() && conf.isXMLAlgorithmSupported(dm->getAlgorithm())) + if (dm->getAlgorithm() && conf.isXMLAlgorithmSupported(dm->getAlgorithm(), XMLToolingConfig::ALGTYPE_DIGEST)) return dm; roleLevel = true; } @@ -2709,7 +2709,7 @@ const DigestMethod* RoleDescriptor::getDigestMethod() const const vector& exts = const_cast(entity->getExtensions())->getUnknownXMLObjects(); for (vector::const_iterator i = exts.begin(); i != exts.end(); ++i) { const opensaml::saml2md::DigestMethod* dm = dynamic_cast(*i); - if (dm && dm->getAlgorithm() && conf.isXMLAlgorithmSupported(dm->getAlgorithm())) + if (dm && dm->getAlgorithm() && conf.isXMLAlgorithmSupported(dm->getAlgorithm(), XMLToolingConfig::ALGTYPE_DIGEST)) return dm; } } @@ -2729,7 +2729,7 @@ pair RoleDescriptor::getSigningMethod(co const SigningMethod* sm = dynamic_cast(*i); if (sm) { roleLevel = true; - if (sm->getAlgorithm() && conf.isXMLAlgorithmSupported(sm->getAlgorithm())) { + if (sm->getAlgorithm() && conf.isXMLAlgorithmSupported(sm->getAlgorithm(), XMLToolingConfig::ALGTYPE_SIGN)) { cc.setXMLAlgorithm(sm->getAlgorithm()); pair minsize = sm->getMinKeySize(), maxsize = sm->getMaxKeySize(); if (minsize.first || maxsize.first) { @@ -2755,7 +2755,7 @@ pair RoleDescriptor::getSigningMethod(co for (vector::const_iterator i = exts.begin(); i != exts.end(); ++i) { const SigningMethod* sm = dynamic_cast(*i); if (sm) { - if (sm->getAlgorithm() && conf.isXMLAlgorithmSupported(sm->getAlgorithm())) { + if (sm->getAlgorithm() && conf.isXMLAlgorithmSupported(sm->getAlgorithm(), XMLToolingConfig::ALGTYPE_SIGN)) { cc.setXMLAlgorithm(sm->getAlgorithm()); pair minsize = sm->getMinKeySize(), maxsize = sm->getMaxKeySize(); if (minsize.first || maxsize.first) { -- 2.1.4