公開鍵の秘密 -追補- 3 ― 2007/02/09 15:32
次に ssh-keygen が実際に秘密鍵を作成する部分のコードを見てみる。
ssh-keygen.c をたどっていくと、
1338 private = key_generate(type, bits);
1339 if (private == NULL) {
1340 fprintf(stderr, "key_generate failed");
1341 exit(1);
1342 }
となっている。private は Key 型へのポインタである。key_generate() は key.c で定義されている。
594 Key *
595 key_generate(int type, u_int bits)
596 {
597 Key *k = key_new(KEY_UNSPEC);
598 switch (type) {
599 case KEY_DSA:
600 k->dsa = dsa_generate_private_key(bits);
601 break;
602 case KEY_RSA:
603 case KEY_RSA1:
604 k->rsa = rsa_generate_private_key(bits);
605 break;
606 default:
607 fatal("key_generate: unknown type %d", type);
608 }
609 k->type = type;
610 return k;
611 }
key_generate() はとても短い。key->type が KEY_RSA のときには、rsa_generate_private_key() を呼び出す。この関数は key.c で定義されている。
569 static RSA *
570 rsa_generate_private_key(u_int bits)
571 {
572 RSA *private;
573
574 private = RSA_generate_key(bits, 35, NULL, NULL);
575 if (private == NULL)
576 fatal("rsa_generate_private_key: key generation failed.");
577 return private;
578 }
鍵が RSA 形式の時には、rsa_generate_private_key() の中で RSA_generate_key() を呼んでいる。紛らわしいが、大文字で始まるほうの RSA_generate_key() は、openssl のソースに含まれているので、これ以上 OpenSSH のソースコードを漁っても何も得られない。
openssl-0.9.8d を展開したあと、crypto ディレクトリに移動するとそこに rsa_depr.c というソースコードがある。RSA_generate_key() はそこに定義されている。
71 RSA *RSA_generate_key(int bits, unsigned long e_value,
72 void (*callback)(int,int,void *), void *cb_arg)
73 {
...中略
92 if(RSA_generate_key_ex(rsa, bits, e, &cb)) {
93 BN_free(e);
94 return rsa;
95 }
とまぁ、RSA_generate_key() のなかでは今度は RSA_generate_key_ex() を呼び出している。_ex つきの関数は rsa_gen.c の定義されている。これで何度目のリダイレクトだ?
rsa_gen.c では、
78 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb)
79 {
80 if(rsa->meth->rsa_keygen)
81 return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
82 return rsa_builtin_keygen(rsa, bits, e_value, cb);
83 }
RSA_generate_key_ex() の関数は、これがすべてである。
本当の鍵の生成は rsa_builtin_keygen() を呼び出しておこなっており、rsa_builtin_keygen() は RSA_generate_key() の直後から定義されている。この関数は長いので割愛。
さて、話を元に戻すと、key_generate() の結果を private (Key 型へのポインタ)に保存すると、その先の処理は大きく分けて二つある。一つは private から公開鍵を生成すること、そしてもうひとつは private を秘密鍵として保存することである。
もう一度 key_generate() の部分を ssh-keygen.c から抜き出すと下記のとおりで、これは今回の冒頭に挙げているものと同じだ。
1338 private = key_generate(type, bits);
1339 if (private == NULL) {
1340 fprintf(stderr, "key_generate failed");
1341 exit(1);
1342 }
private = key_generate(type, bits); の処理で、private には RSA の鍵情報が入っている。この直後に、
1343 public = key_from_private(private);
として、private の内容から公開鍵の情報を取り出して、やはり Key 型へのポインタである public へ代入している。
そして、最終的に、
1405 if (!key_save_private(private, identity_file, passphrase1, comment)) {
1406 printf("Saving the key failed: %s.\n", identity_file);
1407 memset(passphrase1, 0, strlen(passphrase1));
1408 xfree(passphrase1);
1409 exit(1);
1410 }
と、key_save_private() で identity_file に設定されているファイルへ書き出すのである。
最後に見るのは、key_save_private() だ。この関数は OpenSSH の authfile.c で定義されている。
204 switch (key->type) {
205 case KEY_DSA:
206 success = PEM_write_DSAPrivateKey(fp, key->dsa,
207 cipher, passphrase, len, NULL, NULL);
208 break;
209 case KEY_RSA:
210 success = PEM_write_RSAPrivateKey(fp, key->rsa,
211 cipher, passphrase, len, NULL, NULL);
212 break;
213 }
と、key->type が KEY_RSA なら PEM_write_RSAPrivateKey() を呼び出す。この PEM_write_RSAPrivateKey() はマクロで、openssl-0.9.8d/crypto/pem/pem.h に次のように定義されている。
409 #define PEM_write_RSAPrivateKey(fp,x,enc,kstr,klen,cb,u) \
410 PEM_ASN1_write((int (*)())i2d_RSAPrivateKey,PEM_STRING_RSA,fp,\
411 (char *)x,enc,kstr,klen,cb,u)
つまり、PEM_ASN1_write である、と。
openssl-0.8.9d/crypto/pem/pem_lib.c に実際の PEM_ASN1_write() が定義されている。
結果から言うと、PEM_ASN1_write() からは更に PEM_ASN1_write_bio() を呼び出しており、正真正銘、これが最終最後の場所なのだが、はっきりいって、中身をみても良くわからん... 結局、ssh-keygen で id_rsa を生成するときに、p、q、d、n、e の情報を格納していると確信できる部分までだ取り付けていない。今後の宿題かなぁ...
暗号関連、嫌いです。
最近のコメント