-------
public String encryptAssertion(Assertion assertion) throws MarshallingException {
EncryptionParameters encryptionParameters = buildEncryptionParameters();
KeyEncryptionParameters keyEncryptionParameters = buildKeyEncryptionParameters();
Encrypter encrypter = new Encrypter(encryptionParameters, keyEncryptionParameters);
EncryptedAssertion encryptedAssertion = getEncryptedAssertion(encrypter, assertion);
return new Saml2Formatter().format(encryptedAssertion);
}
private EncryptionParameters buildEncryptionParameters() throws MarshallingException {
validateEncryptionParameters();
EncryptionParameters parameters = new EncryptionParameters();
if (secretKey != null) {
logger.info("setting the encryption credential to " + secretKey.hashCode());
parameters.setEncryptionCredential(SecurityHelper.getSimpleCredential(secretKey));
logger.info("finished setting the encryption credential to " + secretKey.hashCode());
}
parameters.setAlgorithm(secretKeyAlgorithm);
return parameters;
}
private void validateEncryptionParameters() throws MarshallingException {
if (secretKeyAlgorithm == null) {
throwMarshallingException("attempt to encrypt an assertion without a secret key algorithm");
}
}
private KeyEncryptionParameters buildKeyEncryptionParameters() throws MarshallingException {
validateKeyEncryptionParameters();
KeyEncryptionParameters parameters = new KeyEncryptionParameters();
Credential credential = SecurityHelper.getSimpleCredential(publicKey, null);
parameters.setEncryptionCredential(credential);
parameters.setAlgorithm(publicKeyAlgorithm);
parameters.setKeyInfoGenerator(getKeyInfoGenerator(credential));
return parameters;
}
private void validateKeyEncryptionParameters() throws MarshallingException {
if (publicKey == null) {
throwMarshallingException("attempt to encrypt an assertion without a public key");
}
if (publicKeyAlgorithm == null) {
throwMarshallingException("attempt to encrypt an assertion without a public key algorithm");
}
}
private KeyInfoGenerator getKeyInfoGenerator(Credential credential) {
return Configuration.getGlobalSecurityConfiguration().getKeyInfoGeneratorManager().getDefaultManager()
.getFactory(credential).newInstance();
}
private EncryptedAssertion getEncryptedAssertion(Encrypter encrypter, Assertion assertion)
throws MarshallingException
{
try {
return encrypter.encrypt(assertion);
}
catch (EncryptionException e) {
String msg = "unable to encrypt the assertion";
logger.error(msg, e);
throw new MarshallingException(msg, e);
}
}
private void throwMarshallingException(String msg) throws MarshallingException {
logger.error(msg);
throw new MarshallingException(msg);
}
-------
This code works fine and seems to produce a correct encrypted SAML assertion. The problem that I'm having is when I try to decrypt the assertion, an exception is being thrown indicating that the assertion can't be decrypted. Here's the code:
-------
private Element decryptAssertion(String serializedAssertion) throws Exception {
BasicParserPool parser = new BasicParserPool();
parser.setNamespaceAware(true);
Document document = parser.parse(new StringReader(serializedAssertion));
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(document.getDocumentElement());
EncryptedAssertion encryptedAssertion = (EncryptedAssertion) unmarshaller.unmarshall(document.getDocumentElement());
logger.info(new Saml2Formatter().format(encryptedAssertion.getEncryptedData()));
PublicKey publicKey = encryptingKeyPair.getPublic();
PrivateKey privateKey = encryptingKeyPair.getPrivate();
Credential credential = SecurityHelper.getSimpleCredential(publicKey, privateKey);
StaticKeyInfoCredentialResolver resolver = new StaticKeyInfoCredentialResolver(credential);
Decrypter decrypter = new Decrypter(null, resolver, new InlineEncryptedKeyResolver());
Assertion assertion = decrypter.decrypt(encryptedAssertion);
return new Saml2Formatter().marshall(assertion);
}
-------
The logger message in the middle is just some debugging code to let me see the encrypted data. Here's what it looks like:
-------
<?xml version="1.0" encoding="UTF-8"?><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_eed2a9d3e825339e6469be143eafaa1f" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RetrievalMethod Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey" URI="#_644fac9576cba28e386bfc91feaf4f3b"/>
</ds:KeyInfo>
<xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:CipherValue>BuxPihNl2rZfDrvlZ7mBCtmESjD0s8LEJy6J8r9yQB7qL+4mcVxF/n/ZbApjRiBkExCRrqMHe3rO
d6S0Fsz2gweI8NREa48iNI4ylhNiBpI8Irj/rOYEzs3hzWhs/JH/XWB7I/t1JeT0gLkVsCaG153n
BDYU9hjQvSqbZcdLATwhcYkLtukkC4h4trxn1c6Hb8TSddSN6x+h1Yu6qhT91KVPoYlc4jXUJoVH
tyvv+X6Yq36+i/oHyNLEnffFgC34y4ZJ1f8N6++0MrHQOinxHOa08dwjpffQw+oIORWoXL84Ufcj
NCFIInSKT7SdODHIvUrQhUt4ohY8ZxydcdulvKuZB8uD9RYz04Rg26GhhlWSpTBtastnK7byxWGI
Q+FqS+BCaG1Gzy9iSE6SEn4MHSass4tH9TfUiuxqU0QASWdRVwwaVf/bCoQcYjNpneUQlSAtnB4a
7og2hERDBqyLZLUPNS5j158i+prsVivKA7/wPrEmnhhe5ZMAORhxWUrnKX6ESsjK5V4JQka93tgw
yg04joIQJNEi5hTyEx3mModlnGgGYweXync7s/hxG9L54WChk9U3l8Bce+V59eiIm6e0zmiv5Fsm
7RvYmGqOy+G6pqhwFD1vXQjOq3Cw/d/euBnUXUBBoj29npqujV51QfBpFDvMsPdNsMXO8UE84Qv4
T3+iWIpNMnAjYoTR1ZPVw5uvYOjNsfV51eIrMDA7HPfkuZuNVMydFTkRO8T7tG3z4m3o9xjxm6Mo
wHPVOkdhkYS4TlLFm34t9I7dzP5alv6HSMWANJnp45rvh2R4iFZXywnR/v5v86D+z56cLzsS3MiU
zmYJ6Y7DBynjMI4wbWtfWiEPOd4HkUrpIqAgxntsj6XaKmcLM5bIe7o0Nses8tiifwB3t9/7PUPg
Mi6GbNhMC2Snkve2UlYd2E3WU07v71AbSy7D+G36blKQHc8megq2rRlP1hAyiDqNkZbZb6ETEV9H
A1UgqW5rlhFtXtUmvz/HgWi9F5LXSfuLtisILTgraV/XfEyGe/WuMP0Sd9RorzTovQYeOq+xj9Rb
XVfWoo5gDmlQhix/n/dJMCAzqMgPF+YakhBzVQz8yukYML1ohFktV/8TNlpULV924Dh9DCLyhOEF
WwCZmTUn/TYOewYllaXOuBsPX59N42RCCMPdbyQ+1EyVlf7wongoV2uNJgTMAPz3jylP9mo4EeH7
5WDxMIDpdJ2qRAE/NCIAh5F+QKSrMCAypn8yLZWjUybwek2FSaBZONnJsPxBb2kXJApB1DcZs09E
VP/y6r0cV7hEq3Qg3kjUrILEy4hWOK4GBLx77r8e4gu5efxJsbFxptGeM9l4Eqvl+wcB+QXUJg2P
xSMUWZ/jX8EMtdGa+v19Bt4DKnsJ3mnefJgBYWwwMkwLzG2dzAyY0HJM0lL4moX2mRz17enzTRXx
URRIKrks8ZFLXpb0I/3oPt8Mun5M</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
-------
I searched for other messages that mention similar problems, but the only one I found appears to have been solved by using objects in the SAML2 package rather than the SAML1 package. That isn't this problem (I'm using only SAML2 objects).
I did step through the code a little, and it appears that part of the problem is that the InlineEncryptedKeyResolver is unable to get the list of encrypted keys from the encrypted data. This line of code from org.opensaml.saml2.encryption.Decrypter passes only the encrypted data to it's parent class:
-------
xmlObject = decryptData(encElement.getEncryptedData(), isRootInNewDocument());
-------
This eventually gets to org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(), which calls the encrypted key resolver's resolve() method. This method then calls encryptedData.getKeyInfo().getEncryptedKeys(), which returns an empty list.
encryptedData.getKeyInfo() returns the ds:KeyInfo child element from the encrypted data above. The problem occurs when getEncryptedKeys() is called. This method looks for child ds:EncryptedKey child elements. In this case, there aren't any ds:EncryptedKey child elements because the ds:KeyInfo element only contains a ds:RetrievalMethod child element.
Am I doing something wrong or is the decryption of assertions in this format not supported yet? If it isn't supported yet, is there an easy way to get OpenSAML to put the keys directly in the ds:KeyInfo element of the encrypted data? I'm using OpenSAML 2.3.1.
Thanks,
Dennis
Which doesn't appear to be pointing to anything, so that's pretty strange.
> Am I doing something wrong or is the decryption of assertions in this
format
> not supported yet? If it isn't supported yet, is there an easy way to get
> OpenSAML to put the keys directly in the ds:KeyInfo element of the
encrypted
> data? I'm using OpenSAML 2.3.1.
I can't imagine how you got it to do anything else, but only Brent probably
knows. In any case, if you want code that works the normal way you'll
probably need to look at Shibboleth to find what you're doing differently.
-- Scott
>
> Decrypter decrypter = new Decrypter(null, resolver, new InlineEncryptedKeyResolver());
> Assertion assertion = decrypter.decrypt(encryptedAssertion);
> return new Saml2Formatter().marshall(assertion);
> }
>
>
>
I think that the problem is, you've got a mismatch between where your
SAML 2 Encrypter instance is placing the keys, and where you are telling
the Decrypter above to resolve them. The Encrypter by default places
them as direct children of the SAML EncryptedElementType (e.g.
EncryptedAssertion), in other words, as peers of the EncryptedData. In
the Encrypter Javadocs that's what is called PEER placment. I did
notice that that default was mis-documented in the Javadoc for the
Encrypter. I fixed it in Subversion. For the record, it should say
that the default for the keyPlacement property of the Encrypter is
Encrypter.KeyPlacement.PEER, not INLINE. Maybe that was what was
throwing you off.
The InlineEncryptedKeyResolver you're using, on the other hand, only
resolves EncryptedKey's that are children of the EncryptedData's KeyInfo
(that's what's meant by INLINE).
>
> I did step through the code a little, and it appears that part of the problem is that the InlineEncryptedKeyResolver is unable to get the list of encrypted keys from the encrypted data.
Right, because they aren't there. :-) For the default Encrypter key
placment of PEER, use the SAML 2
EncryptedElementTypeEncryptedKeyResolver, which knows how to handle the
EncryptedData that is part of a SAML 2 EncryptedElementType (although
see end of this message for better solution).
> In this case, there aren't any ds:EncryptedKey child elements because the ds:KeyInfo element only contains a ds:RetrievalMethod child element.
>
Yeah, it contains a RetrievalMethod b/c that's what the SAML E43 errata
says to do in the case of placing the keys as peers of the
EncryptedData. BTW, I believe use of a
SimpleRetrievalMethodEncryptedKeyResolver (rather than
EncryptedElementTypeEncryptedKeyResolver) in the Decrypter would also
resolve those correctly.
> Am I doing something wrong or is the decryption of assertions in this format not supported yet? If it isn't supported yet, is there an easy way to get OpenSAML to put the keys directly in the ds:KeyInfo element of the encrypted data? I'm using OpenSAML 2.3.1.
>
No, it's all supported.
If you want or need the EncryptedKey's "inline" within in the
EncryptedData's KeyInfo, just call encrypter.setKeyPlacement(INLINE)
before you do the encryption. Then they should be resolvable by the
InlineEncryptedKeyResolver.
Another suggestion is: In the real world, for an actual deployment, you
don't necessarily know in advance how someone sending you encrypted SAML
structures will place the EncryptedKeys. So the best thing to do is
actually supply the Decrypter with a ChainingEncryptedKeyResolver, that
as members has any or all of the above. That way you cover all the
bases. They will be evaluated in the order they are added to the
chaining resolver's List.
HTH,
Brent
On 3/15/2010 9:50 PM, Scott Cantor wrote:
>
>> This method looks for child ds:EncryptedKey child elements. In this case,
>> there aren't any ds:EncryptedKey child elements because the ds:KeyInfo
>> element only contains a ds:RetrievalMethod child element.
>>
> Which doesn't appear to be pointing to anything, so that's pretty strange.
>
I think he just didn't send us the full EncryptedAssertion, only the
EncryptedData. If he had, we would see the EncryptedKeys as children,
and the RetrievalMethod would correctly point to them (and the
EncryptedKey's DataReference would link back to the EncryptedData, as
per E43).
> In any case, if you want code that works the normal way you'll
> probably need to look at Shibboleth to find what you're doing differently.
At least in terms of the Java, it wouldn't help really, b/c we don't yet
do any decryption in the IdP (i.e. don't yet support EncryptedID), so
there's no examples there. There are however lots of examples in the
unit tests for both the generic xmlooling encrypter and decrypter, as
well as the opensaml2 specialized ones for the SAML 2 stuff.
On 3/15/2010 11:36 PM, Brent Putman wrote:
>
> At least in terms of the Java, it wouldn't help really, b/c we don't yet
> do any decryption in the IdP (i.e. don't yet support EncryptedID),
>
Of course, that should have said, we don't support decrypting *inbound*
EncryptedID. Obviously, we support encrypting NameIDs that are outbound.
It all makes perfect sense...now that I know what the answer is. :-)
I'll give this a try tomorrow.
Thanks,
Dennis
>
>
> On 3/15/2010 9:50 PM, Scott Cantor wrote:
>>
>>> This method looks for child ds:EncryptedKey child elements. In
>>> this case,
>>> there aren't any ds:EncryptedKey child elements because the
>>> ds:KeyInfo
>>> element only contains a ds:RetrievalMethod child element.
>>>
>> Which doesn't appear to be pointing to anything, so that's pretty
>> strange.
>>
>
>
> I think he just didn't send us the full EncryptedAssertion, only the
> EncryptedData. If he had, we would see the EncryptedKeys as children,
> and the RetrievalMethod would correctly point to them (and the
> EncryptedKey's DataReference would link back to the EncryptedData, as
> per E43).
That's exactly what I did. Sorry about the confusion there.
Dennis
> Another suggestion is: In the real world, for an actual deployment, you
> don't necessarily know in advance how someone sending you encrypted SAML
> structures will place the EncryptedKeys. So the best thing to do is
> actually supply the Decrypter with a ChainingEncryptedKeyResolver, that
> as members has any or all of the above. That way you cover all the
> bases. They will be evaluated in the order they are added to the
> chaining resolver's List.
That worked perfectly. Thanks again for your help.
Dennis