SAML Response の x.509 電子署名から公開鍵を取り出してみる。

#はじめに

まず今回の検証を行うにあたって、Twitter アカウント名「@angel_p_57」さんの多大なるご協力のお陰であることを、お礼申し上げます。
大変勉強になりました、ありがとうございました。

以前 SAML 2.0 プロトコルのシングル サインオンの流れを以下記事でご紹介しました。

SP-Initiated と IdP-Initiated の動作の違いを Fiddler を見ながら確認してみる
URL:https://qiita.com/Shinya-Yamaguchi/items/434fab8c39e806e69a88

SP-Initiated を例にシングル サインオンの動作を以下のとおり記載します。

1.ユーザーがブラウザーを使って、 SP (Service Provider) にアクセスします。 具体的には Azure AD の下記 サインオン URL にアクセスしに行きます。 
2.SP (Service Provider) はアクセスしてきたユーザーが Azure AD ユーザーかどうかを確認します。
3. SP (Service Provider) が SAML Request と共に、ユーザーを IdP (Identity Provider) にリダイレクトさせます。
4. リダイレクトされた IdP 側で Azure AD ユーザーがサインインしていない場合は Azure AD が認証を要求し、認証に成功した場合、署名をした SAML Response をユーザーに渡します。
5. 署名された SAML レスポンスは、ユーザーが利用しているブラウザを通して、 SP 側に渡されます。
**6. SAML Response を受け取った SP側で SAML Response の内容をチェックします。**
7. SAML Response の内容が、 SP 側が要求した SAML Request の要件を満たしていれば、 SP 側がユーザーにサインオンの許可を与えます。

Azure AD が公開している公開鍵は、各エンタープライズ アプリケーションのシングル サインオンの設定の中にある、XML 形式のフェデレーション メタデータの中に格納されていますが、今回は、Azure AD が 署名した SAML Response の中から公開鍵を抽出したいと思います。

なお、Azure AD の電子署名は下記画面ショットにあるとおり SHA-256 で暗号化しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/da480610-d822-b1f8-04d5-9446822cc348.png)

#やってみる
今回は、以前 G Suite と SAML 連携した際に Fiddler で取得した SAML Response を使います。
下記が電子署名に該当する XML ファイルになります。

```xml

    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
      <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
        <Reference URI="#_36418bbf-d56a-49af-9c36-7636daa05600">
          <Transforms>
            <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
          </Transforms>
          <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
          <DigestValue>ywyIBhjthSa5WE8jZWYbrrUDiIkBpt9hs6rOqixX0Vw=</DigestValue>
        </Reference>
      </SignedInfo>
      <SignatureValue>Qa7yaV94uaWB8ImTH0KqPWyFDDb33bnUEiEPXH07guwVgxhK1To1F9ipgzNUHpkPei/WHc1LEgcj9e9Ycb2bgOTN77YnbldzKXM1SekVguEV/gsTjfJQL7xWpZvowi9r9E/2Gik24o8m1IxzYOYXHGQhpN/Qt6QTq/yx7PloCL+HLJ0BBHl3kPafDtpCYvyvZotRS5t+JrdeqzjfDLN0DT+BupNmCZMr55Bz575whpzPn58uhw2KOxYFV/TjPDw2QciI1LNqvJ02VHFbkMwMKQ49nTTpXxe+B1SGET+iHJJ8TyCXVbVUC3LXMgk/Mo53xfXkK4iP4G5T41jO5x+7Zw==</SignatureValue>
      <KeyInfo>
        <X509Data>
          <X509Certificate>MIIC8DCCAdigAwIBAgIQGkCPLLSyf65KbiYXgJVFdjANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDEylNaWNyb3NvZnQgQXp1cmUgRmVkZXJhdGVkIFNTTyBDZXJ0aWZpY2F0ZTAeFw0xOTA4MTUxMjM0NTNaFw0yMjA4MTUxMjM0NTNaMDQxMjAwBgNVBAMTKU1pY3Jvc29mdCBBenVyZSBGZWRlcmF0ZWQgU1NPIENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiXHZdwwrsj9ZpvUFZjAUiBYpxvXZsfMJVr7PhK3b/ICOmBQrRfunE3rphjTsMFmOgGJY4IyOkpUOd4a9JNJjVujpvHsh932tZejx83daPDGT+CJ5GXOsqsFandeklmpzwUr9ezbpjC9/55A+5v6A+5gQnllhgHCqP14G95bGqi6FGlWjVT6Ssb49TY+UmLUGfItyPgvM3A4oYtEenGcKnqJN5mSwDjSA8FTumb2eZ1fEuAnNMi6z2htA9Eg7cWrB1jbDFTOjBxsKGI4PQ5ikqjqG7BNWxAKCwBi/sziivT0+Pts2ju9uHqZVC1e/a57WaA/0toVQNeVbW0TjslpQPwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBqVQGP7BjsxDirn9vA9pQutnyhm5IXxuH8lYmUPhmkfli+aFqX+DyAdYeEj1PxUbDJsM9raaUxypCSQcSCBjRUlPYA0Lo2RTLLE2gTdX6+gW4WB2n6GF0a9Y72eN72gtlxDCC8SSeU4f69oex8aIgxcZmYgAxB0qfBzYVKlmeNLRAzD9OlCCtiKCSMpNXKnDI31CKzPoAID/fS6kKFYDa2i0bEnjGvpBIyUmkcPUm2j4gSxrTr3th+Z98x17LZQMpVBlY3+YTGQ3ARRXgVtyD1KF6izGIaWAwxrVi1Ztt2GFd4aFswHu6AyEKGD9/Pg8HfxN5i2VBktyvcpBSz8B5d</X509Certificate>
        </X509Data>
      </KeyInfo>
    </Signature>
```

さらに絞り込んで、「\<X509Certificate> と\</X509Certificate>」で囲まれた電子署名の部分だけをコピーします。

```xml
  
<X509Certificate>MIIC8DCCAdigAwIBAgIQGkCPLLSyf65KbiYXgJVFdjANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDEylNaWNyb3NvZnQgQXp1cmUgRmVkZXJhdGVkIFNTTyBDZXJ0aWZpY2F0ZTAeFw0xOTA4MTUxMjM0NTNaFw0yMjA4MTUxMjM0NTNaMDQxMjAwBgNVBAMTKU1pY3Jvc29mdCBBenVyZSBGZWRlcmF0ZWQgU1NPIENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiXHZdwwrsj9ZpvUFZjAUiBYpxvXZsfMJVr7PhK3b/ICOmBQrRfunE3rphjTsMFmOgGJY4IyOkpUOd4a9JNJjVujpvHsh932tZejx83daPDGT+CJ5GXOsqsFandeklmpzwUr9ezbpjC9/55A+5v6A+5gQnllhgHCqP14G95bGqi6FGlWjVT6Ssb49TY+UmLUGfItyPgvM3A4oYtEenGcKnqJN5mSwDjSA8FTumb2eZ1fEuAnNMi6z2htA9Eg7cWrB1jbDFTOjBxsKGI4PQ5ikqjqG7BNWxAKCwBi/sziivT0+Pts2ju9uHqZVC1e/a57WaA/0toVQNeVbW0TjslpQPwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBqVQGP7BjsxDirn9vA9pQutnyhm5IXxuH8lYmUPhmkfli+aFqX+DyAdYeEj1PxUbDJsM9raaUxypCSQcSCBjRUlPYA0Lo2RTLLE2gTdX6+gW4WB2n6GF0a9Y72eN72gtlxDCC8SSeU4f69oex8aIgxcZmYgAxB0qfBzYVKlmeNLRAzD9OlCCtiKCSMpNXKnDI31CKzPoAID/fS6kKFYDa2i0bEnjGvpBIyUmkcPUm2j4gSxrTr3th+Z98x17LZQMpVBlY3+YTGQ3ARRXgVtyD1KF6izGIaWAwxrVi1Ztt2GFd4aFswHu6AyEKGD9/Pg8HfxN5i2VBktyvcpBSz8B5d</X509Certificate>
```

次に、コピーしたファイルを PC の任意のフォルダに、ファイル名「x509」として保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/d10dc098-6c69-b9e8-e459-20b9073697e5.png)

次に PowerShell を管理者として実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/284cf8b5-2d13-ceea-b55a-abb9b2220c90.png)

PowerShell にて「certutil -decode <入力ファイル> <出力ファイル> 」の形式でコマンドレットを実行します。
.der ファイルはバイナリ形式の証明書になりますが、Windows OS 上でダブルクリックすると閲覧できます。

```
PS C:\> certutil -decode x509.txt x509.der                                                                              
入力長 = 1008
出力長 = 756
CertUtil: -decode コマンドは正常に完了しました。
```
                                
出力された x509.der ファイルを見てみると、Azure AD で確認したように、sha256 で署名されていることが分かり、公開鍵が RSA 2048 bit の公開鍵であることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/75a9b73e-76ca-a6b5-cc7a-3901181c0917.png)

このx509.der 証明書から公開鍵を抽出するには、openssl コマンドを使います。
今回は CentOS 環境にインストール済みの openssl コマンドを使ってみます。

まず、WinSCP などのSCPできるツールを使って、作成したx509.cer 証明書を Linux OS にコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/6483cd10-3e53-8640-9ff8-7f2f772189d4.png)

test001ユーザーのホームディレクトリから root ユーザーのカレントディレクトリに移動後に、 openssl コマンドを実行します。

```
# mv /home/test001/x509.der ./
# openssl x509 -pubkey -noout -inform DER -in x509.der


-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiXHZdwwrsj9ZpvUFZjAU
iBYpxvXZsfMJVr7PhK3b/ICOmBQrRfunE3rphjTsMFmOgGJY4IyOkpUOd4a9JNJj
VujpvHsh932tZejx83daPDGT+CJ5GXOsqsFandeklmpzwUr9ezbpjC9/55A+5v6A
+5gQnllhgHCqP14G95bGqi6FGlWjVT6Ssb49TY+UmLUGfItyPgvM3A4oYtEenGcK
nqJN5mSwDjSA8FTumb2eZ1fEuAnNMi6z2htA9Eg7cWrB1jbDFTOjBxsKGI4PQ5ik
qjqG7BNWxAKCwBi/sziivT0+Pts2ju9uHqZVC1e/a57WaA/0toVQNeVbW0TjslpQ
PwIDAQAB
-----END PUBLIC KEY-----
```

すると、「-----BEGIN PUBLIC KEY-----」と「-----END PUBLIC KEY-----」に囲まれた公開鍵が抽出できました。
これが公開鍵の実体です。

実際に SAML Response からコピーした電子署名から、公開鍵を抽出するまでに実行したコマンドは下記 2 コマンドのみでした。

```
PowerShell 上で実行
certutil -decode x509.txt x509.der         

Linux OS 上で実行
openssl x509 -pubkey -noout -inform DER -in x509.der
```

#おわりに
今回は Azure AD が作成した SAML Response から公開鍵を抽出してみました。
この作業自体に特別な意味はないのですが、Azure AD とアプリケーションを SAML 2.0 で統合する中で行われている通信の中で、Azure AD が署名した内容をアプリケーションが検証する際に使っている公開鍵を実際に見てみることで、電子署名がされる意味の一端が垣間見えたのではないかと思います。

暗号化については暗号化だけで書籍が大量にあるくらい奥が深いものですが、今回の記事が少しでも暗号化に興味をもっていただけるきっかけになれば幸いです。