Node.js / SAML:如何解密RequestedSecurityToken的内容

我正在使用passport-wsfed-saml2 ,WS-fed和SAML2协议的护照策略。

逻辑的WS-fed部分似乎不处理其内容是<xenc:EncryptedData>元素的RequestedSecurityToken元素。

这使得该策略与具有指定encryption证书的ADFS 2.0依赖方不兼容。

我想用一些解密逻辑对策略的WsFederation.extractToken方法进行修补。

下面是我想要预处理的RequestSecurityTokenResponse xml示例。 我应该如何去解密令牌? 具体来说,如何将<KeyInfo>元素中提供的信息与<xenc:CipherData>元素结合使用来访问明文标记数据。

 <?xml version="1.0" encoding="UTF-8"?> <t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"> <t:Lifetime> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-01-05T21:02:07.193Z</wsu:Created> <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-01-05T22:02:07.193Z</wsu:Expires> </t:Lifetime> <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing"> <wsa:Address>https://localhost</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <t:RequestedSecurityToken> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> </e:EncryptionMethod> <KeyInfo> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <X509Data> <X509IssuerSerial> <X509IssuerName>CN=token-signing, OU=SomeOrg, O=EvilCorp, L=Williston, S=VT, C=US</X509IssuerName> <X509SerialNumber>13135613350938963680</X509SerialNumber> </X509IssuerSerial> </X509Data> </o:SecurityTokenReference> </KeyInfo> <e:CipherData> <e:CipherValue>v6ueRi+G+s31b9RZxE1X8gfNWk6qC9EWimhmDQzLOl/9HQrToqcLRNVqpdocfAgAGp3RkyR9IcwED7PZkreNNzEYMN3pntqS1372Nk6EEYwJSVmWkXmsv4m+xeJvGPQrDIZOwlq22OBt0EAwXoq7LvkmF0s/uhB4TItD47iAsDOFThMpuPoYo0EDLgPWzHtrZqTsC33c10zKKgyynSJPAKaC/+a9mSc4uxq55njU4GLVP/p4FvubPF2U1j4I7ozRGGWsAD5iTGwIOIF7H/ftKoRGIoFen29Ud87mm00BrF0GSUzcxTX+isMfI+HWp8u9zaO1ZLge5+x12BJcVWOYwblTQ7IPWyCMmaUscGgQPZ82ROrMCbX2f6HcGHtl8rwzXbz/VfAZkkxXZAfq9NRjSIRcmVtwC4cjwPAAcwE6V8+lvFn/2dUgzSz9y5K4HpzWZc2jg91oyzhFV+5luC+NV2HPAtTshjWOWhAcVuZYdINfcU1rSHKirBtDPQjxEWcyxkGyrl6UfWq1sEDuaXBPVNWT9/jyjuf7Rzyxnype8SleTK197FnD+rq6NzG9H4MpTFwhgokiPx4/RONjog7I1qnNM5wFybJ5WvkSh+x1w1w7/CNGipJSXCy3swGuSgSF3LI1bUZSzL+JqhUmYq8EVxW31TPe7JbBwMdvnGl7e6Q=</e:CipherValue> </e:CipherData> </e:EncryptedKey> </KeyInfo> <xenc:CipherData> <xenc:CipherValue>.... whole bunch of base64 encoded data ....</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </t:RequestedSecurityToken> <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType> <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType> <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType> </t:RequestSecurityTokenResponse> 

<RequestedSecurityToken>元素包含一个<EncryptedData>元素。 EncryptedData元素由三部分组成:

1. EncryptionMethod,在我的情况下是aes256-cbc

 <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /> 

2. KeyInfo,在我的情况下,这是AESencryption密钥,但密钥已经使用ADFS中configuration的encryption证书encryption。 我们需要使用encryption证书的RSA私钥对密钥进行解密,并为我们提供可用于解密SAML安全令牌的AESencryption密钥/密码:

 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> </e:EncryptionMethod> <KeyInfo> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <X509Data> <X509IssuerSerial> <X509IssuerName>CN=token-signing, OU=SomeOrg, O=EvilCorp, L=Williston, S=VT, C=US</X509IssuerName> <X509SerialNumber>13135613350938963680</X509SerialNumber> </X509IssuerSerial> </X509Data> </o:SecurityTokenReference> </KeyInfo> <e:CipherData> <e:CipherValue>v6ueRi+G+s31b9RZxE1X8gfNWk6qC9EWimhmDQzLOl/9HQrToqcLRNVqpdocfAgAGp3RkyR9IcwED7PZkreNNzEYMN3pntqS1372Nk6EEYwJSVmWkXmsv4m+xeJvGPQrDIZOwlq22OBt0EAwXoq7LvkmF0s/uhB4TItD47iAsDOFThMpuPoYo0EDLgPWzHtrZqTsC33c10zKKgyynSJPAKaC/+a9mSc4uxq55njU4GLVP/p4FvubPF2U1j4I7ozRGGWsAD5iTGwIOIF7H/ftKoRGIoFen29Ud87mm00BrF0GSUzcxTX+isMfI+HWp8u9zaO1ZLge5+x12BJcVWOYwblTQ7IPWyCMmaUscGgQPZ82ROrMCbX2f6HcGHtl8rwzXbz/VfAZkkxXZAfq9NRjSIRcmVtwC4cjwPAAcwE6V8+lvFn/2dUgzSz9y5K4HpzWZc2jg91oyzhFV+5luC+NV2HPAtTshjWOWhAcVuZYdINfcU1rSHKirBtDPQjxEWcyxkGyrl6UfWq1sEDuaXBPVNWT9/jyjuf7Rzyxnype8SleTK197FnD+rq6NzG9H4MpTFwhgokiPx4/RONjog7I1qnNM5wFybJ5WvkSh+x1w1w7/CNGipJSXCy3swGuSgSF3LI1bUZSzL+JqhUmYq8EVxW31TPe7JbBwMdvnGl7e6Q=</e:CipherValue> </e:CipherData> </e:EncryptedKey> </KeyInfo> 

3. CipherData:使用AESencryption的SAML安全令牌。

 <xenc:CipherData> <xenc:CipherValue>.... whole bunch of base64 encoded data ....</xenc:CipherValue> </xenc:CipherData> 

这里是猴子修补passport-wsfed-saml2库的WsFederation.extractToken方法的代码:

 import WsFederation = require('passport-wsfed-saml2/lib/passport-wsfed-saml2/wsfederation'); import { createPrivateKey } from 'ursa-purejs'; import { createDecipheriv, randomBytes } from 'crypto'; import { DOMParser } from 'xmldom'; import { readFileSync } from 'fs'; const tokenSigningKey = createPrivateKey(readFileSync('./certs/token-signing.pem')); const parser = new DOMParser(); WsFederation.prototype.standardExtractToken = WsFederation.prototype.extractToken; WsFederation.prototype.extractToken = function (this: any, req: string) { const token: Element | null = this.standardExtractToken(req); // Is the SAML token encrypted? if (!token || token.nodeName !== 'xenc:EncryptedData') { // no. return it. return token; } // We need to decrypt the SAML token... // Grab the CipherValue elements. There will be two: // 0. The encryption key for the SAML token, encrypted by ADFS using the rsa-oaep-mgf1p // algo and the public key of the encryption certificate configured in the relying party. // 1. The SAML token, encrypted using the aes-256-cbc algo with the key from #0 ^^^ const ciphers = token.getElementsByTagNameNS('http://www.w3.org/2001/04/xmlenc#', 'CipherValue'); const aesPasswordCipher = <string>ciphers[0].textContent; const samlTokenCipher = <string>ciphers[1].textContent; // Decrypt the password for the SAML token. const aesPassword = tokenSigningKey.decrypt(aesPasswordCipher, 'base64'); // Decrypt the SAML token. const decipher = createDecipheriv('aes-256-cbc', aesPassword, randomBytes(16)); let saml = decipher.update(new Buffer(samlTokenCipher, 'base64'), 'binary', 'utf8'); saml += decipher.final('utf8'); // Parse the XML and return the token. return parser.parseFromString(saml); }; 

有用的链接: https : //coolaj86.com/articles/asymmetric-public–private-key-encryption-in-node-js/