who3411のブログ

情報系の勉強やイベントの参加に関するブログ(をしたい)です。

拡張BNFを用いたLL1文法の判定器を作った話

はじめに

今回、GitHubの勉強も兼ねてタイトルの通りのプログラムを作成してみました。

使い方や記述方法については、リンク先のREADME.mdに書かれているので、このブログでは「そもそもLL1って何?」とかの話も軽く話していきたいと思います。なお本ブログを読むにあたって、拡張BNFやLL1の話はかなり砕いて説明をしているので、詳しく知りたい方は他サイトや書籍を探して読むことをオススメします。

拡張BNFとは

拡張BNFは、BNF記法を拡張したものです。「じゃあBNFって何?」というと、文脈自由文法の定義などに用いられるものです。文脈自由文法は、正規表現よりも記述できる範囲が拡張された文法です。例えば「(1 * (2 + 3) )」のような括弧が混じった数式における"(“と”)“の対応を正規表現では記述することが出来ませんが、文脈自由文法では記述することが可能です。(BNFの記述方法については、ググってもらえば、分かりやすい解説が大量にあるので検索してみてください)

拡張BNFでは、BNF記法に加えて「繰り返し」が存在します。そのためBNF記法で繰り返しを表現したい場合、BNF記法では再帰的に定義することで擬似的に「繰り返し」を表現する必要があります。

例として、括弧を含めた加算を行う数式を表現する場合を、BNF記法の場合と拡張BNF記法の場合で表します。

BNF記法の場合

<DIGIT>  ::= ( "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" )
<DIGITS> ::= <DIGIT> <DIGITS> | <DIGIT>
<EXPR>   ::= <DIGITS> "+" <DIGITS> | "(" EXPR ")" | <DIGITS>

拡張BNF記法の場合

DIGIT  ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
DIGITS ::= DIGIT { DIGIT }
EXPR   ::= DIGITS { "+" DIGITS } | "(" EXPR ")"

このとき、DIGIT、DIGITS、EXPRのように"::=“の前にある記号のことを終端記号といいます。また"0"、”(“、”+“のように”::=“の後ろにしかない記号のことは非終端記号といいます。

LL1文法とは

LL1文法は、1つ先読みすることで構文を決定できる文法の事を指します。この場合の「1つ先読み」とは「1トークン先読み」のことを指しており、つまり「1トークンを先読みすることで、構文を決定・解析できるような文法」を指しています。

つまり今回作成した「拡張BNFを用いたLL1文法の判定器」とは、「拡張BNFで記述されたものがLL1文法であるかどうかを判定する」ことが目的のプログラムになっています。

ではLL1文法を判定するためにどのようにすればよいのでしょうか。ここで必要となってくるのがFirst集合、Follow集合、Director集合という3つの集合です。それぞれについて説明していきます。

First集合

First集合とは、非終端記号と終端記号からなる記号列に対して、記号列から生成される先頭の終端記号の集合を現します。例えば「拡張BNFとは」で説明した文法について説明すると、非終端記号はDIGIT、DIGITS、EXPRの3つ、終端記号は"0"~"9"、"+“、”(“、”)“の12つです。

このとき、終端記号から生成される「先頭の終端記号」とは、自身を示しています。そのためFirst(“0”) = { “0” }、First(“1”) = { “1” }…のように、自身の終端記号のみを生成します。

それに対して非終端記号から生成される「先頭の終端記号」とは、First(DIGIT) = { “0”, “1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9” }、First(DIGITS) = First(DIGIT)、First(EXPR) = First(DIGITS) + { “(” }のように、各記号列の先頭に出る終端記号の集合を生成します。

Follow集合

Follow集合とは、非終端記号に対して、非終端記号の後ろに現れる可能性のある終端記号の集合を現します。例えばDIGITの後ろにはDIGITと"+“と”)“が発生する可能性があるのでFollow(DIGIT) = { "0”, “1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”, “+”, “)” }となります。

First集合とFollow集合についての注意事項として、First集合では終端記号も求める必要がありますが、Follow集合では求める必要がありません。これはDirector集合で意味が分かると思うので、今は省略します。

Director集合

Director集合とは、非終端記号Nとその非終端記号から生成される可能性のある記号列Sを使用します。このときDirector集合はDirector(N, S)のように記述します。Director(N, S)は、Sが空文字でなければFirst(S)を、空文字であればFollow(N)を返します。

今回、空文字を使用していなかったため、Follow(N)となる例を見せることは出来ませんが、README.mdでは実行例を表示しているので見てみてください。

LL1文法の判定方法

LL1の判定方法は、結構簡単でNから生成される可能性のある記号列S1とS2(S1≠S2)のDirector集合の積集合Director(N, S1)∩Director(N, S2)が全て空集合であるかどうかで判定します。このとき、全てが空集合であればLL1であり、一つでも空集合でなければLL1ではありません。

プログラムの作成方法

さて、本題であるプログラムの作成方法について記述していきます。手順は以下の通りです。

  1. 拡張BNFトークンごとに分解する。
  2. 分解した拡張BNFが正しい記法であるかをチェックする。このとき、正しい文法でなければエラー又は警告を出力する。
  3. チェックが終了した状態の拡張BNFを出力する。
  4. 非終端記号のFirst集合を求めて出力する。
  5. Follow集合を求めて出力する。
  6. Director集合を求めて出力する。
  7. 拡張BNFがLL1かどうかをDirector集合を用いて判定・出力する。

各工程について説明していきます。

拡張BNFの分解

まず拡張BNFトークンに分解するにあたり、どのような構文にするかを定めます。この際に定めた構文は、README.mdの「拡張BNF記述ルール」を見てください。

次に定めたルールに従って、Tokenizerを作成していきます。今回のTokenizerでは、単純に以下の4種類に分解します。

  1. 文字と数値の組み合わせ
  2. “:"と”=“の組み合わせ
  3. EOF
  4. その他

分解したトークンが、どのような情報を持つトークンであるかを、別に用意したルールを利用して情報ごとに分類します。つまり一つのトークンには「トークンの文字列」と「トークンの持つ意味」の2つを格納しています。この時点で、終端記号と非終端記号の分類は行っていません。どちらも「分類していない記号」として情報を格納しています。

分解した拡張BNFのチェック

ここでは、「分類していない記号の分類」と「拡張BNFのチェック」を行います。「分類していない記号の分類」は言葉の通りで、「分類していない記号」を終端記号であるか非終端記号であるかを確認します。

「拡張BNFのチェック」では、"(“と”)“の数が一致しない、"A ( ) B"のように必要のない括弧があるなど、LL1であるかどうかを判定するのに必要でない括弧の除去などを行っていきます。このとき、プログラムで直せる範囲であれば警告、直せない範囲であればエラーとして出力します。

「拡張BNFのチェック」で、プログラム側が利用者の記述した拡張BNFを修正する可能性あるため、この工程が終了する時点でプログラム側が今後利用していく拡張BNFを出力します。

First集合の求め方

自身の非終端記号を持つ列を見つけ、その非終端記号のFirst集合を求めます。求め終わった後に、全て出力します。

Follow集合の求め方

拡張BNFの右辺(“::="の右側)から、非終端記号を見つけ、その非終端記号のFollow集合を求めます。求め終わった後に、全て出力します。

Director集合の求め方

非終端記号とその非終端記号が生成する可能性のある記号列、これまで求めてきたFirst集合とFollow集合を用いて、空文字があればFollow集合を、空文字がなければFirst集合をDirector集合として利用します。求め終わった後に、全て出力します。

LL1の判定

同じ非終端記号から求めたDirector集合を用いて、LL1であるかの判定を行います。LL1の判定を行い、LL1でなければ空集合とならなかった積集合を出力します。

おわりに

雑な説明でしたが、以上が今回作成したプログラムの全貌になります。LL1が作れると何が良いかなどは、各自調べていただければ幸いです。(私は勉強目的ですが、自作言語をしたい方は勉強するといいかもしれません。)

セキュリティ・キャンプ全国大会2017に参加しました

目次

はじめに

タイトルの通りセキュリティ・キャンプ全国大会2017に参加しました。
f:id:who3411:20170822024506j:plain
今回は、そこで得た技術について共有しようと思っていたのですが、どこまで書いていいのかよくわかりませんでした。そこで今回は、ぼんやりとどんな感じだったか、どんなことを知ったかという、自分目線の内容を中心に語りたいと思います。

セキュリティ・キャンプについて

私が書くよりもおそらく公式を見た方が早いと思うので、公式サイトのリンクを下に貼っておきます。また生活環境についても、公式Twitterを見た方が早いと思うので、公式サイトのリンクを貼っておきます。(リンクばかりで説明がなくてごめんなさい)
www.security-camp.org
twitter.com
簡単にまとめると、「全ての費用が無料となる上に、4泊5日ですごい人たちの講義を通して、セキュリティのことを学べて楽しい!」ということです。実際セキュリティの様々な分野のヤバい人達が講師として教えてくれるので、とても面白い時間を過ごせます。(裏側で税金やスポンサーからお金が回ってたりするんでしょうね。多分そうでしょう)

参加するまでの流れ

とりあえず応募課題を解くことが最優先ですね。応募課題の回答内容については、前の記事であげているので、リンクを貼っておきます。
who3411.hatenablog.com
記事を見てもらうとわかるのですが、解いた時間や締め切りについては書いてあるのですが、「そもそもなんで参加したの?」「その裏側でなんかあったの?」などなど、個人的に書かないとまずいと思った部分があったので、記述していきます。

そもそも私自身、いつセキュリティ・キャンプを知ったかというと、高校3年生の時でした。現在大学3年生なので、3年前ですね。先生から「これ出てみない?」と言われるがままに応募用紙を書いたら、見事不合格通知を受けました。それからというもの、毎年応募しようとは思っていたのですが、「大学の講義が…」「どうしてもやる時間が…」という現実逃避を続けていました。

そんなこんなで大学3年生になっていたのですが、どうやら今年は同じ大学から応募しようとしている人が複数人いたらしいです。(この時、私は1人しか応募しようとしている人を知りませんでした)また後輩が'14に参加していたらしく、セキュリティ・キャンプ全国大会2017がだんだん気になり始めました。

そんな気になり始めた頃、「そういえば今年はどんなことやるんだろうか」と思ってホームページからコースの内容を確認しました。すると現状興味あるLinuxカーネルの講義があり「これはいきたいな」と感じ始めました。更に大学3年生という現状を踏まえると、来年がラストチャンスになってしまいます。「このままでは一生参加できないかもしれない…。まずい」と思い始め、ようやく今年こそは応募用紙を書くと決意しました。

応募課題を解こうと思ったのはいいものの、結局「勉強が…」「実験が…」とか考え始め、結局共通課題を解いたのが〆切2日前、選択応募課題を解いたのが〆切1日前でした。共通課題に1日かかったのは、単純に「これまで作ってきたもの」の内部仕様を忘れたからです。

応募課題については、単純にLinuxカーネル系の講義を受講したいという思いから選択コースにしました。また選択コースで選んだのはA-1、A-4、A-8です。

A-1ではWiresharkを使って、添付されたpcapファイルの内容を読み取るというものでした。去年の秋にネットワークスペシャリストに合格する際にネットワークの勉強をしていたこと、Wiresharkは昔から使っていたことなどから選択しました。通信から読み取れることは、できる限り考察してゆき、パケット順に「何ができるか」「何の通信が行われるはずなのに欠けていると考えられるか」を考察していきました。実際に通信を再現しようと考えたのですが、この時点で〆切まで残り18時間だったので諦めました。

A-4ではprintf()について調べました。この頃は、運良くfreadやfwriteについてglibcを読んでいた頃なので、その流れでprintfをソースリーディングしました。「step_jumpsってなんだ」「やばい。わけがわからない…」とかなりながらも、なんとか6時間程度で解答晒し記事のようなものが出来上がりました。この時点で〆切まで残り12時間です。

A-8については、前にA-5をやろうと思っていたのですが、「あ、これは絶対に間に合わないやつだ」と思って逃げました。(実際その予感は当たっていたようで、本当にやばい課題だったようです)「興味のあるセキュリティ技術」と言われた時に、私が思い浮かんだのはPKIでした。この年の春に情報処理安全確保支援士の学習を行っており、その際にPKIについて詳しく学習しました。細かい仕組みがわかって行くにつれてだんだん興味が湧いていたので、そのまま殴り書きしました。この時点で〆切まで残り5時間です。(朝7時ごろになり、見事な深夜テンションの人間が出来上がっていました)

この時一度提出したのですが、完全に添削を忘れており、更に爆睡してしまいました。ですが念のため10時に起きるようにしていたことが功を奏し、何とか目が覚めてから添削を行い、結果的に11時ごろに提出することができました。

応募用紙の提出が終わった後には、「こんな深夜テンションで作ったものが通るのか…。いや、多分ダメだろうな」とか思ってビクビクしながら通知を待つ日々が続きました。

参加決定後の流れ

ビクビクした日々が続いたある日、合格通知が届きました。(講義中でしたがガッツポーツとかしてました)それからは、ハイテンションになりながら過ごしていました。トラックの選択は受けたい講義を選択できなかったり、企業の選択はすぐに選んだらどっちも第一希望が通ったりと、いろいろありましたが面白くなりそうな予感がしていました。

ちなみに合格通知が来ると、すぐにあるサイトへの登録を行い、そのサイトを通じて事前課題や重要な連絡などが飛び交います。この時、適切に通知を管理しておかないと、とても面倒なぐらいメールへ通知が来ます。(1日8通とか割とよくあります)気をつけましょう。

あと私が受けることになった講義は以下の通りです。(D2-3受けたかった…)

ここで一つ問題だったのが、大学の実験や期末試験です。実験のデータ収集やプログラム作成に時間を割きすぎて、期末試験対策をあまり行えないまま時間が進みました。次に期末試験対策を行って、期末試験に望むと、今後は期末レポートの提出が危うくなり始めました。何とかして期末レポートも提出すると、セキュリティ・キャンプ当日まで3日しかありませんでした。

もし今後セキュリティ・キャンプに出たいという人がいたら、大学などの課題・試験対策は早めに行っておきましょう。私みたいに大変なことになります。他の人はというと、割と事前課題の進捗報告をサイトに上げており、とてつもない焦りを感じていました。

そこからは事前課題をできる限り進め(3日間のうち50時間程度は事前学習の課題に当てていました)、当日を迎えることになりました。

セキュリティ・キャンプ1日目

そんなこんなで当日を迎えました。私は会場まで3時間程度かかる場所に住んでいたので、朝8時前の電車に乗って、少し早めに向かいました。(この時、最寄駅から実施会場までの経路を知らなかった覚えていなかったので、最寄駅からは視覚情報を頼りにしました)何とか到着して、少し経つと会場への案内が始まりました。会場に着いてからは昼食や名刺交換などがあります。名刺交換は、皆さん素晴らしい名刺を持っていたので、交換してて案外面白かったです。(私が人の顔を覚えるのが苦手なために、顔を忘れて2度目の交換を始めようとするという場面もありました。本当にごめんなさい)

開会式

ようやく開会式が始まりました。開会式では、校長の挨拶素晴らしい式辞や挨拶を受けました。開会式の時間は、正直早く講義を受けたかったのであまり話を聞かなかったこれからの講義に胸踊っていた影響であまり記憶がありません。

セキュリティ基礎

開会式の後、ようやく講義が始まりました。初めの講義は、AIに取って代わられる・代わられないセキュリティ業界などについてのグループディスカッションでした。グループディスカッションでは、座っている席の影響で司会になりましたが、なかなか面白い議論を進められたんじゃないかと思います。ただし少しの時間で、用語の定義やセキュリティの範囲を規定して、その話題について1分で話すのはとても難しいと感じたため、割と適当にまとめてたりします。この時、気づいたらグループの人が発表用コンテンツを作ってたりして驚いたりもしました。

他の班の発表については、全ての班についてメモを取っていたところ、大体言いたいことが重なっている班が多かったので「やっぱりどこも同じような結果になるのかなぁ」とか考えていました。

あとは「これからの4泊5日を有意義に過ごそう」のようなことを色々を聞いて、セキュリティ基礎は終わりました。

特別講義(1)

特別講義(1)では、「凝ったうんこの話」を聞きました。(個人的には、太陽の塔の話が出て来るとは思ってなかったので驚きました。)講義の本題として、現在の仕事や失敗談などを聞きましたが、どれも刺激的なものが多く、とても面白い時間を過ごすことができました。

特に失敗談については「セキュリティの最前線で働いている人として、どのような失敗があったか」を聞けるところがとても印象に残りました。通常では成功談が多いため、失敗談を聞けるのはとてもありがたかったです。

話を聞いていくと、最終的には講師が楽しくて仕事をやっていることを知りました。「楽しんでこその仕事だよなぁ」とか思っていたら、あっという間に特別講義(1)は終わりを迎えました。

特別講義(2)

特別講義(2)では、フォレンジック関係の話を聞きました。フォレンジックについては前々から興味はあったものの、全くやったことがなかったため興味津々で話を聞きました。

やはりフォレンジックを業務としている影響か、警察関連の話も多少聞くことができました。失敗談は聞けなかったものの、事例を紹介していただいたので面白かったです。

ここでは「ロールモデル」が少し引っかかりました。正直ロールモデルなんて全く考えずに生活して来たので、「セキュリティ・キャンプを機会にロールモデルを探すのもありだな」と思いました。そんなことを思っていたら特別講義(2)も終わりました。

チューター紹介

過去にキャンプを卒業した方が現状どのような実績を持っているのかを紹介していただきました。紹介していただいた3人とも、完全にぶっ飛んだ次元の違うような素晴らしいプレゼンを聞くことができました。

圧倒的成長をしてあそこまでの実績ができるかどうかわかりませんが、できる限りあそこまで近づく・追いつく・追い抜くようなレベルまで行きたいと感じました。

グループワーク(1)

当日まで全然講義内容を把握していなかったのですが、どうやらグループワークなるものがあったらしいです。最初にグループ分けされていたのも、このためのようですね。

グループワークでは、講義中に出される4つのテーマの中から1つ選んで、解決策を考えるというものです。私たちの班は「学生のソフトウェアの品質の担保」を選択して、ヒアリングを行いました。この時に少し思ったことなのですが、ソフトウェア品質などの話になると「ソフトウェア工学」などの分野の話にあるかと思います。班員によっては、ソフトウェア工学などの品質に関わることについて全く知らなかった人もいました。また「バグ」=「脆弱性」と結びつけている人もいて、思っていたより基礎をやられていない印象を受けました。(別に嫌味ではなく、基礎知識を身につけないとコーディングを行う気にならない私としては、単純に気になってしまうだけです)

この日はテーマ決めを行うのが中心だったため、テーマを決めてからは複数人にヒアリングして終わりました。終わった後には、大学のレポートが終わっていなかったため、それを終えて楽しい楽しい1日目が終了しました。ちなみに就寝時間は25:30規定通り23:00でした。

セキュリティ・キャンプ2日目

さて、本日からようやく専門講義が始まります。講義開始は8:30からなので、準備や朝食を含めて5:55にタイマーをセットしていました。そのおかげで私は、特に問題もなく8:40に起きました。

「………8:40???えっ!?えっ!?」と頭が混乱して青ざめた私に待ち受けていたのは、扉のノックでした。(本当に申しわけありませんでした)大急ぎで着替えて会場へと向かうことになりました。

専門講義(1)

大慌てで向かった講義はD1 Linuxカーネルを理解して学ぶ 脆弱性入門です。メモリ管理などの話から脆弱性のエクスプロイトの作成などを学びました。講義に遅れた影響でチューターの方にここまで行っていた内容を聞きながら、なんとか演習前に環境を整えることに成功しました。(どうやら私が遅刻している間に行っていた座学は、事前課題として提示されていた内容だったようで、なんとか内容にもついていくことができました)

「入門編????」と入門編かどうかも怪しい講義を受けながら演習を受けていると、早速課題が提示されました。課題内容を解いていると、途中で「あれ?これであってるのかな?」となり始め、だんだん講義についていけるのか不安になり始めました。

それぞれの内容を全て終えた頃には、私はほとんど問題を解くことができずに終わってしまいました。いわゆる洗礼を受けてしまいました。前で説明している内容は理解できている(と思っている)のに、課題を解くことができないというなんとも歯がゆい状況のまま、講義は終わりを迎えてしまいました。

専門講義(2)

専門講義(2)はちゃんと所定の時間に間に合いました。受けた講義はB2 Linuxクロス開発スタートアップです。最小限の環境を構築した状態で、ラズパイを動かして見るというものでした。

こちらは講義終了1時間前に、まさかの仮想環境が再起動してからのデータ消失という訳のわからないエラーに見舞われ、結局時間内に終わることはありませんでした。データ消失前には、あと30分程度で全てが終わるような状態であっただけに残念です。

ちなみにちゃんとラズパイをブートさせていた人は1人だけだったので、割と皆さん苦戦していたようですね。(完成させた人強い…)家にラズパイがあるので、なんとかして家で完成させたいものです。

専門講義(3)

専門講義(3)はC3 Vulsを用いた脆弱性ハンドリングとハッカソンです。Vulsを作成したOSS製作者やPetを作成したOSS製作者の話を聞きました。(VulsとPetは以下のリンクの通りです。) github.com
github.com
正直とてもエモくてバズりたい気分になれる講義でした。実際にOSSでバズられた人の話を聞くのはすごく刺激的で、貴重な時間を過ごしました。

そのあとに行われたハッカソンでは、現在未対応のOSにVulsを実装する方法について2~3人のグループで議論することになりました。Vulsに未対応かつ私が触ったことがあるOSといえばFedoraぐらいしか思いつかなかったので、Fedoraを挙げたところ2人チームになりました。最新アップデートが必要なソフトウェアの列挙などは考え付いたのですが、発表の際に脆弱性発見方法についてやらかしてしまい、グループの方にフォローしていただきました。(申しわけありませんでした)

そんなこんなで2日目が終わりました。今日の遅刻のことを深く反省し、明日は起きれるようにと、パソコンに新たな目覚ましアプリを投入しました。そして早く寝れるように心がけ、24:00規定通り23:00に就寝しました。

セキュリティ・キャンプ3日目

昨日の努力などが功を奏し、7:30に起きることができました。3日目にしてようやく朝飯を食べることができ、余裕を持って専門講義(4)に向かうことができました。

専門講義(4)

専門講義(4)は、B4 Embedded System Reverse Engineering 101です。リバエン(リバースエンジニアリング)は、名前を聞いたことがあるだけで、実際に行ったことはなかったのでワクワクしながら受講しました。

I2C通信についての説明やデータシートからの情報抽出などを行い、実践に入りました。実践では、BusPirateを使用してROMに対してデータの読み書きを行いました。この時に重要なのが、データシートからの情報抽出です。BusPirateではあらかじめ通信方式やボーレートを定めないといけないことに加え、ROMごとに異なるコマンドに対応しなければいけません。その時にデータシートが読めないと、ROMに対してコマンドを送ってデータの読み書きを行うことができません。

I2C通信の次には、SPI通信を行いました。SPI通信の際には、実際に家庭用のルータからROMを取り出すということも行いました。実際の機器に対してリバエンを行うというのは、とても面白い経験になりました。

専門講義(5)

専門講義(5)は、C5 暗号運用技術です。まずはSSL/TLSPKIなど、現在のインフラなどに関係する部分の座学が行われました。コマンドを用いて実践的な作業を行う部分もありましたが、実は座学の部分は情報処理安全確保支援士を学習する際に覚えてしまった内容だったので、少し退屈になったりしました。

これまで学んで来たことを、コマンドを用いて実践的に行うことは、知識の定着には良いので、情報処理安全確保支援士勉強時の復習になりました。

座学や演習の後には、ミニCTFが行われました。私はCTFというものを全く行ったことがなかったので、かなり不安でした。ですが実際に行ってみると、これまで講義で出てきたことを実践するようなもので、CTFは抜きにしてゲーム感覚でやっていきました。すると、気づいたら参加者の中で1位になっていたりしました。(チューターは全問正解していました。さすがです…)

BoF(グループセッション)

夕飯の後にはBoFとして、2つ選択しました。理想論を考えつつも現実的な目線を優先してしまう私としては、倫理を無視した理想論は受け入れがたいものがあります。ですが1つ目のBoFではそのような倫理観無視の議論が行われていた影響で、全く議論に参加することができませんでした。(本当にごめんなさい)BoF自体は面白かったのでよかったですし「こういう考えもあるのか」と納得する部分もあったので、なんだかんだ楽しかったです。

2つ目のBoFはセキュリティの考え方を改める良い機会になった気がします。パケットの山から「どれが攻撃っぽいか」「なんで攻撃と思えるか」「誰が攻撃しているか」などを考えることは、とても重要なことだと知りました。普段から「これは攻撃だとわかりきっている」という攻撃はなく、だからこそ幾つもの攻撃に対処するためのセキュリティ対策は重要です。(とかなんとか書いてますが、うまく言葉にできないだけです。話は本当に興味深いものでした)

企業プレゼンテーション(1)

企業プレゼンではNTTを選択しました。こちらではインシデントレスポンスの話を聞きました。セキュリティの仕事やインシデントレスポンスの仕事の話は、聞いていて結構面白いもので、様々な攻撃に対してセキュリティ対策を行う必要があることの重要性を知りました。

実は企業プレゼン、他にもいくつか聞きたい企業があったので、時間を短くして1日2社にしてもらうとか各企業のプレゼンを見せていただくとかしてくれるとありがたかったです。(おそらくそれができないということを承知の上で記述しています)

グループワーク(2)

さて、企業プレゼンが終わるとグループワークです。1日目でソフトウェア工学だのなんだの言い始めたせいで議論を止めてしまったこともあって、最初は議論に参加しづらいものがありました。(ごめんなさいごめんなさい)流石に止めておきながら議論に参加しないのもまずいと思い、参加しながら用語の定義や議論の進め方など、このままだと平行線の議論になりそうな部分を中心に固めていきました。

これはキャンプと関係のない話ですが、私がグループワークを行う上で一番やりたくない役職は、リーダーもしくは司会です。理由は以下の通りです。

  • 相手とウマが合わなくて嫌われることがある
  • 相手の気持ちを考えながら進めることができない
  • 上手く議論が進まないととても気まずい
  • そもそもリーダーや司会という役職が合わない

そんなこんなでやりたくないんですが、今回のグループワークではついつい(流れで)やってしまいました。本来あれが司会やリーダーに入るかと言ったら別かもしれませんが、なかなか進みそうになかったので、だんだん横槍を入れていきました。幸いにも私と同じ考えを持つ参加者が他にもいたので、割といい感じに進められたんじゃないかと思います。この日は方向性とヒアリングの質問リストを決めて、「誰かにヒアリングを行う」ことを任意の宿題として終えました。

この後は4日目の事前課題勉強会に参加しました。この勉強会に関しては、既に私が終わっている事前課題についての勉強会だったので、教える側に回りました。この時ようやく実施会場にマッサージ機があることに気づきました。(もっと早く知って使えばよかった…)勉強会の後は明日の準備をしてnew game!!を見て27:00に規定通り23:00に寝ました。

セキュリティ・キャンプ4日目

4日目にして、ようやく6:00に起きることができました。やはりカフェイン剤を寝る直前に飲んだのは正解でした。のんびりと朝飯を食べてけもフレを見て、ゆっくりと専門講義(6)に向かいました。

専門講義(6)

専門講義(6)はD6 LSMから見たLinuxカーネルのセキュリティです。この講義、事前課題を30時間〜40時間ぐらいかけてやっていたので、本番でもかなり理解できました。

内容としてはフリーアンチウイルスソフトを利用して、ファイルを開けるたびにそのファイルが感染されているかどうかをスキャンするというものです。最後の最後で一つだけ課題が解けずに終わってしまいましたが、結果として「ユーザ空間とカーネル空間は色々と違って、カーネル空間のミスはやばい」ことがわかりました。

私個人としては、カーネルモジュールを作成するのは初めての経験だったので、やっていてとても楽しかったです。ただし事前課題で何回も仮想環境がフリーズしたりカーネルパニックしたりしたので、課題の進捗がなかなか出なかったりしました。

専門講義(7)

ついに専門講義も最後になってしまいました。専門講義(7)はA7 ファジング実習です。前半はpeachというファジングツールを利用して、ルータやソフトウェアに対してファジングを行いました。そこそこ有名なツールでも脆弱性ってあるんだなぁと感じながら時間を過ごしました。

後半はAFLというファジングツールを利用してバイナリファイルに対してファジングを行いました。こちらは実習もあり、いい感じに脆弱性を見つけることができました。AFLはカーネルに対してもファジングを実行できるようなことを聞いたので、ぜひやってみたいと思います。

これで専門講義は全部終わりました。課題は多いですが、良い時間を過ごすことができました。

企業プレゼンテーション(2)

2つ目の企業プレゼンはさくらインターネットにしました。こちらではDockerの話を中心に聞きました。私はDockerを使用したことがなかったので、基本的な話からセキュリティに関する話まで、幅広く聞くことができました。

グループワーク(3)

さて、企業プレゼンも終わって3日目のグループワークが始まりました。この時点でヒアリングのノルマを達成していなかったようで、先ほど聞いたさくらインターネットの企業プレゼンを行った人からヒアリングを行いました。この時に色々と有益な情報を聞いた他に、プレゼンの問題提起の意見まで聞くことができてとてもありがたかったです。

ヒアリングが面白すぎた影響で、ヒアリングに時間を取られすぎたことが影響したのか、グループワークのプレゼン作成に参加できていませんでした…。(本当にごめんなさい)とはいえヒアリングには必要人数が設定されていたので、必要人数を達成できたという意味ではちゃんと進捗を出していました。

サプライズ

グループワーク終了後、サプライズイベントがありました。書籍やグッズの配布です。このサプライズ、何が問題かというとわかものから順に書籍やグッズを持っていけるという点です。私は20歳だったので、後半戦になってようやく持っていく権利を得ることができました。この時点で欲しかったものの大半は無くなっていたため、「いっそのこと今興味のないものを持って行って勉強しよう」ということで1冊は全く興味のなかったSwiftの本を持って行きました。もう1冊は元から興味のあったルータのVPSの話です。(この本に対象のルータを同梱して欲しかった)

そんなこんなで4日目も終わり、部屋に戻ってグループワークの資料を眺めたり、明日に向けてヒアリングの内容をまとめたりしました。最終的には24:30規定通り23:00に寝ました。

実はこの日、今回参加して一番驚いたことがありました。それで驚いた原因の人と話し合ったりもしていました。いやー、世界って思っていたよりも狭いんだなぁと感じた1日でした。(驚いたことについては、完全にプライベートな内容なので話しません)

セキュリティ・キャンプ5日目

5日目は7:30に起きたため、急いで朝食を食べて講義室へ向かいました。グループワーク開始まで残り少ない時間であるにもかかわらず、なかなか人が来なかったことから、全員疲れが溜まっていることがわかります。私は2日目に遅刻をしてしまいましたが、それ以外はなんとか遅刻しなかったので良かった(?)です。

グループワーク(4)

最終日に入り、グループワークも佳境です。私たちの班は大急ぎでプレゼン用のスライドを作成する必要がありました。他の班は、26:00や27:00ぐらいまでスライドを作成していた自室で睡眠しながらグループと夢の中で語り合う素晴らしい能力を身につけていたようですが、我々の班は健全な睡眠を心がけていたため、スライドが出来上がっていませんでした。

そんなこんなで全力でスライド作成を行い、なんとか完成しました。(というよりはケリをつけました)不満がないと言ったら嘘になりますが、それよりも司会のようなことを行っておきながら、スライドなどの工数を正確に把握できていなかった私が情けなかったです。

スライド作成後は、各グループによるスライド発表です。理想論を語っている班、支援があればなんとかできそうな提案を行う班、割と現実的な目線で語る班など、様々な班がありましたが、どの班の発表もそれなりにおもしろかったです。感想としては、積極的にイキリストの輪を広げて欲しいのとVRキャンプが欲しいということですかね。

成果報告

成果報告は、まず集中コースの発表がありました。X、Y、Zともにとても面白い報告を聞くことができました。個人的にはZトラックの人が頭のネジ壊れてるんじゃないか企業を煽ってたりして面白かったです。もちろんXもYも成果発表はすごいもので、終始「集中コースいいなぁ」とか思ってました。

次に選択コースの発表がありました。選択コースは、プロデューサ4人がそれぞれ指名した人から感想を聞くというものでした。私は専門講義(5)のC5で、ミニCTFの優勝をしてしまったため感想を話すことになりました。しかもこの場でCトラック中心のプロデューサから感想を聞かれていたにもかかわらず、Dトラックの話を始めるとかいう訳のわからないことを始めてしまい、申し訳ない気持ちになりました。

最後にNOCチューターの発表がありましたが、スライドを見れなかったのが残念です。個人的にはインフラに興味があるので、ネットワーク構成図などを説明されながら見るとかしたかったです。

閉会式

いよいよ閉会式になりました。校長の挨拶素晴らしい式辞と挨拶(デジャブのような説明)を聞いていたのですが、一つだけ印象に残ったものがあったので紹介を。それは「5日間を通して挫折した人」でほとんどの人が手を挙げていたことですね。「やはり全員挫折を経験するのか」と思いました。

あとは閉会式の後に写真を撮ったり、皆さん名残惜しかったのか会場前で話し合ったりとありましたが、これで楽しく課題の残る挫折しながらも頑張った5日間が終わりを迎えました。

全体的な感想

完走した感想感想ですが、想像していた以上に解けない課題が多く、事後課題を行わないといけないレベルで知識が正確に定着しませんでした。ここで感じた挫折や課題については、今後の燃料として注がせていただきたいと思います。正直挫折せずに5日間を過ごすことができた人は相当素晴らしい能力を持っている人だと思います。

5日間をどれだけ有効に過ごすかということについては、「講義中に全て学ぶ」という姿勢ではなく「今後学んでいくためのきっかけを作る」という意識で講義に望むことをオススメします。5日間だけで全てが終わってしまうような課題を自分の中で作り上げてしまうと、そこで収束してしまいます。これからも発展させていくような気持ちで5日間を過ごしましょう。

余談ですが、事前課題はちゃんとやりましょう。事前課題をやっておくことで、当日の講義中にどれだけ充実するかが変わると思います。どっかの誰か私みたいにキャンプ3日前に50時間ぐらいかけて、死に物狂いで学習するのは良くないです。

後は睡眠大事ですね。私は全日程を規定を破って規定通り23:00に睡眠することができましたが、3日目ぐらいから疲れが溜まってきて、5日目には閉会式で寝る寸前になりました。たとえ事前課題が全て終わっていなかったとしてもちゃんと寝ましょう。

個人的な課題と、今後セキュリティ・キャンプ全国大会へ望む人へのメッセージが混ざったような感想ですが、ここに書いた内容は大体のことについても言えます。なので5日間は、常にどのような姿勢で生活していくかを考え直す良い機会であったとも考えています。

後日談

B4で使っていたBusPirateを回収されてしまったので、終了後すぐに秋葉原へ向かい、BusPirateを購入しました。 f:id:who3411:20170822025744j:plain
後はmalloc動画見ました。セキュリティ・キャンプ全国大会2017に参加するまで、存在を知っていただけなので、この際の記念として2周しました。

さいごに

参加前の応募課題から参加後まで、総じて楽しい時間を過ごすことができました。5日間を通して、「ブログで私が得た知見を共有していこう」とか「LTや勉強会に参加しよう」とかいう意欲がモリモリ湧いているので、現状ではかなり勉強意欲高いです。

もしこの記事をセキュリティ・キャンプ全国大会に参加したくて読んでいる人がいるとしたら、ぜひ参加してみてください。私みたいな技術のない人間でも、気合いと根性で応募課題を作成して、なんとかして突破できました。技術の有無はそこまで関係ではなく、どれだけ熱意を持ってできるかというのも重要だと思います。(もちろん最低限の技術は必要ですが)後はやりたい目標は見つけておいてください。「理由ないけど参加する」は別にいいとは思いますが、大して目的のないまま5日間を過ごすことになると思います。

セキュリティ・キャンプ全国大会への参加が決定した人が読んでいるとしたら、絶対に事前課題はちゃんとやりましょう。課題をおろそかにしてしまうと、本当に講義時間を無駄にしてしまいます。折角講師の方が時間を削って作成してくださってるので、頑張って解いていきましょう。いっそのこと「事前課題で当日課題まで全て終わらせてやる」ぐらいの気持ちで行くといいかもしれません。あと名刺を作りたい人は、ちょっと凝ったデザインにするといいかもしれません。やはり情報系のイベントでの名刺交換、予想していた通りJSONやシェルを使った名刺が存在しました。中には全然想像していなかった名刺を作成していた人もいたので、結構面白かったです。(私ですか?シンプルすぎてなんとも言えないデザインになりました。辛いです。)

セキュリティ・キャンプ全国大会に参加した人が読んでいるとしたら、お互い頑張りましょう!(それしかないのかって?話題が思いつきませんでしたどちらかというと参加前の人たちにみて欲しいと思っているので、メッセージを書いていません)

本当の最後として、もらったものの一部を上げておきます。それぞれ以下の通りです。
1枚目: 初日にいただいたグッズ
f:id:who3411:20170822024517j:plain
2枚目: 初日にいただいた資料
f:id:who3411:20170822025732j:plain
3枚目: B4でいただいたルータやジャンパ線など
f:id:who3411:20170822024523j:plain
4枚目: サプライズでいただいた本
f:id:who3411:20170822024526j:plain
5枚目: 最終日にいただいた修了証など
f:id:who3411:20170822025735j:plain

セキュリティキャンプ全国大会2017応募用紙

はじめに

セキュリティキャンプ全国大会2017に参加することが決定したので、勢いで応募用紙でも晒してやろうとブログ作ってみました。

問題を解き始めたのは10日前、応募用紙を書き始めたのは締め切り2日前ほどで、提出したのは締め切り当日の11時頃でした。文字数は約17,000文字ほどです。正直応募した時は落ちたと思い込んでいました(笑)。こんなギリギリでもなんとか受かったことに現在でも驚いています。

セキュリティキャンプに受かったというメールがきた時は、講義中でしたので声は出せませんでしたが、とても嬉しかったです。

では以下に応募用紙を晒します。勢いで作ったブログなので、読みづらい可能性大ですがご了承ください。

共通問題

共-1(1) これまで作ってきたもの

JavaScriptを用いたブロック崩しシューティングゲームといった簡易的なゲーム
Apache+PHP+MySQLを用いた高校内アンケートサイト
Javaを用いたフラクタル図形の描画プログラム
Javaを用いたスケジュール管理アプリ
・Nginx+PHP+MySQLを用いたチャットサイト
Arduino+Unityを用いたガンシューティングゲーム
C言語を用いた簡易ヘルプアシスタント
C言語を用いたRTA*検索でのお助け付き8パズルゲーム
C言語を用いたSSL/TLSマルチTalkサーバ・クライアント
C言語を用いた簡易HTMLサーバ

共-1(2) 共-1(1)の作成手段

JavaScriptを用いたブロック崩しシューティングゲームといった簡易的なゲーム
 ライブラリを用いずに作成した。全てのゲームは基礎部分しか作成していないため、ブロック崩しであればアイテム、シューティングゲームであればスクロール型にするなどといった追加機能の作成を行うようにしたかった。ただし中には、オセロに重み付けを用いたCPUの作成、おじゃま機能ありのパズルゲームなども作成することができた。
Apache+PHP+MySQLを用いた高校内アンケートサイト
 XAMPPを用いてApache, PHP, MySQLを動作させた。PHP関連のライブラリは用いていない。アンケート用のユーザデータとアンケート回答用のデータについては、第三正規化した状態でMySQLにテーブルを作成した。そしてApacheでWebサーバとして動作させ、PHPを書いてアンケートに答えられるようにした。最後にアンケートを自分で作成できるようにフォームを作成した。
Javaを用いたフラクタル図形の描画プログラム
 ライブラリは用いていない。シェルピンスキーのギャスケットやマンデルブロ集合、コッホ曲線といったフラクタル図形をAwtで描画するようにした。改善案としては、描画が荒いため、アンチエイリアスを行なって綺麗な描画を行えるようにしておきたい。
Javaを用いたスケジュール管理アプリ
 ライブラリは用いていない。Awtを用いて、年ごと, 月ごと, 日ごとのスケジュールを編集・参照できるアプリを作成した。スケジュール管理を行うためにはアカウントが必要であり、はじめに新規登録も可能であるログイン画面が表示される。そこでログインを行うことで、スケジュール管理を行うことが可能となる。登録したスケジュールがあると、参照しやすくするために、周りの色を変化させる。下にはTodoリストを登録することも可能になっており、年月日とTodoの内容を書くことで、書いた年月日にTodoの期限があることを示す色がつく。改善案として、アプリ自体のデザインの調整とUIの向上がある。
・Nginx+PHP+MySQLを用いたチャットサイト
 CentOS7を用いてチャットサイトを作成した。Ajaxやサイトのデザインに用いるためJQueryを用いている。まずWebサーバを立ち上げるために、Nginxを起動できるようにした。起動の際にはユーザディレクトリを用いるようにコンフィグファイルを書き換えた。またFastCGIを用いることができるよう、http://127.0.0.1:9000をパスとした。次にチャットを行うためのユーザデータ, チャット内容, チャットを行う部屋, チャットに用いた画像の保存パスをデータベースに格納することができるように、第三正規化した状態でMySQLにテーブルを作成した。そしてHTML, CSS, Javascript, PHPを用いてチャットサイトを作成した。チャットサイトでは、部屋を作成し、作成した部屋にユーザを登録することで、グループチャットを行うようになっている。そのため、グループチャットを行えるように登録画面やユーザ管理画面を作成した。最後にチャットデータを持ってくることができるようにAjaxを用いて、まだ送信していないチャット内容の送信や、ユーザから送信されて来たデータの受信及びデータベースへの登録ができるようにした。改善案として、Ajaxを用いたチャットでは、まだ新しい発言が届くまで数秒かかってしまうので、Node.jsなどを用いたWebSocketを用いたチャットサイトの開発を行うようにしたい。
Arduino+Unityを用いた無線ガンシューティングゲーム
 まずArduinoを用いたガンコントローラの作成について述べる。ライブラリは、XBeeのデータの送受信を行うためにhttps://github.com/andrewrapp/xbee-arduinoを用いた。ガンコントローラには、Arduino, 三軸ジャイロセンサ, 三軸加速度センサ, トリガー用のボタン, コントローラ内に入るような電源, 無線用のXBeeを載せる必要があった。これらの部品を, PlayStation2用のガンコントローラであるガンコン2の内部を取り外して格納した。格納にあたっては、できる限り小型化する必要があったため、コントローラー内に入れる電源は単三乾電池1本、Arduinoマイコンブートローダのみ焼いて使用することとした。この時、電源は単三乾電池1本だけでは足りないため、昇圧回路を用いてArduinoが動作するように電圧を上げた。そしてArduinoに三軸ジャイロセンサ, 三軸加速度センサ, ボタンの値を取得し, それをXBeeを通してシューティングゲームを行うパソコンに接続されているXBeeに送信する仕組みを作成した。なお受信するXBeeについても、もう1台のArduinoを用いて受信し、受信した値を相補フィルタを用いて、周波数領域特性を向上させている。
 次にUnityを用いたゲームの作成について述べる。Unity側では、Arduino側からガンコントローラの向いている角度を取得するために、SerialPortを開いてArduinoからのデータを取得できるようにしている。取得したデータを用いて画面の角度を変更することで、ガンコントローラの向いた方向にゲーム画面を向けることが可能となっている。そして周りに破壊対象のオブジェクトを作成し、動くオブジェクトを破壊することで点数を加算する方式とした。
 追加機能としては、背景の明るさを現実世界の明るさに適応させるため、分光器を用いて現実世界の光度を取得した上で背景を朝、昼、夜に変更するようにした。追加したい機能としては、ガンコントローラの精度向上、ビット誤りの減少、ランキング機能の実装、ステージの追加が挙げられる。改善案としては、XBeeからWi-fiモジュールへの変更によるデータ転送量の増加が挙げられる。
C言語を用いた簡易ヘルプアシスタント
 ライブラリはlibgtk3-devを用いた。プログラムを動作させると、まずヘルプアシスタントが画面上のどこかに出現する。出現したヘルプアシスタントは、画面をゆっくりと進んでいく。ヘルプアシスタントをクリックすると、会話やアプリケーションの起動、簡易的な対戦ゲームの起動、ファイル管理、タイマーの設定などを行うことができる。会話は簡単なものしかできないが、単語を認識して会話を行う。アプリケーションの起動では、よく使っているアプリケーションを登録しておくことで、よく使うアプリケーションのどれかまたは新しいアプリケーションを起動することができる。簡易的な対戦ゲームでは、ヌメロンというゲームでヘルプアシスタントと対戦することが可能となっている。ファイル管理では、バックアップしておきたいファイルや検索したいファイルを打つことで、ファイルの検索やバックアップを行う。タイマーの設定では、時間を設定してタイマーをスタートすることで、タイマーが起動する。追加したい機能としては、SNSへの対応などが挙げられる。改善案としては、会話機能の高精度化、機能の充実などが挙げられる。
C言語を用いたRTA*検索でのお助け付き8パズルゲーム
 ライブラリはlibgtk3-devを用いた。プログラムを動作させると、まずファイルをドラッグ&ドロップする画面が開く。画像ファイル以外は受け付けないようになっており、画像ファイルを入れると、ドラッグ&ドロップした画像を9分割して8パズルゲームがスタートする。8パズルでは、横に1手戻る, 1手進む, 初手配置に戻す, 初手配置をリセットする, お助け機能が存在する。お助け機能をクリックすると、RTA*探索を行ったのち、動かすパズルに色をつける。RTA*探索は5手先まで評価する。追加したい機能としては、LRTA*探索の実装が挙げられる。
C言語を用いたSSL/TLSマルチTalkサーバ・クライアント
 ライブラリはlibssl-dev, libmysqlclient-devを用いた。サーバ側のプログラムを動作させると、SSL/TLS通信が行えるように設定を行なったのち、サーバを起動する。作成時では、TLS1.2を用いている。また複数クライアント受信できるよう、selectを用いている。サーバはクライアントからのコネクション確立要請があると、accept関数を用いてコネクションを確立する。この時、SSL/TLS通信を行えるように
サーバとクライアントはSSL/TLSのHandslakeプロトコルを用いて確立を行う。そしてユーザ名・パスワードを受信することで、マルチTalkを行えるようにする。ユーザ名, パスワード, 会話内容は全てデータベースに保管され、ログイン時間、ログアウト時間はログファイルに出力される。追加したい機能としては、ファイル送受信プロトコルの実装などが挙げられる。
C言語を用いた簡易HTMLサーバ
 ライブラリはlibevent-devを用いた。プログラムを動作させると、epoll/kqueueを用いた複数クライアントへの対応を行うために設定を行う。設定後、コネクション確立要請を受けた時に動作するイベントを登録しておく。もしコネクション確立要請のイベントが発火した時、コネクションを確立した上で新たなイベントを登録する。新たなイベントが発火した時、HTTPヘッダーをパースして送信内容を確定する。送信の際には、スレッドを用いて高速化を図っている。送信を行なったのち、イベントを削除する。以上の手順を踏むことで、複数クライアントに対応したepoll+thread型HTMLサーバが起動する。追加したい機能としては、自作のHTTPヘッダーのパースのHTTP2.0への対応、サーバのSSL/TLS対応などが挙げられる。改善案として、epoll+threadをepoll+prethreadにすることが挙げられる。

共-1(3) 開発記のブログやスライドの資料

なし

共-1(4) TwitterアカウントやGithub、ブログのアカウントやURL

Twitterアカウント : who3411

共-2(1) 印象に残っている技術的な壁

・readとfread、writeとfwriteの違いを探る時に、glibcソースコードから違いを探ろうとした。その時のソースリーディングの方法

共-2(2) 共-2(1)を乗り越えるための解決法

・readとfread、writeとfwriteの違いを探る時に、glibcソースコードから違いを探ろうとした。その時のソースリーディングの方法
 まず普段使わないようなマクロの使い方(#演算子,##演算子を含んだマクロなど)について一つ一つ調べて、最低限ソースリーディングを行えるような状態にした。次にソースリーディングを行なったことがある先輩に、どのように読んでいけば良いのかのアドバイスをもらった。結果的にreadはアセンブリシステムコールを行っていたこと、freadはバッファリング関連の処理を行なったのちに_IO_SYSREADを用いてread関数を呼び出していたことがわかった。

共-2(3) その壁を体験している初心者にアドバイスするとしたらどうする?

・readとfread、writeとfwriteの違いを探る時に、glibcソースコードから違いを探ろうとした。その時のソースリーディングの方法
 glibcなどでは、マクロが多くてソースリーディングが難しいので、まずは自分がわからないマクロの記述を読めるようにしてからソースリーディングした方が良い。マクロを読めるようになったら、grepを用いて目的の関数に近いと思われる関数を探し、ctagsなどを使って探すと良い。

共-3(1) 受講したいと思っている講義

受講できるのであれば全て受講したいが、その中でも受けたい講義は以下の通りである。
Linuxカーネルを理解して学ぶ脆弱性入門
 現在、私はLinuxカーネルの解読を行いたいと思っている。そのためLinuxカーネルを理解する講義であり、かつ興味ある脆弱性に関する講義であるため受講したい。
カーネルエクスプロイトによるシステム権限奪取
 バッファオーバーランを起こし、/sh/binを起動させたことはあるが、システム権限の奪取といったことは行ったことがない。またブラウザの脆弱性を組み合わせた高度な攻撃と書いてあり、とても興味が湧いた。
・Embedded System Reverse Engineering 101
 組み込みシステムのリバースエンジニアリングは、前に聞いてから一度実験してみたいと思っていた。しかし実際に組み込みシステムの解析を行ったことはない。そのため専門家のいる中で、リバースエンジニアリングを一度体験してみたいと思っている。
・暗号運用技術
 私がこれまで作成してきたプログラムでは、SSL/TLS通信や暗号化を用いたことはあるものの、ライブラリに頼ったものである。情報処理安全確保支援士の試験勉強をしていた時に、ある程度暗号運用については学んだが、現状では曖昧な理解にとどまっていると感じている。そのため暗号運用がどのように行われているのか、どのような脆弱性が原因となって盗聴が行われるのかなどを知りたい。
・LSMから見たLinuxカーネルのセキュリティ
 LSMについてはSELinuxを調べている時に聞いたことがあるが、実際に使って見たことはない。実際にサーバを運用するということがないため、本格的なセキュリティを行おうとしたことがないからである。LSMを用いることで、自身のセキュリティモジュールが作成できると聞き、一度触って見たいと思った。また安全で丁寧なプログラムを作成したいと思っていたため、本講義を是非受講したいと思った。
・ファジング実習
情報処理安全確保支援士の試験勉強をしていた時に、ファジングという言葉を聞いたことはあったものの、脆弱性検出に使われるということしかわからなかったため、どのようにして行うのかは知らないままの状態である。今後、セキュリティが更に重要となってくると思われる社会において、ファジングを学ぶことは必要であると感じている。学習だけでハンク、実践も行えるということなので、行ってみたいと思った。

共-3(2) セキュリティキャンプでやりたいこと

セキュリティキャンプでは、セキュリティに関する学習・実践を通した技術の取得はもちろんのこと、Linuxカーネルに関する知識なども学びたいと思っている。特に機器を用いた実践は、滅多に行うことができない重要な機会であると思っている。実践を通すことで、知識を定着させるとともに、知識をどのように活かせば実践にも活かすことができるのかを身に付けたい。

選択問題

選択A-1 添付ファイルの通信から読み取れることなど

 解答中にあるNo.については、添付ファイルにあるパケットの順番を示す。また192.168.74.1をクライアント、192.168.74.130をサーバと呼ぶ。
 まずNo.1~3について述べる。ここでは、特に変わった通信は行われておらず、通常の3ウェイハンドシェイクが行われていると考えられる。もしARPテーブルにサーバのMACアドレスが登録されていないとすれば、No.1~3の前にARPの通信が行われているはずである。しかし今回は、通信フローを検知したのみであり、ARPテーブルがどのようであったかを判断することが不可能であるため、ARP通信の有無は問題ではないものの、通信フローに欠けている可能性がある。またサーバの名前解決が行われていない場合、No.1~3の前にDNSの通信が行われているはずである。こちらについても、サーバへのアクセスにIPアドレスを直接URLとして用いたのか、ホスト名を用いたのかが不明である。そのためDNS通信の有無は問題ではないものの、通信フローにかけている可能性がある。
 次にNo.4~5について述べる。No.4では、struts2-rest-showcase/orders.xhtmlに対してGETオプションを用いて、HTTPリクエストを送信している。またNo.5では、No.4でのHTTPリクエストがサーバに届いたことを通知している。事実、No.4のLengthは1146ではあるが、キャプチャした内容をWiresharkで確認すると、[Next sequence number: 1093]と書かれており、次のクライアントのシーケンス番号及びサーバの確認応答番号が1093となることがわかる。No.5のサーバからクライアントへのTCP送信の際には、確認応答番号が1093になっているため、通信が正常に行われたことを示している。しかしNo.6以降にGETに対するHTTPレスポンスが存在しないため、今回の通信フローにはHTTPレスポンスが欠けている。
 No.4について詳しく見てみると、Full request URIが「http://192.168.74.130」を先頭に記述されている。これは、No.1~3で述べたDNS通信の可能性が存在しないことを示す。そのためNo.1~3のDNS通信は欠けているわけではなく、初めから存在しない通信であることがわかった。次にContent-Typeを見てみると、通常ではありえないような文字列が記述されており、何らかのプログラムであることが推察される。調べてみると、https://www.ipa.go.jp/security/ciadr/vul/20170308-struts.htmlに書かれているCVE-2017-5638において、Apache Struts 2が影響し、リモートから任意コードが実行可能であることがわかった。Content-Typeに書かれているプログラムを見てみると、`cat /etc/passwd`が書かれていること、windowsまたはそれ以外において、cmd.exeまたは/bin/bash -cに加えて`cat /etc/passwd`が実行されていると推察できるプログラムが記述されていることから、サーバの/etc/passwdファイルを取得しようとしていると考えられる。以上から、No.4はCVE-2017-5638を悪用した通信であること、No.6以降に存在するはずの/etc/passwdファイルのキャプチャデータが存在しないことがわかる。
 次にNo6~7, 10, 13~14について述べる。ここでは、クライアントがサーバに対してSSH通信を行なっている。SSH通信では、初めに行われるはずの3ウェイハンドシェイクに関するパケットが存在しないため、3ウェイハンドシェイクのパケットデータが欠けていると考えられる。クライアントの確認応答番号が増え続ける一方、シーケンス番号が一切増えないことから、サーバから送られてくるデータを受け取っているだけであると考えられる。この時、もし受け取っているデータが先ほどNo.4で脆弱性を狙って取得しようとした/etc/passwdであれば、GETに対するHTTPレスポンスは、SSHを通じたポートフォワーディングで行われているのではないかと考えられる。もしそうであるとすれば、SSHに関する通信記録が存在しないことから、ポートフォワーディングで送信されているデータが欠けていると考えられる。
 最後にNo.8~9, 11~12について述べる。No.8~9, 12では"TCP ACKed unseen segment"、No11では"TCP Previous segment not captured"がそれぞれ発生している。"TCP ACKed unseen segment"は、正常にパケットが届いているもののWiresharkではそのパケットを認識することができなかった場合に発生する。また"TCP Previous segment not captured"は、直前のパケットが正常に届いていない場合に発生する。ただし"TCP Previous segment not captured"は、Wiresharkの処理速度によっても発生することがあるので、必ずしも届いていないとは限らない。また2つは同様の現象から発生する可能性も存在する。
 No.8~9では、確認応答番号が1464になっていることから、No1~7までの間に1463オクテットのデータをサーバから取得しているが、Wiresharkではキャプチャされていないと考えられる。またNo.7とNo.8の間のtimeを確認すると、約60ミリ秒遅れていることがわかる。60ミリ秒遅れた上でエラーが発生したということは、サーバがDoS攻撃などといった何らかの攻撃を受けている可能性がある。もし攻撃を受けているのであれば、サーバが攻撃を受けている時のパケットデータが欠けていると考えられる。No.11ではサーバ側からクライアントへデータを送信しているが、正常に届いていないことがわかる。そのため、後から送信されている可能性も存在する。No.12ではクライアント側からサーバへデータを送信しているが、これは確認応答番号が1465になっていることから、No.11で送信されたと考えられるデータは正常に送信されていたのではないかとも考えられる。ただしNo.12のパケットは、Wiresharkではパケットをキャプチャできていない可能性が存在する。以上のことから、No.8~9, 11~12は、コネクションの切断である4ウェイハンドシェイクを、Wiresharkから見るとエラーが発生している状況下で行っていたと考えられる。
 ここまでのことから、今回の通信フローでは、ARPやHTPレスポンス、SSH通信のデータなどが欠けている可能性が存在すること、No.4でCVE-2017-5638のApache Struts 2を狙った脆弱性攻撃を行っていること、Wireshark内ではエラーが発生していたと考えられる状況下でコネクションを切断していることなどが考えられる。つまりこの通信が意図していることは、サーバ側に存在する/etc/passwdのデータを取得することであり、そのデータを元にブルートフォース攻撃や辞書攻撃を用いたサーバへのSSH接続を行っていくのではないかと想定される。

参考文献:
[1]Wireshark User's Guide, https://www.wireshark.org/docs/wsug_html_chunked/, 2014

選択A-4 printfとforkについての説明

調べたもの: printf()関数
問題解答環境
OS: Fedora25
gcc: 6.3.1

まず以下のようにmyprintf1.c, myprintf2.cを用意した。
・myprintf1.c
#include <stdio.h>
int main(void){
printf("hello world\n");
}
・myprintf2.c
#include <stdio.h>
int main(void){
int i = 12345;
char *name = "hello world!\n";
printf("%s : %d\n", test, i);
}
 次にmyprintf1.cをgcc -S -o myprintf1.s myprintf1.cのようにアセンブルすると、myprintf1.s内にcall putsが現れた。これは、printf()関数を用いるよりもputs()関数を用いたほうが最適化が行われるとコンパイラが判断したからだと考えられる。また.rodataが現れた。.rodataの内容を探るためにobjdump -s -j .rodata myprintfコマンドを実行すると、.rodataの内容として"................hello."という内容を見ることができた。
 次にmyprintf2.cをgcc -S -o myprintf2.s myprintf2.cのようにアセンブルすると、myprintf2.s内にcall printfが現れた。今回はprintf()関数を用いてフォーマット通りに出力する必要があるからである。12345という数値に関しては、movl $12345, -4(%rbp)という記述があり、ここで格納していることがわかる。また.rodataが現れた。.rodataの内容を探るためにobjdump -s -j .rodata myprintf2コマンドを実行すると、.rodataの内容として"hello world.%s : %d.."という内容を見ることができた。
 次にmyprintf2.cをgcc -o myprintf2 myprintf2.cのようにコンパイルして、objdump -d myprintf2コマンドを実行して逆アセンブルすると、objdumpを行ったmain内にcallq 4003f0 <printf@plt>が現れた。printf@plt内ではjmpq *0x0200c22(%rip) #601018 <_GLOBAL_OFFSET_TABLE_+0x18>が現れた。0x601018を探すためにreadelf -a myprintf2を行うと、'.rela.plt'内にR_X86_64_JUMP_SLO型のシンボル名printfを見つけた。
 以上のことから、固定文字列は.rodataセクションに格納されること、固定数値はアセンブリ上で即値として処理されること、_GLOBAL_OFFSET_TABLE_によってprintfなどといった関数群がまとめられていると考えられることなどがわかった。

 次に、printf()関数の内部を探るためにglibcをインストールした。インストール方法としては
sudo dnf download --source glibc
sudo rpm -ivh glibc-2.24-4.fc25.src.rpm
cd rpmbuild/SOURCES/
tar zxvf glibc-2.24-33-ge9e69e4.tar.gz
のようにコマンドを入力することでインストールした。
stdio-common/printf.cを見ると、
va_start(arg, format);
done = vfprintf(stdout, format, arg);
va_end(arg);
とある。va_startとva_endについては、可変長配列の開始・終了を示している。vfprintf関数を見ると、JUMPマクロが多く存在する。このJUMPマクロを用いて、goto文でLABELマクロで記述されたラベルに移動することで、フォーマットを処理している。JUMPマクロを用いる際には、REFマクロを用いて、どの値であればエラーが発生するか、異なるステップへ移動するか、どの型の値を出力するかといったstep_jumps配列が存在する。step_jumps配列は記述されている状態でstep0, step1, step2などに分かれていく。決められた書式に従ってだんだん遷移先が変わっていく。最終的に一つの書式を取り出すと、process_argとprocess_stinrg_argによって必要な書式が処理されたのち、書式に従って出力処理が行われる。なおstep_jumps配列は、初めの%を識別した後に行われるが、初めの%を識別する処理は__find_specwc()関数または__find_specmb()関数によって行われる。もし確保している領域が足りない上で書式に従って変更していく場合、alloca()関数などを用いて領域を確保している。
 結果的に、printf()関数を呼び出すと、内部でstdoutをファイルディスクリプタとしたvprintf()関数が呼び出されること、初めの'%'を識別した上でjump_table配列やstep1, step2といったstep_jump配列を用いて書式をパースしていること、パースした結果をprocess_argマクロとprocess_string_argマクロによって書式通りの値になるように内部処理していることなどがわかった。
 ここで、ポインタに関する処理を観察するために、以下のようなmyprintf3.cを作成した。
・myprintf3.c
#include <stdio.h>
int main(void){
printf("%p\n", NULL);
printf("%p\n", "a");
}
myprintf3.cをコンパイルして何度か実行すると、
printf("%p\n", NULL);は毎回(nil)
printf("%p\n", "a");は毎回同じアドレス
が表示される。
 NULLについては、vprintf()関数をトレースしていくと、process_argマクロで
string = (CHAR_T *)L_("(nil)");
goto LABEL (print_string);
と記述されている。この部分のプログラムを実行する条件はポインタがNULLである場合である。そのため、NULLを引数に"%p"のprintf()関数を実行すると、毎回同じ(nil)が出力される。
 "a"については、vprintf()関数をトレースしていくと、process_argマクロで
base = 16;
number.word = (unsigned long int) ptr;
is_negative = 0;
alt = 1;
group = 0;
spec = L_('x');
goto LABEL (number);
と記述されている。この部分のプログラムを実行する条件はポインタがNULLでない場合である。そのため、"a"を引数に"%p"のprintf()関数を実行すると、毎回同じアドレスが出力される。毎回同じアドレスが出力されるのは、スタック領域に書き込まれた同じアドレスの値を用いているためである。またポインタの値を出力する場合はnumberとして処理されることがわかった。

参考文献:
[1]ポインタの話をしていたらいつの間にか配列の初期化とかglibのprintfとかを読んでいた話, http://attonblog.blogspot.jp/2014/07/glibc-printf.html, 2014

選択A-8 セキュリティ技術で最も興味のあるテーマ

最も興味のあるテーマ: PKI(公開鍵基盤)
 PKIは、暗号化やデジタル署名を行うことで、守秘性・認証・完全性・否認防止などといったセキュリティ対策を行うことができる技術である。暗号化方式やハッシュ化方式については、いくつもの種類が生まれており、現在でも暗号化・復号時のブロック数を大きくすることによって技術力を高めている節がある。しかしPKIでは、PKIを行うための方式は大きく変化することなく今日まで続いており、完成度の高い技術であると言える。SSL/TLSでのサーバ証明書として用いることができる点が普及するきっかけになったのではないかと考えられる。
 X.509規格に沿った電子証明書を作成することで、偽造することは可能である。事実、私自身も個人用のX.509規格の電子証明書を作成して、SSL/TLS通信を行ったことがある。PKIでは、そのような偽造を行うことができないよう、上位の認証局であるCAからディジタル署名を得る必要がある。上位の認証局からのディジタル署名をもらい、その上位の認証局がさらに上位の認証局からのディジタル署名を得る階層構造によって、利用者から信頼を得ることが可能である。そのため、自ら作成した電子証明書は自己証明書でしかなく、信頼を得ることは到底不可能である。
 PKIに用いるディジタル証明書には、フォーマットのバージョン情報やシリアル番号、証明する公開鍵の情報、有効期限などが含まれている。またオプションとして認証局や認証対象に付与されるユニークIDなども存在する。これらの情報を全てまとめてハッシュ化することで認証局からのディジタル署名として機能する。ディジタル証明書の呼び方は用途によって変化する。例えばクライアント認証に用いるディジタル証明書であればクライアント証明書、S/MIMEで用いるディジタル証明書であればS/MIME証明書などとなる。ディジタル証明書を発行するように認証局に申請する場合、申請者はCSRを生成する。CSRには、公開鍵に加え、証明書を使用するサーバのURLや組織名、部門名などといった情報を記述する。これらの情報を証明書に付与する。ディジタル証明書の有効期限が切れた場合、ディジタル証明書を再発行する必要がある。また何らかの理由によって有効期限前に証明書が失効された場合についても、ディジタル証明書を再発行する。
 先ほど述べたように、電子証明書を作成する際にはX.509規格に従う必要があるが、現在はX.509v3に改訂が行われた状態のものが使用されている。改定前には証明書に拡張領域を設けていたが、改定後には属性証明書であるAC、ACの失効リストであるACRLが新たに定義された。ACでは所有者の役割や権限といった情報を証明する。ACはディジタル証明書とは異なり、属性認証局と呼ばれるAAから発行される。
 PKIでは、先ほど述べたようなCAやAA以外にも以下のような要素から構成されている。
・RA
 証明書発行や失効といった審査の実施、ディジタル証明書利用者情報の登録、鍵の一括管理、、公開鍵を公開するためにリポジトリへ保管、証明書や鍵の配布などを行う。RAでは、ディジタル証明書保持者の身元を保証している。場合によっては、CAがRAを兼ねている場合も存在する。
・VA
 ディジタル証明書失効情報の集中管理、公開鍵での署名検証、ディジタル証明書有効期限の確認、CRLの確認などを行う。
リポジトリ
 ディジタル証明書利用者の情報やディジタル証明書、CRLなどを格納し、検索などのサービスを提供するシステム。LDAPを用いてることが多い。
・CRL
 ディジタル証明書の悪用や誤発行など、何らかの要因によって発生した不測事態によって有効期限内に失効させるディジタル証明書が登録されたリスト。ディジタル証明書が悪用されたなどの事故があればすぐに登録される。ディジタル証明書の有効性を検証する場合には、有効期限はもちろんであるが、CRLへの登録の有無についても確認する必要がある。CRLへの登録は、有効期限が過ぎた時点で終了してしまうため、確認時点ではすでに削除されている可能性も存在する。CRLの更新頻度はCAによって異なるが、12時間程度で更新されることが多い。CRLには、CRL発行日時や次回発行日時、CRLフォーマットバージョン情報などが書かれており、その後ろに失効証明書のリストが格納されている。CRLには以下のような種類が存在する。
-完全CRL
 1つのCRLに全ての失効情報を記載したもの。大規模ドメインでの運用はデータサイズが巨大なものになってしまうため、利用者のCRL取得負荷が重くなってしまうが、適切な規模での運用を行うことで、利用者の取得時間が効率化され、管理も容易になる。
-区分CRL
 完全CRLに対し、複数のCRLに分割して公開する。シリアル番号や失効理由といった、何らかの要因によってCRLを分割することで、CRLのサイズを小さくしている。それ以外にも、CRLの所在が証明書に記載されることから、利用者がCRLの所在を容易に知ることができる。
-デルタCRL
 ベースとなるCRLを発行し、そのCRLの失効情報の差分を記載したCRL。証明書利用者は、ベースとなるCRLと差分のCRLを取得したのち、各失効情報を足し合わせることで完全な状態のCRLを取得することが可能となる。転送効率を高めることが可能である。完全CRLもしくは区分CRLに用いられる。
-間接CRL
 複数のCAから発行されたCRLをまとめて一つのCRLとして発行するCRL。間接CRLには、発行者の署名がつけられるため、利用者は発行者が信頼にたる者であるかどうかを確認する必要がある。複数のCAを利用している利用者が1つのCRLを見れば良いため、確認が容易になる。
-ARL(認証局失効リスト)
 CRLが利用者のディジタル証明書に対する証明書失効リストであるのに対し、ARLはCAのディジタル証明書に対する証明書失効リストである。証明書の有効期限内に鍵が危殆化した場合や相互認証基準違反を犯した場合に、自己署名及び相互認証に用いられた証明書が両方とも記載される。
-CRT(証明書失効ツリー)
 ハッシュツリーを用いて失効情報を証言するための技術。OSCPのバックエンドとして使用されている。

 またCRLを速く取得するための技術は以下のようなものが存在する。
-OSCP
 ディジタル証明書の有効性を、発行されたCRLの情報からリアルタイムで確認する仕組み。OSCPを実装したサーバであるOSCPレスポンダに利用者が問い合わせることで、CRLの取得・照合を行うことが可能となっている。しかしOSCPレスポンだでは失効情報について調べるだけであるため、信頼関係についてはチェックを行わない。場合によっては、複数のOSCPレスポンダに対して問い合わせを行わなければ、目的のCRLを取得することができない可能性も存在する。
-DPV+DPD
 「パス検証(Path Validation)とパス構築(Path Discovery)をサーバに任せるもので、電子証明書の検証方針などをクライアント側が持つことができるプロトコル」[1]。計算能力や処理をサーバ側に任せることで、クライアント側の処理の低減を図っている。
-SCVP
検証専用のサーバを作成することで、OSCPで行われなかった信頼関係のチェックを行うことが可能となっている。

以上の構成要素によって、高信頼性を保ちつつ、情報伝送の効率化を行っている。
 PKIを行う上で、ディジタル証明書はもちろん必要であるが、電子的な署名を行うディジタル署名についても、ディジタル証明書を構成する重要な要素である。ディジタル署名は、以下のような手順で行われる。([3]参照)
1.送信文書をハッシュ関数の引数とすることで、送信文書のメッセージダイジェストを作成する。
2.作成したメッセージダイジェストを送信者の秘密鍵で暗号化、ディジタル署名を作成する。
3.送信文書, ディジタル署名, ディジタル証明書を送信する。
4.受信者は文書のみを取り出し、送信者と同じハッシュ関数を用いてメッセージダイジェストを作成する。
5.受信者は受信データ中のディジタル署名と送信者のディジタル証明書を取り出し、送信者のディジタル証明書内に存在する公開鍵を用いて復号を行う。
6. 4で作成したメッセージダイジェストと5で復号したメッセージダイジェストを比較することで、完全性、正当性を確認する。
ディジタル署名のフォーマットには、PKCS#7を拡張したCMSが用いられる。CMS以外の方式としてはXMLディジタル署名を行うXMLディジタル署名が存在する。
 XMLディジタル署名では、Enveloped署名, Enveloping署名, Detached署名の3つが存在する。Enveloped署名は署名対象のオブジェクト内部に署名が置かれ、Enveloping署名は署名内部に署名対象のオブジェクトが置かれ、Detached署名は署名対象のオブジェクトと署名が独立しておりURIによってオブジェクトを参照する。

 ここまではディジタル証明書に関する話題を行なってきたが、PKIには他にもいくつかの技術が存在する。その中でもタイムスタンプについて述べていく。タイムスタンプはe-文書法の施行などによって、電子データの長期保存を前提とした問題解決の手法であり、タイムスタンプとディジタル署名を組み合わせることでいくつかの問題を解決することが可能となる。
 電子文書といった電子データは、年が経つにつれて変化するようなものではなく、長期間の保存を行うだけだとしたら適した手法であると言える。しかし電子データは、複製や作成日時の偽造を容易に行うことが可能である。その影響もあり、本来作成された日時や原本を書いた作成者を特定することが難しい。そこで解決方法としてタイムスタンプを用いる。タイムスタンプは、時刻認証局であるTSAが時刻情報を含んだ状態で付与する。このタイムスタンプによって、電子文書が作成された日時、時刻以降の改ざんが行われていないことを保証することが可能となる。2005年には、「タイムビジネス(時刻配信及び時刻認証業務の総称)を提供する事業者が, 適切な技術, 運用, 設備の基準を満たし, 業務が厳正に実施されていることを認定する」[3]タイムビジネス認定制度が運用されている。
 上記の方法を用いることで、先ほど述べた作成時刻や改ざんに関する問題は解決することができるが、このままでは記録媒体の劣化、記録媒体や電子文書作成技術の衰退などといった問題が解決できていない。年が経っても変化することのない電子文書は、長期保存には適した手法ではあるものの、周りの技術によって、その有用性が確保されづらいのが難点である。他にも自然災害発生時の電子文書の紛失などに対しても、適切に対処する必要がある。
 電子文書を長期保存する場合、いくつかのファイル形式が推奨されている。例えば、フォーマットが公開されていてかつ他の文書形式からも変換することが可能なPDF/A形式、OSやアプリケーションに依存せずに利用できる上で画像の劣化が少ないTIFFイメージ形式などが存在する。現在、国立国会図書館などでは電子データの長期保存化が進んでいる。また複数の電子データ長期保存サービスを提供している会社も存在する。
 タイムスタンプは以下の手順によって生成される。([3]参照)
1.タイムスタンプ取得要求者が電子文書をハッシュ関数を用いてハッシュ化し、ハッシュ値を生成する。
2.1で生成したハッシュ値をTSAに送信する。
3.TSAは時刻配信局であるTAから時刻を受け正確な時刻を保持する。
4.TSAは受け取ったハッシュ値に時刻情報を連結したデータを、改ざん防止処置を行なったのちにタイムスタンプとして生成する。
改ざん防止処置には以下のようなものが存在する。
ディジタル署名
TSAがCAから公開鍵証明書の発行を受けた専用の暗号鍵を用いて各タイムスタンプにディジタル署名を施すことで信頼性を確保する。
・リンキング方式
TSAが複数の利用者のMDを関連づけたリンク情報を生成してタイムスタンプに含め、それぞれのタイムスタンプを他のリンクしているタイムスタンプに依存させておくことで、信頼性を確保する。
・アーカイビング方式
TSAが受信したハッシュ値と正確なタイムスタンプ付与時刻を特定する情報を、タイムスタンプ検証の際の照合用データとする。
5.TSAは生成したタイムスタンプを送信元に返信する。
 ここまでに述べたタイムスタンプの方式では、ハッシュ関数や暗号技術が危殆化する恐れがある。もし破られるような状態になってしまった場合、タイムスタンプを付与したとしても完全性を証明することができない。そこで、過去にディジタル署名が有効であったことを検証できるようなタイムスタンプを付与することでこの問題を解決する。この方式は、何度もタイムスタンプを付与する方式であり、アーカイブタイムスタンプと呼ばれる。この方式を用いる場合、付与するたびに最新技術を用いたアーカイブタイムスタンプを用いる必要がある。

 ここまでがPKIに関する基礎的な技術である。これらの技術の一部については、オープンソースソフトウェアであるOpenSSLを用いることで実現することができる。OpenSSLはSSL/TLSプロトコル関連のライブラリであるが、PKIを構築することも可能である。
 構築環境はFedora25, Openssl 1.0.2k-fipsを用いている。また[4]を参考にしている。まずCSRを作成するための秘密鍵を作成するには`openssl genrsa`コマンドによって作成することが可能である。この時、出力ファイルや鍵の方式、ビット長などをオプションでつけることができる。また秘密鍵を作成する際、オプションの付け方によってはpass phraseをつける必要がある。秘密鍵を作成した後に`openssl req`コマンドによってCSRを作成することができる。この時、コンフィグファイルや用いる秘密鍵、出力ファイルなどをオプションで設定することができる。コマンドを実行すると、国名や都道府県名などを入力するように促されるので、入力内容に従って入力していく。CSRを作成した後に、`oepnssl ca`コマンドによって証明書を作成することができる。この時、コンフィグファイルや用いる秘密鍵、証明書の形式、出力ファイルなどをオプションで設定することができる。コマンドの実行が終了すると証明書の作成が終了する。ただし他の証明書の鍵を用いて証明書を作成しない限り、自己証明書となる点に注意する必要がある。
 結果的に`oepnssl genrsa`コマンド、`openssl req`コマンド、`openssl ca`コマンドの3つを用いるだけで秘密鍵CSR、証明書の3つを作成することが可能である。もし作成した自己証明書をルートCAとするのであれば、先に作成した証明書の鍵を用いて次に作成する証明書の鍵とすれば良い。それだけでは作成した証明書からルート証明書を探索することはできないので、2つの証明書に対して`openssl x509`コマンドを用いて、証明書から必要な情報のみにした証明書を別途作成し、別途作成した2つの証明書をつなぎ合わせて一つの証明書にすると良い。

 最近のPKIに関する記事としては[5]が挙げられる。[5]は、IoTデバイスメーカーに向けて電子証明書を発行するサービスを提供する発表を、GMOグローバルサインが行ったものである。IoTの普及によりデータをやり取りすることが増えたこの世の中において、電子証明書を大量に発行できるサービスは魅力的なものである。また認証局についてもパブリック認証局とプライベート認証局から選べる点についても良い点であると感じる。プライベート認証局であれば、証明書の最長有効期限が40年も持つため、プライベート空間のネットワークで電子証明書を利用するのであれば、とても良い選択肢の一つである。IoTの全てに対して電子証明書を発行してPKIを適用するのは難しいことではあるが、セキュリティの向上を行う手段としては手頃なものであるとも感じる。
 
参考文献:
[1]PKI技術関連情報, https://www.ipa.go.jp/security/pki/index.html, 2012
[2]電子認証フレームワークIPアドレス認証の展開に関する調査報告書, https://www.nic.ad.jp/ja/research/200707-CA/all.pdf, 2007
[3]上原孝之, 情報処理安全確保支援士2017年度版, 翔泳社, 2017
[4]OpenSSLによるPKI構築, http://www.prosper2.org/devwiki/index.php?OpenSSLによるPKI構築, 2016
[5]GMOグローバルサイン、IoTデバイス向けのSSL証明書大量発行サービスを開始, http://www.atmarkit.co.jp/ait/articles/1705/08/news075.html, 2017