ゲスト[ログイン]

おおいしゆうのASミュージックスコア登録CGI

おおいしゆうが日々のフォルテール演奏の記録を書き続けるCGI(日記じゃないです。blogでもないです)

工画堂スタジオ 『スマイル☆シューター ~ふぁーすと☆ちけっと~』OHP

パルフェ10周年ポータル パルフェ10周年寄せ書き企画

Aozora Melodyのパーフェクト動画公開中!

日 (今日 最終日)
日 ~ 日 (全部)
フォルテール総合情報サイト
ASミュージック
ポータル

同曲演奏状況
CSV登録
工画堂スタジオ&ヤマサ 『スマイル☆シューター ~ふぁーすと☆ちけっと~』応援中!
工画堂スタジオ 『ソルフェージュ~La finale~』OHP
曲名スコア記録曲名スコア記録
天使の歌う小夜曲66474(96.25%)普通69063羽根のブランケットにつつまれて62573(98.11%)普通63776
メロディー126479(94.78%)普通132237obedience113849(83.19%)妥協126145
ハレルヤ彗星群98674(89.86%)妥協106612
今日も遅かったです。

フォルテールはコースがメロディー→まり様→ハレルヤという激重コースで、やっぱりダメでした。まり様もハレルヤも全然伸びずに妥協です。
名前: ひとこと:
この記事へのトラックバックURL: https://www.asmusic.jp/ASHARD/score/tb.cgi/yu-oishi/20080710手動トラックバック
ここのところSSLを使った暗号化通信の方法を勉強しているのですが、とりあえず出来るようになったのでまとめておきます。
基本的に普段のソケットプログラミングに1枚皮を被せるだけで素直な作りになっているようですが、ドキュメントが一部の関数の分しか存在しないのが困りものですが。

サーバもクライアントもいつものヘッダに加えて
#include  
#include  
を指定しておき、リンク時には-lsslオプションを付けます。パスは各自の環境に合わせて下さい。

クライアント編



SSL_CTX *ctx; //SSL全体の設定や作業領域のようです(プログラム全体で1つ)
SSL *ssl;  //実際のSSL通信に対応する構造体のようです(接続毎に1つ)
int sock;  //いつものソケットディスクリプタ

//SSL初期化 error_stringsはエラーメッセージ出力用のようですが使ってないのでよく分かりません
// SSL_load_error_strings()したときは終了前にERR_free_strings()で開放
SSL_load_error_strings();
SSL_library_init();

// SSL_CTX作成
// 今回はTLSv1を使ったのでTLSv1_client_method()を引数に。その他
// SSLv2 SSLv2_client_method()
// SSLv3 SSLv3_client_method()
// が指定できるようです
// SSL_CTXを作ったら終了前にSSL_CTX_free(ctx)で開放
if(!(ctx=SSL_CTX_new(TLSv1_client_method())))
{
  fprintf(stderr,"SSL init error.\n");
  ERR_free_strings();
  return -1;
};

// ルート証明書読み込み
// 今回は似非証明書CRTFILEを読み込む(自分で作ったサーバとクライアント同士の接続なので)だけですが、httpsクライアントとか作る時は必要なルート証明書を同じディレクトリに集めておき、SSL_CTX_load_verify_locationsの第3引数にディレクトリを指定するとそれを全部読み込みます
if(!SSL_CTX_load_verify_locations(ctx,CRTFILE,NULL))
{
  fprintf(stderr,"Can't load CA file.\n");
  SSL_CTX_free(ctx);
  ERR_free_strings();
  return -1;
};


//とりあえず普段通りソケット作って繋ぎます

struct addrinfo hints,*ai,*ai_start;
memset(&hints,0,sizeof(hints));
hints.ai_family=PF_UNSPEC;   //IPv4のみのときはPF_INET, v6のみのときはPF_INET6
hints.ai_socktype=SOCK_STREAM;
char addr_string[128];
char port_string[64];
  
strncpy(addr_string,ADDRESS,128);  
snprintf(port_string,64,"%d",PORT);

if(getaddrinfo(addr_string,port_string,&hints,&ai_start))
{
  fprintf(stderr,"Host lookup error\n");
  SSL_CTX_free(ctx);
  ERR_free_strings();
  return -1;
};

sock=-1;
for(ai=ai_start;ai!=NULL;ai=ai->ai_next)
{
  sock=socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  if(sock<0){continue;};
    
  if(connect(sock,ai->ai_addr,(int)ai->ai_addrlen)<0)
  {
    close(sock);
    sock=-1;
    continue;
  };

// connectまで成功したらSSL_nex(ctx)でSSL構造体を作成し(開放はSSL_free(ssl))、
// SSL_set_fd(ssl,sock)でソケットディスクリプタをSSL構造体にセットし、
// SSL_connect(ssl)でSSL通信を開始します
  ssl=SSL_new(ctx);
  SSL_set_fd(ssl,sock);
  if(SSL_connect(ssl)<0)
  {
    SSL_free(ssl);
    ssl=NULL;
    close(sock);
    sock=-1;
    continue;
  };
  break;
};
if(sock<0)
{
  fprintf(stderr,"Can't connect server\n");
  SSL_CTX_free(ctx);
  ERR_free_strings();
  return -1;
};
freeaddrinfo(ai_start);

あとはread(sock,buf,buflen), write(sock,buf,buflen)のかわりに
SSL_read(ssl,buf,buflen), SSL_write(ssl,buf,buflen)を使えばOKです。
selectする際などSSL構造体からソケットディスクリプタを得る必要があるときは
SSL_get_fd(ssl)で取得できます。

// 後始末
// closeする前にSSL_shutdownでSSL通信を終了します。
// 強制切断された時などはSSL_shutdownしようとするとSIGPIPEで落ちるのでトラップしておきましょう(^^;;)
SSL_shutdown(ssl);
SSL_free(ssl);
close(sock);
SSL_CTX_free(ctx);
ERR_free_strings();
return 0;



名前: ひとこと:
この記事へのトラックバックURL: https://www.asmusic.jp/ASHARD/score/tb.cgi/yu-oishi/20080710_1手動トラックバック
暗号化だけする時は前のモノでOKですが、証明書の正当性を検証する時はSSL_connectした後に次のようにします。

int ret;
int verify_success=TRUE;
X509 *cert=SSL_get_peer_certificate(ssl);

// SSL_get_verify_resultで証明書を検証
// 返り値(エラーメッセージ)の意味はopenssl/err.hを見てください(爆)
if((ret=SSL_get_verify_result(ssl))!=X509_V_OK)
{
  fprintf(stderr,"Certification failed. (%d)\n",ret);
  verify_success=FALSE;  
};

// Common Name検証
// SubjectのCommonNameフィールドしか見てません。X509拡張による指定もあるようですけどよく分からないのでとりあえずパス
char buffer[256];
X509_NAME *xname=X509_get_subject_name(cert);
if(X509_NAME_get_text_by_NID(xname,NID_commonName,buffer,sizeof(buffer))==-1 || strcmp(buffer,ADDRESS))
{
  fprintf(stderr,"Can't find valid CommonName.\n");
  verify_success=FALSE;
};

if(!verify_success)
{
  X509_free(cert);
  SSL_shutdown(ssl);
  SSL_free(ssl);
  close(sock);
  SSL_CTX_free(ctx);
  ERR_free_strings();
  return -1;
};
X509_free(cert);



ちなみに証明書の内容を表示する時は次のようにすればOK
SSL* sslとX509 *cert=SSL_get_peer_certificate(ssl)を使って

printf("Encryption Method: %s\n",SSL_get_cipher(ssl));
printf("Encryption Protocol: %s\n",SSL_get_cipher_version(ssl));

// BIOというのはよく分からないけどI/Oのカプセル化でX509_get_...の返り値を表示するためのものらしい??
BIO *bio=BIO_new_fp(stdout,BIO_NOCLOSE);
BIO_printf(bio,"Cert Information:\n");
X509_NAME_print_ex(bio,X509_get_subject_name(cert),0,XN_FLAG_RFC2253);
BIO_printf(bio,"\n");
X509_NAME_print_ex(bio,X509_get_issuer_name(cert),0,XN_FLAG_RFC2253);
BIO_printf(bio,"\n");
BIO_printf(bio,"from: ");
ASN1_TIME_print(bio,X509_get_notBefore(cert));
BIO_printf(bio,"\nto: ");
ASN1_TIME_print(bio,X509_get_notAfter(cert));
BIO_printf(bio,"\n");
BIO_free(bio);
名前: ひとこと:
この記事へのトラックバックURL: https://www.asmusic.jp/ASHARD/score/tb.cgi/yu-oishi/20080710_2手動トラックバック

サーバ編



サーバも基本的には同じで、acceptしたあとSSL構造体を作ってSSL_set_fdしてSSL_acceptしてあげればOKです。


// SSL_CTXを作るところまではクライアントと同じ
// TLSv1_client_method()等のかわりにTLSv1_server_method()などを用いる

SSL_load_error_strings();
SSL_library_init();

if(!(ctx=SSL_CTX_new(TLSv1_server_method())))
{
  fprintf(stderr,"SSL init error.\n");
  ERR_free_strings();
  return -1;
};

// 秘密鍵KEYFILEを読み込み
// SSL_FILETYPE_PEMは通常のBase64でテキスト化された鍵ファイルの場合
SSL_CTX_use_PrivateKey_file(ctx,KEYFILE,SSL_FILETYPE_PEM);
// 証明書CRTFILEを読み込み
SSL_CTX_use_certificate_file(ctx,CRTFILE,SSL_FILETYPE_PEM);

// ソケット生成
int sock,sock_accept;
struct addrinfo hints,*ai,*ai_start;
memset(&hints,0,sizeof(hints));
hints.ai_family=protocol;
hints.ai_socktype=SOCK_STREAM;
hints.ai_flags=AI_PASSIVE;

if(getaddrinfo(NULL,temp,&hints,&ai_start))
{
  fprintf(stderr,"getaddrinfo error\n");
  SSL_CTX_free(ctx);
  ERR_free_strings();
  return -1;
};
sock=-1;
for(ai=ai_start;ai!=NULL;ai=ai->ai_next)
{
  sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);
  if(sock<0){continue;};

  if(bind(sock,ai->ai_addr,(int)ai->ai_addrlen)<0)
  {
    close(sock);
    sock=-1;
    continue;
  };
  
  if(listen(sock,5)<0)
  {
    close(sock);
    sock=-1;
    continue;
  };
};
freeaddrinfo(ai_start);
if(sock<0)
{
  fprintf(stderr,"Can't create socket\n");
  SSL_CTX_free(ctx);
  ERR_free_strings();
  return -1;
};

// acceptしたらforkしてSSL_accept
sock_accept=-1;
struct sockaddr  fromadd;
int fromlen=sizeof(fromadd);
while(1)
{
  sock_accept=accept(sock,(struct sockaddr*)&fromadd,&fromlen);
  if(sock_accept==-1){continue;};
  if(0==fork())
  {
// child process
    if(!(ssl=SSL_new(ctx)) || !SSL_set_fd(ssl,sock_accept))
    {
      fprintf(stderr,"Can't crate SSL object.\n");
      if(ssl){SSL_free(ssl);};
      SSL_CTX_free(ctx);
      ERR_free_strings();
      return -1;
    };
    if(SSL_accept(ssl)>=0)
    {
// サーバとしての処理を行う
      SSL_shutdown(ssl);
    };
    SSL_free(ssl);
    close(sock_accept);
    fprintf(stderr,"closed\n");
    SSL_CTX_free(ctx);
    ERR_free_strings();
    return 0;
  }else{
// parent process
    close(sock_accept);
  };
};

名前: ひとこと:
この記事へのトラックバックURL: https://www.asmusic.jp/ASHARD/score/tb.cgi/yu-oishi/20080710_3手動トラックバック