🥑

JWK(JSON Web Key)クイズ

2022/12/15に公開3

この記事は Digital Identity技術勉強会 #iddance Advent Calendar 2022 の15日目の記事です。

※ 1年ぐらい前に酔った勢いで書いて放置していたものを掘りおこして加筆したものです。クイズといっても単なる間違いさがしなので、気が向いたら暇つぶしにどうぞ。

はじめに

JWT好きな方々は、きっとJWKも好きですよね?

JWK(JSON Web Key)はざっくり言うと暗号処理で使われる鍵のJSON表現です。RFC7517として標準化されており、JWTの署名検証用の公開鍵のフォーマットとして、Web技術者には馴染みが深いと思います。昨今、OpenID Connect/OAuth 以外でも活用されており、例えば、ここ数年のコロナ禍の中、デジタルワクチン接種証明書の国際標準が突貫で策定されましたが、その2大規格(EUDCC, SMART Health Cards)のいずれにおいても検証鍵の公開にJWKS(JWK Set)エンドポイントが使われています(以下、日本のJWKSエンドポイント)。

https://vc.vrs.digital.go.jp/issuer/.well-known/jwks.json

ということで、今や社会インフラをも支える重要な鍵フォーマットとなったJWK。知っておいてよいレベルの基本的な仕様をクイズ形式でおさらいしてみましょう。

全7問、所要時間20分(目安)。30点とれたら十分です。60点とれたらすごいかも。

問題編

クイズは全てJWKの間違い探しです。間違いの定義は以下とします。3を問う場合は問題文に明記します("相互接続性が懸念される間違い")。

  1. 規格(RFC7517 など)に反している
    • 含まれるべき属性がない、含まれてはいけない属性がある、使い方が間違っているなど
  2. セキュリティ上の問題がある
  3. 規格に反しているとまでは言えないが、提示したJWKに対応する秘密鍵で署名したJWTの検証が通らない、あるいは通らない懸念がある
    • 規格の推奨(SHOULD, SHOULD NOT) に反している
    • 規格(RFC7517など)で言及されていない部分で相互接続性の問題がある

前提条件

解答のヒントも含まれていますので、以下はよく読んでください。

  • 問題中のJWKは、全てJWKS(JWK Set)エンドポイントで公開された公開鍵とします。含まれる公開鍵はすべて署名用途です。
  • 鍵本体(x属性など)を解析しなければならない問題はありません。
  • JWTの検証時刻は、この記事の公開タイミング2022-12-15T21:00(JST)とします。

第1問 ~ 初級(15点)

以下のJWKに含まれる間違い(1箇所)を挙げてください。

{
    "keys": [
        {
            "kid": "my-awesome-public-key-01",
            "kty": "EC",
            "crv": "P-256",
            "alg": "ES256",
            "use": "sig",
            "x": "1nDufOZdUAiI2YkK1mup3PRqpF82jphkExrXR5i1JBQ",
            "y": "FXKYVXwOp7GUke4U8pe0j8H9ukR2WrzS3_LhCrvcfIQ",
            "d": "Y_nNqi5wXHj2Aud3BW091SeZYNViXRwJ-8K1yKd_l5s"
        }
    ]
}

第2問 ~ 初級(15点)

以下のJWKに含まれる間違いを挙げてください。正確な指摘ができるに越したことはないですが、ざっくりな指摘が1点できれば良いです。

{
    "keys": [
        {
            "kid": "my-awesome-public-key-01",
            "kty": "RSA",
            "alg": "RS256",
            "use": "sig",
            "n": "o4hWSF-rtXeKI8J32sX3agnJZMyprxQWdmfkaL3jsLK13Yelk7ChlaKIPWU0GHU7Wh_Ce3aslUIb7KsU51Fo3olAVBVszjTYZFu5IIgKtZoni-r8NVHqcmT6JLGhoVGVRaPjEGudmCtxocgiWXGHucl14DChV6PAcPlcbcosNmeJ5z6ia8lp5det-KkjFTe0-EdWB2kTzZvEmbotbtPL-B0BH_jYqmmZWgCU_TZ76QgORiOPmN-GW5RrLOEkay-f-Sx6XGTZxC_heN6eT-Ql1KgGQnagRDOAmcKy4CJp2vmODR8LbOyZl22C8x5wR5Vzz-9NE_WIF0nHT1ivIFOOZQ",
            "e": "AQAB",
            "d": "nGQfN_meid33UvmAi811LoiLfIWp5RCN5tC2hGDNJkfSWziFZbeu4B5esnBdoOJET409_brhk6B0eiKmzA10ABY8We1fb9jj9R4u7miL7V6uYUXpysg7MQlWm87wpwkRe1cfKK3yOfuaIUD3cJh9V3TN8Qgw1FJ7EM-40Bpfq-pQiebd9kScYbDBgU6UpdEqGvvN_F1-t3e9cnKF8R3Az6L3MyCZzMP_1VU2ec06D-_js232SZr5wBaUoYGBw6v5EQLlm4uRfBVh830Nj13nYUMBdxFta_vxuVjyT7nQ4lKnr9UegsLNuIdNjzQG-u7YHO51Wz_4XpzhR14oWRQ7xQ",
            "p": "522lC3SOUd0cPamIQu1mzFIgSJO0zXaS2VhFw9rzvFN3EWzSCawfhURSA7Luf_zy8hNle7fc1ak7rztPbcJYU4kaUs-3s2uSh0OkjFFY-O22MTlSFy08SnUUWjOr6SANdZwXBvwFp_bHo2L5exaoVDbBWWFydAknMdXxesj7uVM",
            "q": "tOU_OTANjWxYkBlXsM0zZnHe2Y-cr6LWoEdXOPf-Qz3qBtODsBBCGEMIWeIMZiYVXWgupTFxUbSvi2XzOSLW_kmzX66Onhg_HxFr6f0GwUC2r0o7DTxkGmImpoGhs-nLY-0lSTJsYWeCRqWvF8Z4lBIScwwJQPNKUrLjM2FeSmc",
            "dp": "CBnIayw7RxZMRMRIZr9Ul9ZQFvpEm-SIo175oi9p1K-_PTbn6zrBJ7MKg-Khgo1iG6MeLER1UG1KD4ot75Ob7-CesUNgFMGxMVbmzZqTWLNJa1OsUe9dauXKPpYMcG6Uygcarz3nHMgAmPF_9hUG81uvTOeiT_l6C76HY1rhpM0",
            "dq": "X-RqiHE9retyYyjcAGA20Caq4J-tirmClsJarVthENogVfAIDewAbYYTRjp7IicsCjDxESbNkGd86yNnNLGQUIpXKPCKr6ngxCJjF03HJ-ibLv7loNWTpxzCql9rjcjwxY7vxgaRx2ysdbDcyXivcKbH2u7VdPXDP2WO5SzHZB8",
            "qi": "1Zo1K-2F34u9NGVS1FvWT1AYTCCpJgpmnRoQ-sFP20W5q_W2pXKniSFn1de7_swUrDf_gQmTOuWHlMwDfD_vJwaUElRlR6qVUjHaLTjWKQMYUnaVLJEUa6sgON1mYJ3agH-AYZqv1mWGpOt2yEvTisX6lkK5wWWyqKOJhHyTkK8"
        }
    ]
}

第3問 ~ 初級(15点)

以下のJWKに含まれる間違い(1箇所)を挙げてください。

{
    "keys": [
        {
            "kid": "my-awesome-public-key-01",
            "crv": "P-256",
            "x": "1nDufOZdUAiI2YkK1mup3PRqpF82jphkExrXR5i1JBQ",
            "y": "FXKYVXwOp7GUke4U8pe0j8H9ukR2WrzS3_LhCrvcfIQ"
        }
    ]
}

第4問 ~ 中級(15点)

以下のJWKに含まれる間違い(2箇所)を挙げてください。

{
    "keys": [
        {
            "kty": "EC",
            "alg": "ES384",
            "key_ops": [
                "sign"
            ],
            "x": "zM6neei8BONDCjSrRXndYt_-76UGsuOA9jDIq5_JQFzNbZV-s9pvFj80U50fHfN_",
            "y": "KW6AEiEtwskgPa2dFrC2OIfGBPnftulsmtg_q74208kKjPZmNEdDjM-54K993FmK"
        }
    ]
}

第5問 ~ 中級(15点)

以下のJWKに含まれる間違い(1箇所)を挙げてください。

{
    "keys": [
        {
            "kid": "my-awesome-public-key-01",
            "kty": "EC",
            "crv": "P-512",
            "alg": "ES512",
            "use": "sig",
            "x": "APkZitSJMJUMB-iPCt47sWu_CrnUHg6IAR4qjmHON-2u41Rjg6DNOS0LZYJJt-AVH5NgGVi8ElIfjo71b9HXCTOc",
            "y": "ASx-Cb--149HJ-e1KlSaY-1BOhwOdcTkxSt8BGbW7_hnGfzHsoXM3ywwNcp1Yad-FHUKwmCyMelMQEn2Rh4V2l3I"
        }
    ]
}

第6問 ~ 中級(15点)

以下のJWKに含まれる相互接続性が懸念される間違い(1箇所)を挙げてください。

{
    "keys": [
        {
            "kid": "my-awesome-public-key-01",
            "kty": "OKP",
            "crv": "Ed25519",
	    "alg": "EdDSA",
            "x": "iUoyaqv4Wy7RFOrUeilTnkUfzWHrPZVcL2RgrmvFWCY",
            "use": "sig",
            "key_ops": [
                "verify"
            ]
        }
    ]
}

第7問 ~ 中級(10点)

本題?です。以下のJWKに含まれる相互接続性が懸念される間違い(1箇所)を挙げてください。なお、x5c属性に含まれる3つ目のX.509証明書は、プライベートなRoot CA証明書として検証側に信頼されているものとします。

{
    "keys": [
        {
            "kty": "EC",
            "kid": "f1vhQP9oOZkityrguynQqB4aVh8u9xcf3wm4AFF4aVw",
            "use": "sig",
            "alg": "ES256",
            "x5c": [
	        "MIIByjCCAXGgAwIBAgIJAPZFN9WW4voaMAoGCCqGSM49BAMDMCIxIDAeBgNVBAMMF3ZjLnZycy5kaWdpdGFsLmdvLmpwIENBMB4XDTIxMTEyNTEyNTUxNloXDTIyMTEyNTEyNTUxNlowJjEkMCIGA1UEAwwbdmMudnJzLmRpZ2l0YWwuZ28uanAgSXNzdWVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEViKBgZ0f3pQKv+tSz653HUtIzCS8TVSNu1Hwi0tKpSnTXXvtqkpcfYeAZ+SfvVk8SWNaTRDZ9wTNjb9c58v9l6OBizCBiDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUiIXKUyT93YdyqsIjE8i5I1z8w0IwHwYDVR0jBBgwFoAU0cYt0sPpuIDBt7a9PD3qs9mOu7EwLgYDVR0RBCcwJYYjaHR0cHM6Ly92Yy52cnMuZGlnaXRhbC5nby5qcC9pc3N1ZXIwCgYIKoZIzj0EAwMDRwAwRAIgEwVdLdbPqMYqEsVltnsm3bI/Z6eibgMwYaNVZiu0r2sCIFebHk1i6ghWOQn+Q0+t5F77fasgJ3Oc6NWx9I8AWjRM",
                "MIIBkDCCATagAwIBAgIJAOECTZDa4MA7MAoGCCqGSM49BAMEMCcxJTAjBgNVBAMMHHZjLnZycy5kaWdpdGFsLmdvLmpwIFJvb3QgQ0EwHhcNMjExMTI1MTI1NTEzWhcNMjYxMTI0MTI1NTEzWjAiMSAwHgYDVQQDDBd2Yy52cnMuZGlnaXRhbC5nby5qcCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEL3S0yNIJ8EuxgiaHEvsjGWd60P0BBKUfVUVSxpVyGsnXwuzkS7OPGG/DT60m5XTvKT125MRuZoS/sajPBcg2KjUDBOMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFNHGLdLD6biAwbe2vTw96rPZjruxMB8GA1UdIwQYMBaAFPKN8VogQyX0IuxEi7jBB5gUnFinMAoGCCqGSM49BAMEA0gAMEUCIQCcq3H/pRMRkUmpWUDsggQXJAjLB/AutlHQigEBsVx0sgIgfVyc0L1cbRaDmdCQ3CGd994rRuwlQI0/cJCIv5LeI3g=",
                "MIIBlTCCATugAwIBAgIJANt2MZrWChe2MAoGCCqGSM49BAMEMCcxJTAjBgNVBAMMHHZjLnZycy5kaWdpdGFsLmdvLmpwIFJvb3QgQ0EwHhcNMjExMTI1MTI1NDUzWhcNMzExMTIzMTI1NDUzWjAnMSUwIwYDVQQDDBx2Yy52cnMuZGlnaXRhbC5nby5qcCBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEilfgw+JIG8TOliOLe7jufm2m0+HqL4t5nvBdQj3UMgh8jjl6VoVKKwcj3T1DWFinm6sCTWYUrPSXWcvOq64GbKNQME4wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8o3xWiBDJfQi7ESLuMEHmBScWKcwHwYDVR0jBBgwFoAU8o3xWiBDJfQi7ESLuMEHmBScWKcwCgYIKoZIzj0EAwQDSAAwRQIgQWnKyVhaKpu1WcXP49s9inaa5mnWgV/pCW31h/NIJnwCIQDSIHvGUuPwK+ofYqLJGo99hhwhfkIBWhvSo0vr5IGesg=="
            ],
            "crv": "P-256",
            "x": "ViKBgZ0f3pQKv-tSz653HUtIzCS8TVSNu1Hwi0tKpSk",
            "y": "01177apKXH2HgGfkn71ZPEljWk0Q2fcEzY2_XOfL_Zc"
        },
        {
            "kty": "EC",
            "kid": "5fGcRveDtGxLX2q_CjXLUOITyAR5KuVNsfe9TkjE86k",
            "use": "sig",
            "alg": "ES256",
            "x5c": [
                "MIIByzCCAXGgAwIBAgIJAPZFN9WW4vocMAoGCCqGSM49BAMDMCIxIDAeBgNVBAMMF3ZjLnZycy5kaWdpdGFsLmdvLmpwIENBMB4XDTIyMTAwNjA2MzU1M1oXDTIzMTIzMTA2MzU1M1owJjEkMCIGA1UEAwwbdmMudnJzLmRpZ2l0YWwuZ28uanAgSXNzdWVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMFzLPQDWyrJgioCAc3Agake1GNt7SPulfbOydJG2I7jTpjzc5c2PVXmYiAFQYGkyuwm+TjSegAC7zorVotXtSqOBizCBiDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU9K/DJIIekbNV+TBatIPYPgHLo84wHwYDVR0jBBgwFoAU0cYt0sPpuIDBt7a9PD3qs9mOu7EwLgYDVR0RBCcwJYYjaHR0cHM6Ly92Yy52cnMuZGlnaXRhbC5nby5qcC9pc3N1ZXIwCgYIKoZIzj0EAwMDSAAwRQIgDDOnvuHUa7s6o+EKLfqQw8wr6MhWoA0QhiduFA652dYCIQCb7Bfr/lIQc/VhpQcLUd7hloqChXm0m3tsgXYEogLxMw==",
                "MIIBkDCCATagAwIBAgIJAOECTZDa4MA7MAoGCCqGSM49BAMEMCcxJTAjBgNVBAMMHHZjLnZycy5kaWdpdGFsLmdvLmpwIFJvb3QgQ0EwHhcNMjExMTI1MTI1NTEzWhcNMjYxMTI0MTI1NTEzWjAiMSAwHgYDVQQDDBd2Yy52cnMuZGlnaXRhbC5nby5qcCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEL3S0yNIJ8EuxgiaHEvsjGWd60P0BBKUfVUVSxpVyGsnXwuzkS7OPGG/DT60m5XTvKT125MRuZoS/sajPBcg2KjUDBOMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFNHGLdLD6biAwbe2vTw96rPZjruxMB8GA1UdIwQYMBaAFPKN8VogQyX0IuxEi7jBB5gUnFinMAoGCCqGSM49BAMEA0gAMEUCIQCcq3H/pRMRkUmpWUDsggQXJAjLB/AutlHQigEBsVx0sgIgfVyc0L1cbRaDmdCQ3CGd994rRuwlQI0/cJCIv5LeI3g=",
                "MIIBlTCCATugAwIBAgIJANt2MZrWChe2MAoGCCqGSM49BAMEMCcxJTAjBgNVBAMMHHZjLnZycy5kaWdpdGFsLmdvLmpwIFJvb3QgQ0EwHhcNMjExMTI1MTI1NDUzWhcNMzExMTIzMTI1NDUzWjAnMSUwIwYDVQQDDBx2Yy52cnMuZGlnaXRhbC5nby5qcCBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEilfgw+JIG8TOliOLe7jufm2m0+HqL4t5nvBdQj3UMgh8jjl6VoVKKwcj3T1DWFinm6sCTWYUrPSXWcvOq64GbKNQME4wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8o3xWiBDJfQi7ESLuMEHmBScWKcwHwYDVR0jBBgwFoAU8o3xWiBDJfQi7ESLuMEHmBScWKcwCgYIKoZIzj0EAwQDSAAwRQIgQWnKyVhaKpu1WcXP49s9inaa5mnWgV/pCW31h/NIJnwCIQDSIHvGUuPwK+ofYqLJGo99hhwhfkIBWhvSo0vr5IGesg=="
            ],
            "crv": "P-256",
            "x": "MFzLPQDWyrJgioCAc3Agake1GNt7SPulfbOydJG2I7g",
            "y": "06Y83OXNj1V5mIgBUGBpMrsJvk40noAAu86K1aLV7Uo"
        }
    ]
}

解答・解説編

第1問

基本を問う問題です。署名に使われるキータイプ"RSA", "EC", "OKP"すべてに言えることですが、dを入れてはいけません。秘密鍵/秘密情報です。 一般教養としては、ここさえ押さえておけばいいかもしれません。

第2問

第1問のRSAバージョンです。RSA公開鍵の構成要素はn(modulus)とe(exponent)のみです。それ以外(d, p, q, dp, dq, qi)は秘密鍵の構成要素です。くりかえしますが、非対象鍵のJWKにおいてdが含まれるのは秘密鍵です。 ちなみにRSAのJWKを出題した意図としては、まだ主流で使われているキータイプであるということも勿論ありますが、第1問のECやあとで出てくるOKP(DJB氏のCurve25519)と比較して、鍵データがかなり大きい点を見て欲しかったというのがあります。

第3問

これは、JWKの共通パラメータの必須要素を問う問題です。必須なのはktyだけです。 kidあたりは必須にしておいてよかったんじゃないかとも思いますがオプションです。algもオプションにすぎません。公開鍵・秘密鍵の判別とあわせて、おさえておいてよい基本ポイントなので問題にしてみました。ちなみに現在、署名で使われるキータイプは "RSA", "EC", "OKP"の3つです。

余談ですが、この基本がおさえられていない有名な(よく使われる)OSS実装として PyJWT ってやつがあります。kty毎に鍵(というか鍵に紐づくアルゴリズム)を実装すべきところをそうできていないため内部実装がグダグダになっています。

第4問

(1) 署名によく使われるキータイプECOKPcrv属性が必須です。上記しましたが、alg属性は任意なんですよね。

(2) 間違えやすいポイントですが、useならば"sig"でも、key_opsでは"verify"です。useの方は、X.509のKey UsageのノリのdigitalSignature(デジタル署名)を表しており、key_opsの方はその鍵で行うオペレーションを表す動詞です。公開鍵は検証("verify")に使います。署名("sign")は秘密鍵でやるものですね。

第5問

しょうもない問題ですみません。alg=ES256はcrv=P-256、alg=ES384はcrv=P-384、なのに、alg=ES512はcrv=P-521 なんですよね。alg値のES512の意味は"ECDSA w/SHA512"でありハッシュの話であり、P-521は楕円曲線の話なので全然別です。

余談ですが、"P-512"って定義しちゃってた有名なOSSがあるんですよね。 PyJWT っていうんですけど。楕円曲線パラメータは、「P-512じゃなくてP-521」 はこの際、覚えておきましょう。

第6問

OKP (Octet Key Pair)関連の出題と思わせつつ、またkey_opsでした。すみません。仕様上はSHOULD NOTで必ずしも従う必要は無いのですが避けた方がよいです。どちらに絞るべきかと言うと、useかなと思います。OIDC/OAuth関連仕様(RFC8414など)に"暗号用途の鍵も含める場合にはuse属性が必須"という記載があるからなのか、前提条件を無視してuse属性を必須としているJWT実装もかつて存在したので(PyJWTっていうんですけどね)、入れておくのが無難です。

ちなみにCOSE_Key(バイナリ版のJWK)にはkey_opsしかありません。また、Web Cryptograph APIのCryptoKey にもkey_opsに対応する属性しかありません。

OKP(Octet Key Pair)(RFC8037: CFRG ECDH and Signatures in JOSE)について余談ですが、現在はエドワーズ曲線を使った署名アルゴリズム(Ed25519, Ed448)やECDH(X25519, X448)用につかわれるものというイメージが強いですが、本来OKPは、公開鍵、秘密鍵をそれぞれ単一のオクテット文字列(それぞれx値とd値)で表現するためのシンプルかつ汎用的なJWKという位置づけです(ただしcrv属性必須なので楕円縛りがあり、ポスト量子の非対称鍵に使えない問題があるのですが)。以下、規格に準拠した必要最小限のEd25519のJWKです。データサイズも小さくすっきりしていますね。鍵サイズが小さく、安全で高速処理できるので、NIST準拠(P-256など)である必要が必ずしもないケースにおいて今後は主流になっていくでしょう。

{
    "keys": [
        {
            "kid": "my-awesome-public-key-01",
	    "kty": "OKP",
            "crv": "Ed25519",
            "x": "iUoyaqv4Wy7RFOrUeilTnkUfzWHrPZVcL2RgrmvFWCY"
        }
    ]
}

第7問

JWKSは有効な公開鍵リストであるべきなので、期限切れの検証鍵を入れるのは問題ですよね。普通、有効期限が1年なのであれば、実際の利用期間は例えば半年ぐらいにして早めに鍵の切り換えを行う等、鍵のローテーションルールをしっかり定めて運用するべきなのかなと思います。

x5c値に含まれる証明書チェーンについてですが、こうした国レベルが管理している認証局としては、1つ目をDSC(Document Signer Certificate)、3つ目のルートCAを、CSCA(Country Signing Certificate Authority)と呼んだりします。1つ目のx5c値をdsc.pemとして保存してデコードしてみましょう。

openssl x509 -text -noout -in dsc.pem

以下が出力です。Not Afterの項目を見て頂ければわかるように既に無効になっていますね。2022年11月25日で切れています。

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            f6:45:37:d5:96:e2:fa:1a
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: CN = vc.vrs.digital.go.jp CA
        Validity
            Not Before: Nov 25 12:55:16 2021 GMT
            Not After : Nov 25 12:55:16 2022 GMT
        Subject: CN = vc.vrs.digital.go.jp Issuer
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:56:22:81:81:9d:1f:de:94:0a:bf:eb:52:cf:ae:
                    77:1d:4b:48:cc:24:bc:4d:54:8d:bb:51:f0:8b:4b:
                    4a:a5:29:d3:5d:7b:ed:aa:4a:5c:7d:87:80:67:e4:
                    9f:bd:59:3c:49:63:5a:4d:10:d9:f7:04:cd:8d:bf:
                    5c:e7:cb:fd:97
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature
            X509v3 Subject Key Identifier:
                88:85:CA:53:24:FD:DD:87:72:AA:C2:23:13:C8:B9:23:5C:FC:C3:42
            X509v3 Authority Key Identifier:
                keyid:D1:C6:2D:D2:C3:E9:B8:80:C1:B7:B6:BD:3C:3D:EA:B3:D9:8E:BB:B1

            X509v3 Subject Alternative Name:
                URI:https://vc.vrs.digital.go.jp/issuer
    Signature Algorithm: ecdsa-with-SHA384
         30:44:02:20:13:05:5d:2d:d6:cf:a8:c6:2a:12:c5:65:b6:7b:
         26:dd:b2:3f:67:a7:a2:6e:03:30:61:a3:55:66:2b:b4:af:6b:
         02:20:57:9b:1e:4d:62:ea:08:56:39:09:fe:43:4f:ad:e4:5e:
         fb:7d:ab:20:27:73:9c:e8:d5:b1:f4:8f:00:5a:34:4c

証明書チェーンを検証してみましょう。x5c値の2つ目、3つ目をそれぞれintermediate.pem, root.pem として —

$ openssl verify -CAfile root.pem --untrusted intermediate.pem dsc.pem
CN = vc.vrs.digital.go.jp Issuer
error 10 at 0 depth lookup: certificate has expired
error dsc.pem: verification failed

"error dsc.pem: verification failed"

ちなみに2つ目の(新しい)JWKの証明書を除いてみるとNot Beforeが今年の10月6日でした。この日までに発行された日本のデジタルワクチン接種証明書はすべて有効期限切れになってしまっているということですね。

特に問題が起きていないのは、検証側がx5c値をみていないのか、ワクチン接種証明書のアプリが自動で新しい証明書を取り直してくれるのか、そもそも誰も検証なんてしていないのか。アプリ入れてないので知りませんが。

おわりに

ということでクイズ形式に見せかけての日本のトラスト基盤disでした。他にも書きたいことや書くべきことが色々あるのに、一番しょうもないネタを取り上げてしまった気がして反省している。

Discussion

TikTakSickTikTakSick

第7問に関してご質問がございます.私の勘違いでしたら,申し訳ございません.
詳細は下記の通りです。

質問

  • 「ワクチン接種証明書のjwkの有効期限切れは、問題ない」のではないでしょうか?

  • 期限切れの検証鍵(jwk)は、既に発行された証明書検証のために必要であり、jwks内に残しておくべきではないでしょうか?

根拠・詳細

  • SHCの仕様において鍵(検証鍵)の管理に関しては、少なくとも一年毎に新しい検証鍵を再生する必要があります.

  • その一方で、それ以前に発行したワクチン証明書の検証を行うために、古い方の検証鍵は絶対jwks内に残しておく必要があるという旨の記載もされてます.

https://spec.smarthealth.cards/#key-management

  • したがって,デジタル庁のワクチン接種証明書用jwk(s)の管理に関しましては,問題ないと考えます.

※追記です.

  • 検証手順に,「有効期限切れでない&失効していない証明書パスの検証」が含まれていることから,鍵管理に関して私の方で解釈をミスしているかもしれません.

https://spec.smarthealth.cards/#certificates

dajiajidajiaji

コメントありがとうございます。まさか最後の問題までトライしてくれる人がいるとは!

その一方で、それ以前に発行したワクチン証明書の検証を行うために、古い方の検証鍵は絶対jwks内に残しておく必要があるという旨の記載もされてます.

すみません、原典をあたっていないのですが、この古い方の鍵というのは、"古いが有効期限内"の鍵のことではないでしょうか?

鍵ローテーションにおいては必ず重複期間を設ける必要があります。鍵の有効期間は1年でも、半年ごとに鍵を更新し、常に2個の鍵が有効になるように運用する等です。このような鍵のライフサイクル管理についてもEUDCCの公開文書では事例と共に記載がありました。

"古いが有効期限内"の鍵を指すと解釈すると、古い方の検証鍵は"絶対"jwks内に残しておく必要があるという記載や、"検証手順に,「有効期限切れでない&失効していない証明書パスの検証」が含まれている" という内容とも整合が取れると思います。また、仮に有効期限切れの鍵のことを指しているのだとすると、過去使われていたすべての鍵情報をjwksに含めなければならなくなり、運用や検証のプロセスが破綻するように感じます。

TikTakSickTikTakSick

ご返答ありがとうございます.大変,参考になりす。

古い方の鍵に関して,"古いが有効期限内鍵"と解釈するとうまくいくというのは,御尤もだと思いました。原典の方では,jwk鍵管理の詳細な記述がなかったため、困惑してました。

ちなみにですが、古い方の鍵に関する説明は,原典ですと下記の通りでOlder public key〜と表記されています.

Older public key entries that are needed to validate previously signed Health Cards SHALL remain in the JWK set for as long as the corresponding Health Cards are clinically relevant.

https://spec.smarthealth.cards/#certificates