月別アーカイブ: 2014年7月

GnuPG key signの作業をする(signing-party/caff)

先日JNUGの総会へ行ってきて、OpenPGPの鍵の本人確認をしてきました。その後にやるべき作業を、忘備録として記しておきます。

key signの作業を楽にするためのツールはいろいろありますが、今回はsigning-partyパッケージに含まれるcaffを使います。

Package: signing-party
Version: 1.1.4-1
Maintainer: Thijs Kinkhorst 
Description-ja: 各種 OpenPGP 関連ツール
 signing-party はあらゆる種類の PGP/GnuPG 関連ツール集で、キーサイン、
 キーリングの分析、キーサインパーティの準備用ツールを含んでいます。
 .
  * caff: "CA - Fire and Forget" 鍵にサインしてメールを送信します
  * pgp-clean: 自己署名以外の全署名を鍵から削除します
  * pgp-fixkey: 鍵から破損したパケットを除去します
  * gpg-mailkeys: サイン済みの鍵をその所有者へ単純にメール送信します
  * gpg-key2ps: 指紋を短冊にした PostScript ファイルを生成します
  * gpgdir: 再帰的にディレクトリを暗号化するツールです
  * gpglist: あなたの UID にサインした人を表示します
  * gpgsigs: GnuPG 鍵の一覧に対してサイン済みの鍵に注釈を付けます
  * gpgparticipants: パーティ参加者の一覧を主催者向けに作成します
  * gpgwrap: パスフレーズ用ラッパーです
  * keyanalyze: キーリングの minimum signing distance (MSD) を分析します
  * keylookup: gpg --search の ncurses ラッパーです
  * sig2dot: GnuPG 署名の一覧を .dot ファイルに変換します
  * springgraph: .dot ファイルからグラフを作成します
Homepage: http://pgp-tools.alioth.debian.org/

pkgsrcにはcaff単独でsecurity/caffがあるので、そちらを使いましょう(実際にはsigning-partyのtar ballを取得します)。

まず、ID確認の完了したユーザーの公開鍵を入手します。公開キーサーバーに登録されていることもありますし、人によっては公開していない場合もあります。後者の場合はメールなどで直接受け取ってください。キーサーバーから取得する方法は以下のようになります。

$ gpg --keyserver pgp.nic.ad.jp --recv-keys "keyid"
gpg: 鍵xxxxxxxxをhkpからサーバーpgp.nic.ad.jpに要求
gpg: 鍵xxxxxxxx: 公開鍵“User Name <user@example.com>"を読み込みました
gpg: 最小の「ある程度の信用」3、最小の「全面的信用」1、classic信用モデル
gpg: 深さ: 0  有効性:   3  署名: 127  信用: 0-, 0q, 0n, 0m, 0f, 3u
gpg: 深さ: 1  有効性: 127  署名:  33  信用: 126-, 0q, 0n, 0m, 1f, 0u
gpg: 次回の信用データベース検査は、2016-07-04です
gpg:     処理数の合計: 1
gpg:           読込み: 1  (RSA: 1)

今回はpgp.nic.ad.jpを使いましたが、他のキーサーバー(pgp.mit.edu)等にあることもあります。

公開鍵を入手したら、手元にあるはずの指紋(fingerprint)と、取得した公開鍵の指紋が一致するか確認しましょう。

$ gpg --fingerprint 9C0C1404
pub   4096R/9C0C1404 2009-09-11
                 指紋 = 9945 2B4D D28B EEAC 8AB5  C931 B066 62EC 9C0C 1404
uid                  NOKUBI Takatsugu <knok@daionet.gr.jp>
uid                  NOKUBI Takatsugu <knok@debian.org>
uid                  NOKUBI Takatsugu <knok@namazu.org>
uid                  NOKUBI Takatsugu <knok@fsij.org>
sub   4096R/07098680 2009-09-11
sub   2048R/861243E1 2012-08-23

これを、ID確認したユーザーの数だけ実施します。確認ができたら、ようやくcaffの出番です。

$HOME/.caffrc を作成します。caff –help等を実行すれば、現在の環境を見てとりえあずデフォルトの値を埋めたものが自動生成されます。作成されたものを自分の環境に合わせて修正してください。以下は私の設定例です。

# .caffrc -- vim:ft=perl:
# This file is in perl(1) format - see caff(1) for details.

$ENV{'MAILADDRESS'} = 'knok@daionet.gr.jp';
$CONFIG{'owner'} = 'NOKUBI Takatsugu';
$CONFIG{'email'} = 'knok@daionet.gr.jp';
#$CONFIG{'reply-to'} = 'foo@bla.org';
$CONFIG{'bcc'} = 'nokubi+caff@example.com';

# You can get your long keyid from
#   gpg --with-colons --list-key 
#
# If you have a v4 key, it will simply be the last 16 digits of
# your fingerprint.
#
# Example:
#   $CONFIG{'keyid'} = [ qw{FEDCBA9876543210} ];
#  or, if you have more than one key:
#   $CONFIG{'keyid'} = [ qw{0123456789ABCDEF 89ABCDEF76543210} ];
$CONFIG{'keyid'} = [ qw{B06662EC9C0C1404 ];
# Select this/these keys to sign with
#$CONFIG{'local-user'} = [ qw{2BA82602C2CE8099 ACCBC06B6A2171ED B06662EC9C0C1404} ];

# Additionally encrypt messages for these keyids
#$CONFIG{'also-encrypt-to'} = [ qw{2BA82602C2CE8099 ACCBC06B6A2171ED B06662EC9C0C1404} ];

# Mail template to use for the encrypted part
#$CONFIG{'mail-template'} = << 'EOM';
#Hi,
#
#please find attached the user id{(scalar @uids >= 2 ? 's' : '')}
#{foreach $uid (@uids) {
#    $OUT .= "\t".$uid."\n";
#};}of your key {$key} signed by me.
#
#If you have multiple user ids, I sent the signature for each user id
#separately to that user id's associated email address. You can import
#the signatures by running each through `gpg --import`.
#
#Note that I did not upload your key to any keyservers. If you want this
#new signature to be available to others, please upload it yourself.
#With GnuPG this can be done using
#       gpg --keyserver pool.sks-keyservers.net --send-key {$key}
#
#If you have any questions, don't hesitate to ask.
#
#Regards,
#{$owner}
#EOM
$CONFIG{'mailer-send'} =  [ 'smtp', Server => 'localhost', Port => 10025 ,
        Envelope => 'knok@daionet.gr.jp', Debug => 1 ];

自分はカスタマイズしたsmtp設定をしています。mailer-sendについてはcaff(1)に解説がありますが、PerlのMail::Mailerが受け付けるパラメータを記述します。man Mail::Mailerに詳細がありますが、smtpの代わりにtestfileを指定すれば、メールを送信する代わりにファイルに保存するので、活用して動作確認をするとよいでしょう。

準備ができたら、caffを起動します。私は以下のようなスクリプトを使っています。

#!/bin/sh
caff -m yes -u B06662EC9C0C1404 `cat $1`

B06662EC9C0C1404 は私のlong key idです。出力させるにはgpg –with-colons –fingerprint shortid 等とします。

caffを起動すると、作業ディレクトリを作成した上で指定した公開鍵に署名をしてゆきます。署名の作業にはパスフレーズが必要です。何度も入力することになるので、gpg-agentを使うことをお勧めします。

一通り署名が完了すると、実際のkeyringに結果をコピーした上で、公開鍵のメールアドレス(id)あてに1通づつメールを送信します。同じように、相手もこちらに署名した公開鍵を送ってくるのを待ちましょう

以上が相手の鍵に署名をしてメールで送信する方法です。その結果をキーサーバーに送ることもできますが、相手が常にキーサーバーに後悔しているとは限らないので、その点注意しましょう(既知の公開鍵は誰でもキーサーバーに送信して公開できてしまう)。

逆に、相手から受け取った署名付き鍵の取り込みをする方法はまた別途記事として書く予定です。

Intel Celeron N2806のeMMC(RPMB)

ECS LivaというBay-Trail MベースのPCがあります。秋葉原の複数の店舗やAmazonで扱っています。2万円しない小型PCで、メモリ(2GB)とストレージ(eMMC 32GB)を搭載しているので、OSさえ用意すれば他には何もなくても使えるマシンです。

公式でUbuntu 14.04が動作すると書かれているのですが、やはりDebianを使いたいのでなんとかしてインストールしてみました。

しかし、wheezyのインストーラではストレージを認識できません。Linux kernel 3.8から入ったsdhc_acpiというホストドライバが必要なのですが、Debian wheezyの標準kernelは3.2と古いのが原因です。

結局、自分は一度Ubuntu Live USBイメージから起動して、debootstrapで頑張ってDebianをインストールするという手段で実現しました。Debianさえ入ってしまえば、backportsにある3.14 kernelがwheezyでも使えます。

最初はwheezy用のインストーラを作るべく頑張ってみたのですが、3.14 debian udebにsdhc-acpi.koが含まれていないというバグがあるため(kernel debにはある)、kernelパッケージを作り直す必要がありました。しかし作り直しても、eMMCデバイスは見えるけれどもアクセスすると固まるという問題があったため、挫折しました。

今のbackports kernelでは一応動いていますが、Replay Protected Memory Block(RPMB)と呼ばれる領域にアクセスできないという不具合があります。この警告はUbuntu kernelだと出ません。

[    3.202626] mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900
[    3.205033] mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900
[    3.207399] mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900
[    3.209806] mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900
[    3.212209] mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900
[    3.214579] mmcblk0rpmb: timed out sending r/w cmd command, card status 0x400900
[    3.214861] end_request: I/O error, dev mmcblk0rpmb, sector 8190

Ubuntu kernelからこの対応をやっている箇所をどうやって特定しようか、と考えていたら、対応している人の記事がみつかりました。

/dev/nell – RPMB eMMC errors under Linux

この記事ではASUS T100Aを対象としているようですが、おそらくLivaでも使えることでしょう。

KAKASIのコードについて

ここしばらくKAKASIのソースをいじっています。いい加減あたらしいバージョンをリリースして、しばらくは他のことをやりたいのですが、次に戻ってきたときいろいろと忘れそうなので、記録として残しておこうと思います。

そもそもKAKASIとは何か

オリジナルのKAKASIはたかはしもとのぶさんによって作成されたソフトウェアです。漢字、カタカナ、ひらがな、ローマ字を相互に変換する機能をもっています。SKKの辞書を用いて、

オリジナルのKAKASIに、単語を分割する「分かち書き」機能をパッチとして作成したのが、馬場さんです。馬場さんはこの機能を利用して、freeWAISやNamazuなどの全文検索ソフトウェアで日本語を扱えるようにしました。

自分もNamazuの開発にかかわる中で、パッチとしてKAKASIの機能をメンテナンスするのはしんどい、KAKASIのリリース自体長らく行われていない、といった理由で、Namazuの開発の一環としてKAKASIの開発を継承することをたかはしさんに打診し、受け入れられて今に至ります。

最近の作業

KAKASIのバージョンは長いこと2.3.4でリリースが止まっていました。2006年ごろ自分がリリースをしようとした痕跡があるのですが、その後Debian方面でlibtext-kakasi-perlのテストが通らなくなった等いろいろな要因で「これはリリースしないといけない」と思い、ようやく出せたのが2014/1/18です。このリリースで一番大きい変化はUTF-8のサポートです。といっても、iconvに依存しています。KAKASI本体がISO-2022-JP, EUC-JP, SJIS(cp932)の変換機能を持っているのですが、UTF-8対応のためにテーブルを持つのもどうかな、と思いiconvを使うようにして実装しました。

これでひとまず解決か、と思いきやperlモジュールでテストが通らない問題が直っていませんでした。何が起きていたかというと、分かち書きオプション-wを付加したときに、先頭に余計な空白を出力するために、期待されていた出力とは異なっていたのです。

このバグはDebianパッケージの自動ビルドで発覚しました。開発者がアップロードしたアーキテクチャ以外(mips, arm等)のパッケージは、自動的にビルドサーバーによってパッケージが作成されます。その時make testまで実行するので、ライブラリの変化によってバグが顕著化されました。

これを直すために作業を進めていたところ、さらに複数のバグが発覚し、それらの対応も必要になり、今に至ります。

KAKASIの基本データ構造Character

kakasi.hで様々なデータ構造が定義されていますが、文字を格納する基本となる型Character(実体はstruct character)が入出力の基本となります。

typedef struct character {
    char type;
    unsigned char c1, c2;
} Character;

typeは文字の種別を表し、0~5, 127の値をとります。値の定義は同様にkakasi.hで行われています

/* character set */
#define ASCII    0
#define JISROMAN 1
#define GRAPHIC  2
#define KATAKANA 3
#define JIS78    4
#define JIS83    5
#define OTHER  127

typeの値は常に正しい値が入っているわけではなく、マルチバイト文字が入力された直後はとりあえずOTHERを設定し、のちの処理に応じて適切な値に変更します。ASCIIとJISROMANはISO-2022-JP向けの値です。SI/SOによって、単なるASCIIと区別してJIS X 0212ラテン文字集合を選択できるのがISO-2022-JPの特徴です。主な違いは0x5Cが半角の”¥”(円記号)として定義されている点(ASCIIならバックスラッシュ)です。

Character型の変数は、多くの場面で入力バッファと出力バッファを兼ねています。なのでソースコードの可読性がよろしくありません。まだコンピューター資源が乏しかったころに書かれたコードなのである意味仕方がないともいえます。

内部的な基本となるコードはISO-2022-JPです。制御コードを抜いたMSBが0のデータ(0x00~0x7f)をc1, c2に保持します。出力時にコードの加工をします(kanjiio.c putkanji参照)。

文字変換処理

文字種の相互変換処理は、大域変数proc[]に関数へのポインタとして呼び出すべき関数を保持させ、それらを呼び出すようになっています。

static int (*proc[8])()={NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
/* ASCII, JISROMAN, KATAKANA, GRAPHIC, ZENKAKU-KIGOU, ZENKAKU-KATAKANA, ZENKAKU-HIRAGANA, KANJI, */

個々の処理は*2.cというファイル名のソースに保持されています。たとえば全角カタカナからの変換であればkk2.cが対応するソースになります。

ローマ字変換一般的にローマ字にはヘボン式と訓令式の2種類があるとされています。実際にはもう少し複雑なのですが、オリジナルのKAKASIはそれらをサポートしているといいつつ、一般的な表記とも微妙に異なる体系を持っていました。このあたりは最近のコミットでもう少ししっかりと明文化されたmodified hepburnと呼ばれる体系と、ISO3602、BS4812に対応させています。

ローマ字のテーブルはソースコード埋め込みで、メンテナンス性がよくありません。しかもカタカナ、ひらがなそれぞれにテーブルを持っています(kk2.c, hh2.c)。メンテナンスの手間を低減するため、2進数で書かれたソースをEUC-JPに変換するdumptable.pl, その逆を行うocttable.pl, テーブルの文字列をコード順に並び替えるromantablesort.plの3つのスクリプトを書きました。これで多少メンテナンス性が向上しました。

これだけ書いておけば次の作業の時には思い出すのにそれほど苦労しないだろうと思います。他に記録を残しておかないといけないことを思い出したら、またblogに書いておこうと思います。