[{"data":1,"prerenderedAt":104},["ShallowReactive",2],{"i-heroicons:building-office-2":3,"i-heroicons:computer-desktop":8,"i-heroicons:cloud":10,"i-heroicons:server":12,"i-heroicons:folder":14,"i-heroicons:chart-bar":16,"i-heroicons:lock-closed":18,"i-heroicons:rectangle-stack":20,"i-heroicons:scale":22,"i-heroicons:key":24,"i-heroicons:finger-print":26,"i-heroicons:cpu-chip":28,"i-heroicons:document-text":30,"i-heroicons:shield-exclamation":32,"i-heroicons:shield-check":34,"blog-ja-implementing-fido-u2f-ctap1":36,"i-heroicons:user":102},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 3.75h.008v.008h-.008zm0 3h.008v.008h-.008zm0 3h.008v.008h-.008z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25m18 0A2.25 2.25 0 0 0 18.75 3H5.25A2.25 2.25 0 0 0 3 5.25m18 0V12a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 12V5.25\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M2.25 15a4.5 4.5 0 0 0 4.5 4.5H18a3.75 3.75 0 0 0 1.332-7.257a3 3 0 0 0-3.758-3.848a5.25 5.25 0 0 0-10.233 2.33A4.5 4.5 0 0 0 2.25 15\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M21.75 17.25v-.228a4.5 4.5 0 0 0-.12-1.03l-2.268-9.64a3.375 3.375 0 0 0-3.285-2.602H7.923a3.375 3.375 0 0 0-3.285 2.602l-2.268 9.64a4.5 4.5 0 0 0-.12 1.03v.228m19.5 0a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3m19.5 0a3 3 0 0 0-3-3H5.25a3 3 0 0 0-3 3m16.5 0h.008v.008h-.008zm-3 0h.008v.008h-.008z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":17},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875zm6.75-4.5c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125zm6.75-4.5c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":19},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":21},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M6 6.878V6a2.25 2.25 0 0 1 2.25-2.25h7.5A2.25 2.25 0 0 1 18 6v.878m-12 0q.354-.126.75-.128h10.5q.396.002.75.128m-12 0A2.25 2.25 0 0 0 4.5 9v.878m13.5-3A2.25 2.25 0 0 1 19.5 9v.878m0 0a2.3 2.3 0 0 0-.75-.128H5.25q-.396.002-.75.128m15 0A2.25 2.25 0 0 1 21 12v6a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 18v-6c0-.98.626-1.813 1.5-2.122\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":23},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M12 3v17.25m0 0c-1.472 0-2.882.265-4.185.75M12 20.25c1.472 0 2.882.265 4.185.75M18.75 4.97A48 48 0 0 0 12 4.5c-2.291 0-4.545.16-6.75.47m13.5 0q1.515.215 3 .52m-3-.52l2.62 10.726c.122.499-.106 1.028-.589 1.202a6 6 0 0 1-2.031.352a6 6 0 0 1-2.031-.352c-.483-.174-.711-.703-.59-1.202zm-16.5.52q1.485-.305 3-.52m0 0l2.62 10.726c.122.499-.106 1.028-.589 1.202a6 6 0 0 1-2.031.352a6 6 0 0 1-2.031-.352c-.483-.174-.711-.703-.59-1.202z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":25},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M15.75 5.25a3 3 0 0 1 3 3m3 0a6 6 0 0 1-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1 1 21.75 8.25\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":27},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M7.864 4.243A7.5 7.5 0 0 1 19.5 10.5c0 2.92-.556 5.709-1.568 8.269M5.742 6.364A7.47 7.47 0 0 0 4.5 10.5a7.46 7.46 0 0 1-1.15 3.993m1.989 3.559A11.2 11.2 0 0 0 8.25 10.5a3.75 3.75 0 1 1 7.5 0q0 .79-.064 1.565M12 10.5a14.94 14.94 0 0 1-3.6 9.75m6.633-4.596a18.7 18.7 0 0 1-2.485 5.33\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":29},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M8.25 3v1.5M4.5 8.25H3m18 0h-1.5M4.5 12H3m18 0h-1.5m-15 3.75H3m18 0h-1.5M8.25 19.5V21M12 3v1.5m0 15V21m3.75-18v1.5m0 15V21m-9-1.5h10.5a2.25 2.25 0 0 0 2.25-2.25V6.75a2.25 2.25 0 0 0-2.25-2.25H6.75A2.25 2.25 0 0 0 4.5 6.75v10.5a2.25 2.25 0 0 0 2.25 2.25m.75-12h9v9h-9z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":31},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":33},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M12 9v3.75m0-10.036A11.96 11.96 0 0 1 3.598 6A12 12 0 0 0 3 9.75c0 5.592 3.824 10.29 9 11.622c5.176-1.332 9-6.03 9-11.622c0-1.31-.21-2.57-.598-3.75h-.152c-3.196 0-6.1-1.25-8.25-3.286m0 13.036h.008v.008H12z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":35},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M9 12.75L11.25 15L15 9.75m-3-7.036A11.96 11.96 0 0 1 3.598 6A12 12 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623c5.176-1.332 9-6.03 9-11.622c0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285\"\u002F>",{"id":37,"documentId":38,"title":39,"content":40,"slug":41,"published":42,"createdAt":43,"updatedAt":43,"publishedAt":44,"locale":45,"authorManual":46,"cover":47,"tags":98,"seo":99,"author":51},227,"dllpf0x03a12rb890iq23erd","いまさらながら FIDO U2F CTAP1 を実装してみた","\u003Cp>更新日：2021年6月23日\u003C\u002Fp>\n\u003Cp>\u003Cstrong>はじめに\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>今日は、大変いまさらながら U2F の Hostライブラリを作る機会がありましたので、U2F のスペックを読んでわかりにくかったことなどをまとめていきたいと思います。\u003C\u002Fp>\n\u003Cp>Host ライブラリと言っているのは、いわゆる FIDO Client(web ブラウザ) と Authenticator(YubiKeyなど） との通信をする部分で、通常 U2F 通信は Chrome や Firefox などのブラウザが担ってくれるため、我々がなにかプログラムを書く必要はありません。\u003C\u002Fp>\n\u003Cp>ただし、Webブラウザが利用できないようなネイティブアプリで FIDO認証を利用したい場合、今回のように Hostライブラリを作成する必要があります。（Windows Hello など、プラットフォームAPIでサポートされれば必要なくなります）\u003C\u002Fp>\n\u003Cp>正直、CTAP2 のスペックやサンプルが出てきている段階で、なぜ今更 U2F なんだと思われるかもしれませんが、デバイスと Authernticator の通信に関しては、CTAP2と似通った部分もあり、気になる方もいるのではないかと考えブログに纏めました。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>目次\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>・シーケンス\u003C\u002Fp>\n\u003Cp>・ホストライブラリがやっていること\u003C\u002Fp>\n\u003Cp>・U2Fデバイスとの通信\u003C\u002Fp>\n\u003Cp>・JavaScript API\u003C\u002Fp>\n\u003Cp>・Raw Message Format\u003C\u002Fp>\n\u003Cp>・APDU Format\u003C\u002Fp>\n\u003Cp>・HID Protocol\u003C\u002Fp>\n\u003Cp>・FIDO2について\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>シーケンス\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>まずはU2Fのシーケンス全体を確認してみましょう。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>登録時\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fblog_implementing_fido_u2f_ctap1_1_9d2672b151.png\" alt=\"\">\u003C\u002Fp>\n\u003Cp>\u003Cstrong>認証時\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fblog_implementing_fido_u2f_ctap1_2_b57f5ba130.png\" alt=\"\">\u003C\u002Fp>\n\u003Cp>よく見る U2F のチャレンジ&amp;レスポンスの図ですね。この Client と YubiKey の通信部分が、 CTAP と呼ばれるところです。\u003C\u002Fp>\n\u003Cp>FIDO2 での CTAP2 のスペックと比較して CTAP1 とも呼ばれますので、本記事では CTAP1と呼んでいきます。\u003C\u002Fp>\n\u003Cp>Client は通常はブラウザだと思いますが、U2Fとして実装しているのは Chrome だけです。（WebAuthN としては Firefox60 以降も対応しています）\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>ホストライブラリのやるべきこと\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>ホストライブラリは、 U2F JavaScript API などの API の裏側で動作します。 たとえば登録時であれば、\u003C\u002Fp>\n\u003Cp>・USBデバイスを列挙する\u003C\u002Fp>\n\u003Cp>・U2Fデバイスを探す\u003C\u002Fp>\n\u003Cp>・登録のリクエストをデバイスに書き込む\u003C\u002Fp>\n\u003Cp>・デバイスからのレスポンスを読み取る\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fblog_implementing_fido_u2f_ctap1_3_44d50934d8.png\" alt=\"\">\u003C\u002Fp>\n\u003Cp>といった機能が必要になります。\u003C\u002Fp>\n\u003Cp>今回は FIDO U2F の実装である 3. registration request 以降の動作について、解説していきます。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>U2Fデバイスとの通信\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>U2Fのスペックには\u003Ca href=\"https:\u002F\u002Ffidoalliance.org\u002Fspecs\u002Ffido-u2f-v1.2-ps-20170411\u002Ffido-u2f-javascript-api-v1.2-ps-20170411.html\">U2F JavascriptAPI U2F\u003C\u002Fa>,  \u003Ca href=\"https:\u002F\u002Ffidoalliance.org\u002Fspecs\u002Ffido-u2f-v1.2-ps-20170411\u002Ffido-u2f-raw-message-formats-v1.2-ps-20170411.html\">U2F Raw Message Formats\u003C\u002Fa> , そして、\u003Ca href=\"https:\u002F\u002Ffidoalliance.org\u002Fspecs\u002Ffido-u2f-v1.2-ps-20170411\u002Ffido-u2f-hid-protocol-v1.2-ps-20170411.html\">U2F HID Protocol\u003C\u002Fa> があり、 Javascript API から順番に Client 側からデバイスのローレベルなプロトコルになっています。\u003C\u002Fp>\n\u003Cp>なにやら、スペックがいっぱいありどれがどう関係しているのかわからなくなりますが、ポイントは3つです。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Point 1.  U2Fデバイス は HID デバイスとして動作する\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>さて、スペックにあるように、U2Fデバイスと Client の通信は HID(Human Interface Device) プロトコルでお話します。 HIDとはキーボードやマウスといったデバイスなどで用いられる共通規格でドライバレスで利用することが可能です。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Point 2. データの送受信フォーマットは APDU Format\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>通信は HID プロトコルで行うのですが、実際のメッセージは APDU Format という、フォーマットで送ります。\u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSmart_card_application_protocol_data_unit\">APDU Format\u003C\u002Fa>とはスマートカードの読み取りなどで利用されるデータのやり取りの方式で、コマンドとデータ長を表すヘッダーと、データをくっつけて送る形になっています。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Point 3. 実際のデータ形式は U2F Raw Message Formts\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>そして、APDUで送る肝心のデータは \u003Ca href=\"https:\u002F\u002Ffidoalliance.org\u002Fspecs\u002Ffido-u2f-v1.2-ps-20170411\u002Ffido-u2f-raw-message-formats-v1.2-ps-20170411.html\">U2F Raw Message Formats\u003C\u002Fa> という形式にして送ります。\u003C\u002Fp>\n\u003Cp>Raw Message Format はバイト配列のデータなので、最終的に JavaScript などで扱えるようなデータ形式に変換してやれば、Chrome に搭載された API のように、JSONなどのデータ形式で扱えます。\u003C\u002Fp>\n\u003Cp>まとめると、こんな感じです。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fblog_implementing_fido_u2f_ctap1_4_4d7f4dbcaa.png\" alt=\"\">\u003C\u002Fp>\n\u003Cp>以上3つのポイントがわかれば、あとはスペックや \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FYubico\u002Fpython-u2flib-host\">yubico のリファレンスコード\u003C\u002Fa>を読めば理解できるかと思います。\u003C\u002Fp>\n\u003Cp>（私は普段デバイス周りの開発をしているわけではないので、このあたりを理解するのに時間がかかりました）\u003C\u002Fp>\n\u003Cp>すべてを説明すると長くなってしまいますので、今回は登録フェーズをなぞりながら、実際のデータを確認してみましょう。\u003C\u002Fp>\n\u003Cp>例えば、 JavaScript API で \u003Ca href=\"https:\u002F\u002Fexample.com\">https:\u002F\u002Fexample.com\u003C\u002Fa> から、以下のような Registration Request がきたとします。\u003C\u002Fp>\n\u003Cp>このデータを Raw Message Formats に変換するには、まずは ClientData と呼ばれる JSON String を作成します。\u003C\u002Fp>\n\u003Cp>ClientDataのメンバは “type”, “challenge”, “origin”, “cid” とありますが、U2Fデバイス登録の際は、\u003C\u002Fp>\n\u003Cp>・type: “navigator.id.finishEnrollment” 固定\u003C\u002Fp>\n\u003Cp>・challenge: サーバーからのチャレンジ string そのまま\u003C\u002Fp>\n\u003Cp>・origin: HTTP 通信なら、認証するドメイン\u003C\u002Fp>\n\u003Cp>・cid:  option。 \u003Ca href=\"https:\u002F\u002Ftools.ietf.org\u002Fid\u002Fdraft-balfanz-tls-channelid-01.html\">channel ID\u003C\u002Fa> という Token Binding を実現する署名に使われる\n JwkKey 形式の公開鍵です。、今回は割愛です。\u003C\u002Fp>\n\u003Cp>Raw Message Formats 側では JSON の SHA256 のハッシュを取った値を使います。\u003C\u002Fp>\n\u003Cp>これが Challenge Parameter になります。（16進数表記です）\u003C\u002Fp>\n\u003Cp>また、JSONをを Web Safe Base64 Encode したものは、 ClientData としてサーバーに送信します。\u003C\u002Fp>\n\u003Cp>Web Safe Base 64 とか URL Safe Base64  とか呼ばれている “\u002F” を “_”, “+” を “-” に変える例のアレです。ただしパディングは削除します。（つまり末尾の === は削除します）\u003C\u002Fp>\n\u003Cp>このパラメータはサーバーに送るためにBase64エンコードしただけで、このデータをAuthenticator との通信で使うわけではありません。\u003Cstrong>私はエンコードしてからHashをとってしまい動かないということがありました。\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>もう一つのパラメータとして appId(“\u003Ca href=\"https:\u002F\u002Fexample.com%E2%80%9D\">https:\u002F\u002Fexample.com”\u003C\u002Fa>) の sha256 ハッシュを取ったものを Appication Parameter とします。\u003C\u002Fp>\n\u003Cp>この二つを合体させたものが Registration Request Message です。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fblog_implementing_fido_u2f_ctap1_5_efed34ec9d.png\" alt=\"\">\u003C\u002Fp>\n\u003Cp>※FIDO U2F Raw Message 4.1 Fig. 2 Registration Request Message\u003C\u002Fp>\n\u003Cp>\u003Cstrong>APDU Format\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>次に、U2F Raw Message フォーマットは APDU Format で HID デバイスに送られます。\u003C\u002Fp>\n\u003Cp>APDU Format はヘッダ部にデータ長やコマンドパラメータを指定する必要があり、Registration時のコマンドパラメータは以下のようになっています。\u003C\u002Fp>\n\u003Cp>APDU のデータには Short Encoding と Extended Length Encoding の2種類があり、 U2F では Short Encoding を利用します。\u003C\u002Fp>\n\u003Cp>※Le はレスポンスデータの最大サイズを規定するのですが、 最大長を 256 bytes に設定する場合は無視されます。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>HID Protocol\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>あとは、HIDデバイスにデータを送るだけなのですが、 HIDデバイスへの書き込みは 64byte ずつしかできません。\u003C\u002Fp>\n\u003Cp>また APDU format 同様ヘッダが以下のように付きますので、実際に送るデータはこんな感じです。\u003C\u002Fp>\n\u003Cp>・※チャンネルIDはデバイスの初期化時に取得\u003C\u002Fp>\n\u003Cp>・※コマンドの 7番目の bit は常に1\u003C\u002Fp>\n\u003Cp>DATAは先ほどの APDU データです。計 71 byte(0x47)ですが、 HIDのパケットは 64 byte であり、HID Transport 用のヘッダー 7 byte をのぞいた 57 byte しか送れません。残りのデータはシーケンスデータとして以下のような形で送ります。\u003C\u002Fp>\n\u003Cp>あとはデバイスからのレスポンスを読みます。\u003C\u002Fp>\n\u003Cp>つまり、今度は HID protocol → APDU format → U2F Raw Message Format と逆にたど\u003C\u002Fp>\n\u003Cp>っていって、デバイスのレスポンスを取得します。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>FIOD2について\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>いまさらながらの情報でしたが、いかがでしたでしょうか。\u003C\u002Fp>\n\u003Cp>冒頭の話と重なりますが、なぜいまさら U2F のホスト側の通信の解説をしたかというと、 FIDO2 での CTAP2 でも同様のプロトコルが使われており、練習台にちょうどよかったからです（CTAP1のほうがずっと簡単）。\u003C\u002Fp>\n\u003Cp>CTAP2では PIN関連のコマンドが増えていたり、送るデータも増えており、かつ標準化され CBOR と呼ばれるフォーマットになっていたりします。\u003C\u002Fp>\n\u003Cp>今週末の \u003Ca href=\"https:\u002F\u002Fidcon.connpass.com\u002Fevent\u002F84839\u002F\">#fidocon\u003C\u002Fa> では CBOR についての解説が聞けるそうですので、勉強してきましたらブログをアップデートしたいと思います。\u003C\u002Fp>\n","implementing-fido-u2f-ctap1","2018-06-05","2026-04-28T08:43:59.968Z","2026-04-28T08:44:02.584Z","ja","YubiOn",{"id":48,"documentId":49,"name":50,"alternativeText":51,"caption":51,"focalPoint":51,"width":52,"height":53,"formats":54,"hash":93,"ext":56,"mime":60,"size":94,"url":95,"previewUrl":51,"provider":96,"provider_metadata":51,"createdAt":97,"updatedAt":97,"publishedAt":97},1717,"dnjqkfuyhiovz0czii1xd4pe","blog-implementing-fido-u2f-ctap1-1.png",null,1052,551,{"large":55,"small":66,"medium":75,"thumbnail":84},{"ext":56,"url":57,"etag":58,"hash":59,"mime":60,"name":61,"path":51,"size":62,"width":63,"height":64,"sizeInBytes":65},".png","https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Flarge_blog_implementing_fido_u2f_ctap1_1_9d2672b151.png","268b7b9af21435858e6a6e79ef5730f7","large_blog_implementing_fido_u2f_ctap1_1_9d2672b151","image\u002Fpng","large_blog-implementing-fido-u2f-ctap1-1.png",98.28,1000,524,98282,{"ext":56,"url":67,"etag":68,"hash":69,"mime":60,"name":70,"path":51,"size":71,"width":72,"height":73,"sizeInBytes":74},"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fsmall_blog_implementing_fido_u2f_ctap1_1_9d2672b151.png","8842554524825a5262b2dd91b1d83106","small_blog_implementing_fido_u2f_ctap1_1_9d2672b151","small_blog-implementing-fido-u2f-ctap1-1.png",39.12,500,262,39121,{"ext":56,"url":76,"etag":77,"hash":78,"mime":60,"name":79,"path":51,"size":80,"width":81,"height":82,"sizeInBytes":83},"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fmedium_blog_implementing_fido_u2f_ctap1_1_9d2672b151.png","e838bb14a28f63e4c032e01815767095","medium_blog_implementing_fido_u2f_ctap1_1_9d2672b151","medium_blog-implementing-fido-u2f-ctap1-1.png",66.91,750,393,66913,{"ext":56,"url":85,"etag":86,"hash":87,"mime":60,"name":88,"path":51,"size":89,"width":90,"height":91,"sizeInBytes":92},"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fthumbnail_blog_implementing_fido_u2f_ctap1_1_9d2672b151.png","8a7fe4f9d17adb17167d81418536460d","thumbnail_blog_implementing_fido_u2f_ctap1_1_9d2672b151","thumbnail_blog-implementing-fido-u2f-ctap1-1.png",15.28,245,128,15283,"blog_implementing_fido_u2f_ctap1_1_9d2672b151",15.24,"https:\u002F\u002Fdty9gbw7gew16.cloudfront.net\u002Fuploads\u002Fblog_implementing_fido_u2f_ctap1_1_9d2672b151.png","aws-s3","2026-04-28T08:43:41.209Z",[],{"id":100,"metaDescription":101},461,"FIDO U2F (CTAP1) のホストライブラリを実装する際の技術的なポイントを解説。シーケンスや通信フォーマットなど、ブラウザ外でのFIDO認証に役立つ情報をまとめました。",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":103},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M15.75 6a3.75 3.75 0 1 1-7.5 0a3.75 3.75 0 0 1 7.5 0M4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.9 17.9 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632\"\u002F>",1783406259217]