(上のアイキャッチ画像の無断転載・流用を禁止します。)
この記事は Apache License, Version 2.0で配布されている成果物を含んでいます。
こんにちは。
GMOグローバルサイン・ホールディングスCTO室でデジタルアイデンティティーのR&Dをしている神沼(@t_kanuma)です。
この記事ではSSI(Self-Sovereign Identity/自己主権型アイデンティティー)におけるJOSE(JSON Object Signing and Encryption)について述べます。
SSIを実装するHyperledger Indyエコシステムの要素の1つにHyperledger Ariesがあります。(Ariesの詳細はこちらの記事をご覧ください)AriesはIssuer、Holder、VerifierがそれぞれにP2Pでメッセージ(接続の確立からVerifiable Credentialの要求や発行、Proofの要求や送信など)を送受信する部分を担当します。このメッセージ送受信はDIDを前提として機能するDIDCommというAries独自のプロトコル仕様に則ります。具体的にはこのDIDCommにおけるJOSEの使われ方について述べます。
JOSE
JOSE(RFC7165)はIEFTが定める5つのRFC(JWS, JWE, JWK, JWA, JWT / RFC7515~7519)の集合です。アプリケーションのレイヤーで通信経路に中間者が入るタイプのシステムにおいて、通信内容となるメッセージオブジェクト自体をend to endでセキュア化(暗号化&署名)するために策定されました。
このタイプのシステムとして昔からあるメールではASN.1という規格を採用しています。ASN.1は開発者が扱いにくく普及せず、その後XMLベースの仕様も上手く広まらず最終的にWebと非常に相性が良い、軽量で扱いやすいJSONをベースに策定された歴史があります。
ユースケース
OAuthにおいてアクセストークンをセキュア(署名でのJWS、場合によってはNested JWT)にするためにJOSEを使うケースというのは多々あると思います。この場合、クライアントが中間者として認可サーバとリソースサーバの間に入ります。OAuthを発展させたOIDC(Open ID Connect)におけるアクセストークンに関しても同様だと思います。またOIDCにおいてはIDトークン、ユーザー情報をJWSにすること(オプションでNested JWT)が仕様になっています。
昨今ではそれだけでなく(SPA、モバイルアプリを含む)APIクライアントとプロバイダーの2者間のシンプルなAPI認証においてもRESTfulにするため、すなわち認可情報をクライアント側で保持してAPIをステートレスにするためアクセストークン(MACでのJWS)に利用するケースも多々あると思います。さらにIoTにおいてもエッジでのデバイス認証に利用されるなど、昨今のモダンなシステムを支えるセキュリティ技術の1つとして広まっていると思います。
JWM(JSON Web Message)
DIDCommにおいてベースとなる平文メッセージの構造はJWMに従います。JWMは2021年8月現在においてJOSEの正式な仲間ではありません。まだIEFTのRFCになっておらずドラフトの状態です。
JWMはJWTと並んだ立ち位置で、同様にJOSEヘッダーと属性情報を保持しJWS/JWEに具現化されます。ただしその目的や仕様で予め登録されている属性名などは異なります。詳細はドキュメントをご参照願います。
DIDComm
DIDCommの仕様はバージョン1と2が存在します。バージョン1はHyperledger AriesのRFCであり、ACA-pyなど各種Aries Frameworkにて実装されています。
バージョン2は分散型IDを推進する標準化団体であるDIF(Decentraized Identity Foundation)の持ち物で現在はドラフトの状態です。これはHyperledger Indy以外のSSIシステムとも相互連携が可能になるように考慮されたものです。バージョン2の検証が済み次第、AriesのRFCもそれにアップデートされる模様です。
それではここからは、Apache License, Version 2.0で公開されているDIFによるDIDComm v2におけるJOSEをみていきます。
メッセージの種別
以下2. Message Typesの改変(翻訳と要約)です。
DIDCommメッセージは3つの種別に分類される。それらはDIDComm Plaintext Message(DIDComm平文メッセージ)、DID Signed Message(DIDComm署名付きメッセージ)、DIDComm Encrypted Message(DIDComm暗号化メッセージ)である。通常DIDCommメッセージと言う時は、3番目のDIDComm Encrypted Messageを指す。
DIDComm平文メッセージ
DIDComm平文メッセージは保護されたエンベロープに包まれておらず、秘匿性と完全性に欠陥がある、また否認可能である。通常はそのままでネットワークを流れることはない。通常、DIDComm上で機能するアプリケーションは、保護されたエンベロープからこの平文メッセージをアプリケーションデータとして取り出し処理する。
DIDComm署名付きメッセージ
DIDComm署名付きメッセージは、否認防止可能な署名とDIDComm平文メッセージを持つJWSである。
このメッセージ種別はメッセージの完全性を提供する目的において、または受信者に対し送信者の身元を保証する目的において必須の種別ではない。この両方は後述するDIDComm暗号化メッセージにて自動的に保証される事になる。
署名付きメッセージは以下の場合にだけ必要とされる。それは(暗号化はいらないが)第三者に平文の出所を証明したい場合、もしくはブロードキャストのユースケースなど事前に受信者を特定できず、DIDComm暗号化メッセージを使えない場合である。
その必要がない場合に署名を付けることはセキュリティを逆に下げることに繋がる。なぜならばそれは送信者の能力を無駄に曝け出し攻撃のリスクを高めるからだ。ゆえに我々はこの署名付きメッセージを使うケースは当たり前ではなく少数であると考える。
メッセージが署名と暗号化が同時に為される場合、平文は署名されてから暗号化される必要がある。反対の順序は、署名者が不透明なデータにコミットしたことを意味し、それは安全ではなく否認防止を弱めるものであるため、その順序では使われない。
DIDComm暗号化メッセージ
DIDComm暗号化メッセージは暗号化されたJWM、つまりJWEである。認められた受信者に送信者の身元を保証でき、その受信者のみがコンテンツを参照でき、そしてメッセージの完全性を保証する。プライバシー保護が必要な通信経路で重要になる。DIDCommアプリケーションにおいてネットワーク経路を移動する通常の形態であり、DIDCommをストレージに保管する状態においても最も安全な形態である。
平文の構造
以下3. Plaintext Message Structureの改変(翻訳と要約)です。主に前述のDIDComm平文メッセージに関連します。
3つのメッセージ種別の1つであるDIDComm平文メッセージはJWMをベースにする。その内容はヘッダー(メタデータ)とボディ(アプリケーションデータ)に大別される。ヘッダーは各メッセージで共通である。ボディは各メッセージ固有の属性を持つ。通常、受信者に送信される前にJWEとして暗号化される。
ヘッダーは事前に定義されている以下のようないくつかの属性を持つ。
- id : 必須。メッセージのID。1送信者の範囲で各メッセージのIDはユニークでなければならない。
- from : オプション。送信者のID。有効なDIDまたはDID URLでなくてはならない。
- to : オプション。受信者もしくは複数受信者のID。有効なDIDまたはDID URLの配列でなくてはならない。
- created_time : オプション。メッセージの作成日時。形式はエポック秒。
- expires_time : オプション。メッセージの有効期限。形式はエポック秒。指定しない場合は無期限になる。
メッセージへの署名
以下6. Message Signingの改変(翻訳と簡易な要約)です。主に前述のDIDComm署名付きメッセージに関連します。
DIDComm平文メッセージには、暗号化と同時に、もしくは暗号化せずに署名することができる。DIDComm暗号化メッセージは否認可能であるため、否認防止を達成するために署名と暗号化の両方を施す際は、署名してから暗号化する順序でなくてはならない。この結果はNested JWMと呼ばれる。
送信者が否認防止機能を持つ電子署名をメッセージに施す際は、JWAで定義された以下のアルゴリズムをJWSの構造に則り利用できる。この仕様の実装は以下の全てのアルゴリズムを検証できなければならない。また署名に関して最低でも以下のうち1つのアルゴリズムをサポートしていなければならない。(#)
(#) サポートするアルゴリズムは原文を参照願いします。
メッセージの暗号化
以下5. Message Encryptionの改変(翻訳と要約)です。主に前述のDIDComm暗号化メッセージに関連します。
JWMの暗号化された形態はJWEである。相互運用性の目的からDIDCommはJWAのサブセットをサポートする。(#)
DIDComm暗号化メッセージにはコンテンツ暗号化鍵(CEK)を生成・共有するためにJWAのドラフトで定義されているECDH-1PUをJOSEヘッダーの”alg”属性に指定しなければならない。
(#) サポートするアルゴリズムは原文を参照願いします。
スペックの全体を読んだ上での個人的な意見、考察のまとめ
- DIDComm通信を行う2つのEntityは、最初にPublic DIDまたはPeer DIDの公開鍵、もしくは一時的な公開鍵を元に、Peer DID Documentを、DIDCommを通して交換する。
- 2つのEntityは互いに交換した公開鍵を用い鍵交換を行い、DIDComm本文を暗号化するCEK、それを暗号化するKEKを生成しCEKを暗号化する。
- そのアルゴリズムはECDH-1PU+A256KWである。
- 鍵交換の公開鍵はDID DocumentのkeyAgreementプロパティのそれを使う。
- 暗号化されたCEKはJWE上のrecipients[].encrypted_keyプロパティに該当する。
- recipients[].header.kidプロパティには送信先のDID Dcoument上の公開鍵IDが記載される。それにより受信者はどの鍵を使えばよいかわかる。
- protected.skidプロパティには送信者のDID Document上の公開鍵IDが記載される。これにより受信者は、鍵交換からKEKを算出し、CEKを復号し、DIDComm Plaintextを復号することができる。
- Content EncrptionとAuthentication TagのアルゴリズムにはA256CBC-HS512を使う。
- JWEの仕様通り、Authentication TagはJWE本文(DIDComm Plaintext/JWM)とprotectedヘッダーに対し、非改竄性担保のために作られる。
- DIDCommではNested JWMではなくJWEを採用することで通信の効率化を図っている。
- Nest JWMとは異なり、JWEは否認ができる。
- 受信者が第三者に送信者を証明する場合や、送信者にとって受信者が信頼できない匿名の場合にのみ、電子署名が含まれるNested JWM(JWMをJWS化してJWE化する)を使う。
- Nested JWMは暗号化、改竄検知、送信者認証、否認防止の全てを達成できるが、そのネスト構造とそれによるサイズの増大から、毎回のネットワーク通信と計算のオーバヘッドが大きく非効率である。
- 以上をまとめると、DIDCommメッセージと言った場合、通常DIDComm Encrypted Messageを指す。ただし場合によってはオプションでメッセージをJWS、もしくはNested JWMにして送受信することも可能である。
これからもDIDCommの進展を注視していきたいを思います。