OpenAMでSAMLアサーションを暗号化する


SAML アサーションの暗号化とは?

弊社OSSテクノロジではOpenAMの開発とサポートを行っています。
SAMLといえばOpenAM、OpenAMといえばSAMLという訳ではありませんが、SAMLについて少し書きます。

SAMLアサーション?

SAMLについては、今更詳しく書くことはしませんが、サラッと関連事項だけフォローしておきます。
SAMLとはフェデレーション(シングルサインオン)に使われているプロトコルで、G-SuitesやOffice365、Salesforce、AWSなど主要なクラウドサービスでサポートされています。
SAMLにはIdP(認証サーバー)と、SP(認証を依頼し、認証情報を使うアプリケーションサーバー)の2役ありまして、このIdPからSPへ流れる認証情報をアサーションと呼んでいます。
SAMLアサーションはXML情報なので、暗号化にはXMLの暗号化規約xmlencを利用しています。

暗号化しない時のSAMLアサーションをFirefoxのアドオン SAML-tracer で見てみます。

いたって普通のXMLです。
SAMLアサーションの暗号化はこのXMLの大事な部分を暗号化してしまおうとういことです。

XML 暗号化の仕組み

ではどのようにXMLを暗号化するかというと、2種類の暗号方式が使われています。

公開鍵暗号方式

IDPからSPへ渡される共通鍵を暗号化するのに使います。
共通鍵暗号方式に比べて計算に時間がかかるため、SAMLアサーション全体を暗号化するのではなく、共通鍵のみを暗号化するのに使われます。
暗号に使った共通鍵は、IdPがSPの公開鍵で暗号化してSAMLアサーションと一緒に送ります。

共通鍵暗号方式

SAMLアサーションを暗号化するのに使います。
公開鍵暗号方式にくらべて計算時間が短いため、SAMLアサーション全体を暗号化するのに使われます。

SAMLアサーションの暗号化を試して見る

SAMLアサーションの暗号化がわかったところで、設定して試してみます。

OpenAMでのSAMLアサーション暗号化の設定

特に難しいことはありません、以下のチェックボックをチェックするだけです。

先程と同じように暗号化した時のSAMLアサーションをFirefoxのアドオン SAML-tracer で見てみます。

画像だと分かりにくいので、一部抜粋します。
先程説明しました2種類の暗号化方式が使われています。


共通鍵暗号方式(SAMLアサーションの暗号)
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" /> 
公開鍵暗号方式(共通鍵の暗号)
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> 

あぁ...エラー

若干上の説明でネタバレしてますが、今回SPに使ったソフトウェアはshibbolethです。
OpenAMからのSAMLアサーションを受けた時に、以下のエラー画面が出ます。

HTMLのエラーメッセージだけでは詳細が分からないので、/var/log/shibboleth/shibd.logをみるとshib.logxmlenc#rsa-1_5 は許されないぞと...復号化時にエラーになってます。

2018-11-30 16:44:30 WARN XMLTooling.Decrypter [2] [default]: XMLSecurity exception while decrypting key: XSECAlgorithmMapper::mapURIToHandler - URI http://www.w3.org/2001/04/xmlenc#rsa-1_5 disallowed by whitelist/blacklist policy

機能が無いならコードを追加すればいいじゃない

パンが無いならケーキを食べればいいじゃないの法則

RSAES-PKCS1-v1_5は無しの方向で...

SAMLアサーションの暗号化はあまり人気が無い技術で、いろいろなWebサービスでは「SAMLの暗号化はオフにすること」なんて注釈があったりしますが、、、
RSA-1.5が許されない世界なら、RSA-OAEPを使えるように改造するのです。

とりあえず、コードを見てみるのです。
OpenAMのコードでは以下のような実装です。RSAなら1.5決め打ち。
FMEncProvider.java


  if (publicKeyEncAlg.equals(EncryptionConstants.RSA)) {

    cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);

  } else if ...

後方互換性を気にしないで、単純にRSA-OAEPにしたいだけなら以下のようにするのもアリです。


  if (publicKeyEncAlg.equals(EncryptionConstants.RSA)) {

    cipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP);

  } else if ...

弊社はアップデートするお客様までフォローする必要があるので、高度な設定にuseRSAOAEPという設定を追加して、そのパラメーターが true だったら RSA_OAEPで暗号化するようなコードとします。


  if (publicKeyEncAlg.equals(EncryptionConstants.RSA)) {

    if (useRSAOAEP) {
      cipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP);
    } else {
      cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
    }

実食というかテスト

いままでと同じように、暗号化時のSAMLアサーションをFirefoxのアドオン SAML-tracer で見てみます。

スクリーンショットでは分かりにくいので抜粋します。
公開鍵暗号方式がrsa-oaep-mgf1pに変わったのがお分かりいただけるだろうか?


共通鍵暗号方式(SAMLアサーションの暗号)
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
公開鍵暗号方式(共通鍵の暗号)
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" />

機能が欲しければ自分で書く、オープンソースの基本ですね。おはり