X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=saml%2Fsaml2%2Fcore%2Fimpl%2FAssertions.cpp;h=545748d4905b8652b20cb8ad869a5d67b753aafd;hb=e72b6644c8730e68142d78b712116538d88715f3;hp=794f5049086be43526ab3027f2b948c944299dcf;hpb=9f10292e987cc822929bb83f9462e21874b9863a;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml2/core/impl/Assertions.cpp b/saml/saml2/core/impl/Assertions.cpp index 794f504..545748d 100644 --- a/saml/saml2/core/impl/Assertions.cpp +++ b/saml/saml2/core/impl/Assertions.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -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, 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( @@ -87,16 +132,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. @@ -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()); @@ -156,7 +241,7 @@ XMLObject* EncryptedElementType::decrypt(const CredentialResolver& credResolver, { if (!getEncryptedData()) throw DecryptionException("No encrypted data present."); - EncryptedKeyResolver ekr(*this); + opensaml::EncryptedKeyResolver ekr(*this); Decrypter decrypter(&credResolver, criteria, &ekr); DOMDocumentFragment* frag = decrypter.decryptData(*getEncryptedData(), recipient); if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) { @@ -164,7 +249,18 @@ XMLObject* EncryptedElementType::decrypt(const CredentialResolver& credResolver, 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();