公開鍵の秘密 -追補- 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 の情報を格納していると確信できる部分までだ取り付けていない。今後の宿題かなぁ...
暗号関連、嫌いです。
最近のコメント