LoginSignup
11
6

More than 3 years have passed since last update.

[CWT入門その2] CBOR Object Signing and Encryption (COSE)

Last updated at Posted at 2019-12-21

どーも、ritouです。

アドカレ

これは認証認可技術 Advent Calendar 2019 21日めの記事です。
次回は gebo さんが CTAP のお話を書いてくれるようです。楽しみですね!

概要

個人的なモチベーション低下により第1弾からだいぶ期間が空いてしまいましたがこの投稿はCBOR Web Token(CWT)入門3部作の第2弾という位置付けです。

[CWT入門その1] CBORによるオブジェクトのバイナリ表現 では、CBORの概要を紹介しました。
これは2018年03月の投稿ですが、最近はWebAuthn以外にもCBORが使われているようで時代が追いついてきたな!って感じですね。

今回は、シリアライズにCBORを用いた署名、MAC値計算、暗号化の処理が定義されているCOSEの立ち位置と一部の機能を紹介します。
WebAuthnではCBORによるエンコードと共に、COSEの鍵表現が使われていることをご存知の方もいらっしゃるでしょう。

CBOR vs JSONと言う比較の流れで、今回の比較対象としてはJavascript Object Signing and Encryption(JOSE)となります。JOSEはたくさんのRFCがあることで有名です。
Javascript Object Signing and Encryption (jose) Documents
この記事では、JOSEとの比較を用いて説明していくため、JOSEに関する知識があるのが望ましいかもしれません。

COSEの仕様は、たった1つです。
RFC 8152 - CBOR Object Signing and Encryption (COSE)
JOSE相当の内容が詰め込まれていることもあり、当然ながら仕様自体は結構なボリュームです。

RFC8152の目次とJOSEの仕様の対応表を無理やり作ってみると

COSE 内容  JOSE
Signing 署名付きオブジェクト JSON Web Signature(JWS) の RSA/ECDSA あたり
Encryption コンテンツを暗号化したオブジェクト JSON Web Encryption(JWE)
Message Authentication Code (MAC) (MAC値を用いた)署名付きオブジェクト JWS の HMAC あたり(細かいところは微妙に違う)
Algorithms 使用されるアルゴリズム JSON Web Algorithm(JWA)
Key 鍵の表現 JSON Web Key(JWK)

のようになります。

JOSE の JWS 相当の Signing と MAC が分離されているなど、COSE と JOSE で異なる部分はありますが、大体のイメージはつかめるのではないでしょうか。

この記事では

  • Signing, MAC : JSON Web Signature相当のことができそうなやつ

について、

  • Structure : どのような構成になっているか
  • Algorithm : 対応するアルゴリズム
  • Key : 鍵の表現方法

という視点から紹介します(Encryptはしんどいのでやめた)。

Basic COSE Structure

全てのCOSEのメッセージは、CBORの配列形式となっており、先頭からの3要素は共通です。

  1. バイナリ文字列で表現された protected header の集合. 暗号処理に関わるパラメータ
  2. Map で表現された unprotected header の集合
  3. 平文(Signing, MAC)もしくは暗号化された(Encryption)メッセージの内容

その後ろの要素については、メッセージの種類(Signing, MAC, Encryption)により異なります。

ちなみに、JOSEでも、JWSとJWEで "." でつなぐ文字列の数が違ったりしますね。

Message Identification

COSEメッセージの種類を識別する方法が定義されています。

  • CBOR tag付きメッセージ
  • application/cose + cose-type

CBOR TagがついていればCBORメッセージ単体で識別できますが、ついていない場合はHTTP Headerの Content-Type のように指定することで識別できます。

あとはConstrained Application Protocol(CoAP)というプロトコルでの使われ方も定義されていますが、省略します。

Signing

COSEでは、2種類の署名付きオブジェクトが定義されています。

  • COSE_Sign : 1つのコンテンツに対する複数の署名を含む形式。 JOSE で言う所の JWS JSON Serialization
  • COSE_Sign1 : 1つのコンテンツに対して1つの署名を含む形式。 JOSE で言う所の JWS Compact Serialization

JOSEの現状を見ても、COSEが使われるようになっても、まずは COSE_Sign1 の方からかなーと思っています。

Signing Objects

上述の通り、オブジェクトは CBOR の配列となります。
COSE_SignCOSE_Sign1 を識別するために、異なるCBOR Tagが用意されています。

  • COSE_Sign : 98
  • COSE_Sign1 : 18

COSEの仕様では、CDDL(Concise data definition language)と言う表現方法を用いてオブジェクトの構成を表現しています。

COSE_Sign から見ていきます。

# COSE_Sign 用の CBOR Tag は 98
COSE_Sign_Tagged = #6.98(COSE_Sign)

# ヘッダー、ペイロード、署名のリストで構成される
COSE_Sign = [
  Headers,
  payload : bstr / nil, # payload を分けて送る場合は nil
  signatures : [+ COSE_Signature]
]

# 個々の署名もヘッダー、署名部分から構成される
COSE_Signature =  [
  Headers,
  signature : bstr
]

COSE_Sign1 はシンプルです。

# COSE_Sign1 用の CBOR Tag は 18
COSE_Sign1_Tagged = #6.18(COSE_Sign1)

# ヘッダー、ペイロード、署名から構成される
COSE_Sign1 = [
  Headers,
  payload : bstr / nil,
  signature : bstr
]

JSON Web Signature でもよく使われているシリアライズ方式なので、理解しやすいかと思います。
仕様に記載されているサンプルも見てみましょう。

# C.2.  Single Signer Examples - C.2.1.  Single ECDSA Signature
18(
  [
    / protected / h'a10126' / {
        \ alg \ 1:-7 \ ECDSA 256 \
      } / ,
    / unprotected / {
      / kid / 4:'11'
    },
    / payload / 'This is the content.',
    / signature / h'8eb33e4ca31d1c465ab05aac34cc6b23d58fef5c083106c4d25a91aef0b0117e2af9a291aa32e14ab834dc56ed2a223444547e01f11d3b0916e5a4c345cacb36'
  ]
)

構成としては

  • CBOR Tab : 18
  • Headers
    • protected : 署名生成に用いるアルゴリズムを指定. key/value ともに一意に決められた 整数 で表現されている
    • unprotected : kid の値はこちらに含まれる
  • paylaod : バイナリデータ
  • signature : バイナリデータ

となっています。
実際にどんな値になるかについては、cbor.me を用いてエンコードすることで確認できます。


# 注釈を省略したCBOR Object
18(
  [
    h'a10126',
    {4:'11'},
    'This is the content.',
    h'8eb33e4ca31d1c465ab05aac34cc6b23d58fef5c083106c4d25a91aef0b0117e2af9a291aa32e14ab834dc56ed2a223444547e01f11d3b0916e5a4c345cacb36'
  ]
)

# cbor.me でエンコード
D2                                      # tag(18)
   84                                   # array(4)
      43                                # bytes(3)
         A10126                         # "\xA1\x01&"
      A1                                # map(1)
         04                             # unsigned(4)
         42                             # bytes(2)
            3131                        # "11"
      54                                # bytes(20)
         546869732069732074686520636F6E74656E742E # "This is the content."
      58 40                             # bytes(64)
         8EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36 # "\x8E\xB3>L\xA3\x1D\x1CFZ\xB0Z\xAC4\xCCk#\xD5\x8F\xEF\\\b1\x06\xC4\xD2Z\x91\xAE\xF0\xB0\x11~*\xF9\xA2\x91\xAA2\xE1J\xB84\xDCV\xED*\"4DT~\x01\xF1\x1D;\t\x16\xE5\xA4\xC3E\xCA\xCB6"

# 注釈を省略したBase16エンコードされた値
D28443A10126A10442313154546869732069732074686520636F6E74656E742E58408EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36

署名の生成方法については後述します。

Signature Algorithms

JSON Web Algorithm でいう所の RSXXX, ESXXX 系に対応している部分です。
RFC8152 にて定義されている署名生成向けアルゴリズムは以下の通りです。

Name Value Hash Description
ES256 -7 SHA-256 ECDSA w/ SHA-256
ES384 -35 SHA-384 ECDSA w/ SHA-384
ES512 -36 SHA-512 ECDSA w/ SHA-512
EdDSA -8 EdDSA

JWSで割と使われている RSXXX 系がありません。
COSE and JOSE Registrations for WebAuthn Algorithms にて以下の4つが追加で定義されています。

Name Value Hash Description
RS256 -257 SHA-256 RSASSA-PKCS1-v1_5 w/ SHA-256
RS384 -258 SHA-384 RSASSA-PKCS1-v1_5 w/ SHA-384
RS512 -259 SHA-512 RSASSA-PKCS1-v1_5 w/ SHA-512
RS1 -262 SHA-1 RSASSA-PKCS1-v1_5 w/ SHA-1

また、Web Authentication:
An API for accessing Public Key Credentials
Level 1
ではED256、ED512の値が定義されています。

Name Value Hash Description
ED256 -260 SHA-256 TPM_ECC_BN_P256 curve w/ SHA-256(Recommended: Yes)
ED512 -261 SHA-512 ECC_BN_ISOP512 curve(Recommended: Yes)

JWSと同等の表現ができそうですね。

Signing and Verification Process

COSE_Sign1 用の署名の生成/検証処理について紹介します。
Base64 URLエンコードした文字列を繋げただけなJWSとは異なり、それなりの正規化が必要です。
署名の生成/検証に必要な構造体は以下のものから構成されます。

  1. context : 署名のコンテキストを識別する文字列 : Signature1
  2. body_protected : protected ヘッダーの中身をCBORエンコードしたバイナリ
  3. external_aad : アプリケーション固有の追加データ的なやつをCBORエンコードしたバイナリ。CoAPとかで使うらしい。
  4. payload : payloadをCBORエンコードしたバイナリ
Sig_structure = [
  context : "Signature1",
  body_protected : empty_or_serialized_map,
  external_aad : bstr,
  payload : bstr
]

説明には body_protectedbstr っぽく書いてあったのにここでは empty_or_serialized_map ですね。なんでだろ...まぁいいか。

とりあえず、署名の生成手順は以下のようになります。

  1. Sig_structure を作成
  2. Sig_structure を CBOR エンコードしてバイト列(ToBeSigned)を生成する
  3. 署名生成アルゴリズムに K(鍵) と alg(アルゴリズム), ToBeSigned を渡して署名生成(バイト列)
  4. COSE_Sign1 オブジェクトの signature 部分にその値を配置

署名の検証手順

  1. Sig_structure オブジェクトを作成し、適切な値を埋める
  2. Sig_structure をCBOR エンコードしてバイト列を生成する
  3. 署名検証アルゴリズムに K(鍵) と alg(アルゴリズム), ToBeSigned, Signature を渡して署名検証を行う

Sig_structure さえ作ってしまえばこっちのもんだという感じなので、ハマりどころもそこになりそうです。

Message Authentication Code (MAC)

MAC値を利用する方を紹介します。最もシンプルなもので JWS の alg=HSXXX 相当となります。
システム内でバイナリデータの生成と検証を同じ場所で行うユースケースで使えるでしょう。

MAC Objects

MACの方では、Signingとは別の切り口で2種類のオブジェクトが定義されています。

  • COSE_MAC0 : 使用される鍵が暗黙的に知られて(共有されて)おり、受信者情報を含まない形式。
  • COSE_MAC : 受信者情報を含む形式。

例から見ていきましょう。COSE_MAC0 の例です。

   17(
     [
       / protected / h'a1010f' / {
           \ alg \ 1:15 \ AES-CBC-MAC-256//64 \
         } / ,
       / unprotected / {},
       / payload / 'This is the content.',
       / tag / h'726043745027214f'
     ]
   )

これは JWS で HSXXX を利用、kidすら使わないパターンと同等と言えます。
構造を見ていきます。

# COSE_Mac0 用の CBOR Tag は 17
COSE_Mac0_Tagged = #6.17(COSE_Mac0)

COSE_Mac0 = [
    Headers,
    payload : bstr / nil, # Payloadを分けて送る場合は nil
    tag : bstr, # Mac値が入る
]

これだけであれば、tag の計算方法だけわかれば検証もできますね。

受信者情報を含む COSE_MAC の方も見ていきましょう。

   97(
     [
       / protected / h'a1010f' / {
           \ alg \ 1:15 \ AES-CBC-MAC-256//64 \
         } / ,
       / unprotected / {},
       / payload / 'This is the content.',
       / tag / h'9e1226ba1f81b848',
       / recipients / [
         [
           / protected / h'',
           / unprotected / {
             / alg / 1:-6 / direct /,
             / kid / 4:'our-secret'
           },
           / ciphertext / h''
         ]
       ]
     ]
   )

recipients ってところが受信者情報で、COSE_MAC0との違いです。
構成も見ていきましょう。

# CBOR Tag
COSE_Mac_Tagged = #6.97(COSE_Mac)

# recipients が追加されている
COSE_Mac = [
   Headers,
   payload : bstr / nil,
   tag : bstr,
   recipients :[+COSE_recipient]
]

Signingの2種類の違いに比べるとこっちはあまり変わらない気もしますね。
興味がある方は recipients にどんな値が入るかなどを調べてみてください。

MAC値の計算方法

署名計算と同じような構造体を用いてMAC値を計算します。

MAC_structure = [
    context : "MAC" / "MAC0",
    protected : empty_or_serialized_map,
    external_aad : bstr,
    payload : bstr
]

計算手順も同様です。

  1. MAC_structure を作成
  2. MAC_structure を CBOR エンコードしてバイト列(ToBeMaced)を生成する
  3. MAC値の生成アルゴリズムに K(鍵) と alg(アルゴリズム), ToBeMaced を渡して署名生成(バイト列)
  4. COSE_MAC0 / COSE_MAC オブジェクトの tag 部分にその値を配置

検証もそれなりに似ています。

  1. MAC_structure オブジェクトを作成し、適切な値を埋める
  2. MAC_structure をCBOR エンコードしてバイト列を生成する
  3. 鍵を取得する
  4. MAC値の生成アルゴリズムに K(鍵) と alg(アルゴリズム), ToBeMaced を渡してMac値を生成する
  5. tag部分と比較

ここでもキモは MAC_structure の作成になりそうです。

MAC Algorithms

MAC値の計算に利用するアルゴリズムは、HMACとAES-CBC-MACをサポートしています。
ハッシュ関数、tagの長さによって4種類にわかれています。

Name Value Hash tag length Description
HMAC256/64 4 SHA-256 64 HMAC w/ SHA-256 truncated to 64 bits
HMAC256/256 5 SHA-256 256 HMAC w/ SHA-256
HMAC384/384 6 SHA-384 384 HMAC w/ SHA-384
HMAC512/512 7 SHA-512 512 HMAC w/ SHA-512

とりあえずHMACがあれば既存のJWS + HSXXX相当のことはできそうです。
AES-MACについても、鍵の長さ、tagの長さによって値がわかれています。

Name Value Key length tag length Description
AES-MAC128/64 14 128 64 AES-MAC 128-bit key, 64bit tag
AES-MAC256/64 15 256 64 AES-MAC 256-bit key, 64bit tag
AES-MAC128/128 25 128 128 AES-MAC 128-bit key, 128bit tag
AES-MAC256/128 26 256 128 AES-MAC 256-bit key, 128bit tag

Key

COSEにおける鍵の表現方法についても紹介します。
表現方法として、鍵単体を表す COSE_Key とそのリストである COSE_KeySet があります。

   COSE_Key = {
       1 => tstr / int,          ; kty
       ? 2 => bstr,              ; kid
       ? 3 => tstr / int,        ; alg
       ? 4 => [+ (tstr / int) ], ; key_ops
       ? 5 => bstr,              ; Base IV
       * label => values
   }

   COSE_KeySet = [+COSE_Key]
  • kty : 鍵の種類
    • OKP(1) :
    • EC2(2) :
    • Symmetric(4)
  • kid : JWSでもおなじみ kid
  • alg : ここまでで紹介したアルゴリズムの値
  • key_ops : 鍵の用途 sign, verify, MAC create, MAC verifyなど

これらの値を基本として、あとはアルゴリズムによって必要なパラメータを用いて表現されます。

WebAuthnの仕様でも説明があります。

{
  1:   2,  ; kty: EC2 key type
  3:  -7,  ; alg: ES256 signature algorithm
 -1:   1,  ; crv: P-256 curve
 -2:   x,  ; x-coordinate as byte string 32 bytes in length
           ; e.g., in hex: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d
 -3:   y   ; y-coordinate as byte string 32 bytes in length
           ; e.g., in hex: 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
}

↓

A5
   01  02

   03  26

   20  01

   21  58 20   65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d

   22  58 20   1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c

最初にWebAuthnの仕様見た時はなんだこの表現って思われたかもしれませんが、これでCOSEの鍵も怖くないですね!!!

JOSE との違い

COSE is not a direct copy of the JOSE specification.

とある通り、細かいところで COSE と JOSE には違いがあります。

  • JOSE は Sign/Encrypt の2種類だけど COSE は最初から Sign/Encrypt/Mac の3つに分かれている
  • CBOR Tagがついてたら一発で構造がわかる
  • MAC値を使うやつを署名と分離
  • バイナリエンコード(CBOR)を使う
  • 暗号化周り(省略)

というあたりの違いは、ここまでの紹介でもなんとなく理解いただけるかと思います。

実装、ライブラリ

最後に、実装はあるのかと気にされる方もいらっしゃるでしょう。
Githubのこのリポジトリをご覧ください。

https://github.com/cose-wg

色々リポジトリがありますが、標準化仕様と言えばとりあえずJavaでしょう。Javaのライブラリがあればとりあえずヨシ!
これを参考に、私の手元にはElixirのライブラリを作っていた記録がありますが、記憶がありません。どうやら途中で挫折した模様です。

あとは人気があるGoでの実装とかだと、Mozillaのパッケージが引っかかるのも興味深いですね。

年末年始の課題にいかがでしょうか?

まとめ

JOSEのバイナリ版であるCOSEの中でJSON Web Signature相当の部分について紹介しました。
既存のJWxを置き換えるわけではなく、JWxが適用しにくい「バイナリが飛び交うシステムで構造化されるデータをそこそこ小さめのデータに抑えてやりとりしたい」みたいなところで使えるんじゃないかと思います。

CWT入門などというタイトルでやってきましたが、最後は RFC7519 JSON Web Token (JWT) の CBOR 版である CBOR Web Token (CWT)について取り上げます。

[CWT入門その3] クレームもコンパクトに表現された CBOR Web Token (RFC8392)

内容は簡単なので大丈夫です。
ではまた!

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6