SSL_new

SSL_newで、SSL接続情報を作成することもできる。
BIOを使わないでSSL接続をする場合はこれを使う。

/docs/man1.0.2/ssl/SSL_new.html

SSL_new.cで、

SSL_newにctxを渡すことで、sslを作成。
sslの指すアドレスを出力。
SSL_newで作成した場合は、SSL_freeでsslを解放する必要がある。

$ vi SSL_new.c
$ gcc -o SSL_new SSL_new.c -lssl -lcrypto
$ ./SSL_new 
ctx = 01072820
ssl = 01073860
$

sslを作成できた。

Sample/openssl/SSL_new/SSL_new/src/SSL_new at master · bg1bgst333/Sample · GitHub

SSL_load_error_strings

SSL_load_error_stringsもエラー文字列を読み込む関数だが、ERR_load_BIO_stringsとはちょっと違う模様。

/docs/man1.0.2/crypto/SSL_load_error_strings.html

SSL_load_error_strings.cで、

ERR_load_BIO_stringsに加えて、SSL_load_error_stringsも呼ぶ。

$ vi SSL_load_error_strings.c
$ gcc -o SSL_load_error_strings SSL_load_error_strings.c -lssl -lcrypto
$ ./SSL_load_error_strings ctx = 00972ad0
SSL_CTX_load_verify_locations error!
139907107936152:error:02001002:system library:fopen:No such file or directory:bss_file.c:175:fopen('dummyurl','r')
139907107936152:error:2006D080:BIO routines:BIO_new_file:no such file:bss_file.c:182:
139907107936152:error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib:by_file.c:258:
$

func(132)がX509_load_cert_crl_fileなのがわかった。

Sample/openssl/SSL_load_error_strings/SSL_load_error_strings/src/SSL_load_error_strings at master · bg1bgst333/Sample · GitHub

ERR_load_BIO_strings

ERR_load_BIO_stringsで、エラー文字列をロードすることで、意味の分からないエラーコードをある程度エラー文字列に変換して出力させる。

OpenSSL API によるセキュア・プログラミング: 第 1 回 API の概要

ERR_load_BIO_strings.cで、

最初にERR_load_BIO_stringsでエラー文字列をロードさせておく。

$ vi ERR_load_BIO_strings.c
$ gcc -o ERR_load_BIO_strings ERR_load_BIO_strings.c -lssl -lcrypto
$ ./ERR_load_BIO_strings 
ctx = 014f96e0
SSL_CTX_load_verify_locations error!
140602612119448:error:02001002:system library:fopen:No such file or directory:bss_file.c:175:fopen('dummyurl','r')
140602612119448:error:2006D080:BIO routines:BIO_new_file:no such file:bss_file.c:182:
140602612119448:error:0B084002:x509 certificate routines:func(132):system lib:by_file.c:258:
$

lib(2)がsystem libraryで、func(1)がfopenで、reason(2)がNo such file or directoryという感じである程度は内容がわかった。

Sample/openssl/ERR_load_BIO_strings/ERR_load_BIO_strings/src/ERR_load_BIO_strings at master · bg1bgst333/Sample · GitHub

ERR_print_errors_fp

ERR_print_errors_fpにファイルポインタを指定すると、そのストリームにOpenSSLのエラーメッセージを書き込む。

/docs/man1.1.0/crypto/ERR_print_errors_fp.html

ERR_print_errors_fp.cで、

SSL_CTX_load_verify_locationsで"dummyurl"という存在しないパスを指定し、わざとエラーを起こす。
ERR_print_errors_fpにstderrを指定し、エラーメッセージを標準エラー出力に出力するようにする。

$ vi ERR_print_errors_fp.c 
$ gcc -o ERR_print_errors_fp ERR_print_errors_fp.c -lssl -lcrypto
$ ./ERR_print_errors_fp 
ctx = 01cdf820
SSL_CTX_load_verify_locations error!
140164446353304:error:02001002:lib(2):func(1):reason(2):bss_file.c:175:fopen('dummyurl','r')
140164446353304:error:2006D080:lib(32):func(109):reason(128):bss_file.c:182:
140164446353304:error:0B084002:lib(11):func(132):reason(2):by_file.c:258:
$

とはいえ、これだけだと、さっぱりわからない。

Sample/openssl/ERR_print_errors_fp/ERR_print_errors_fp/src/ERR_print_errors_fp at master · bg1bgst333/Sample · GitHub

SSL_get_verify_result

SSL_get_verify_resultで、接続先のSSL証明書の検証結果を取得する。
これで問題ないならば、リクエストの書き込みをするという流れとなる。

/docs/man1.0.2/ssl/SSL_get_verify_result.html

SSL_get_verify_result.cで、

BIO_do_connectで接続後、SSL_get_verify_resultにsslを渡す。
ssl_resultがX509_V_OKなら、問題ないのでGETリクエストを書き込み、そしてレスポンスを読み込む。
今回はちゃんとした証明書がある"www.google.co.jp"に接続した。
"bgstation0.com"のオレオレ証明書だとエラーが出たので。

$ vi SSL_get_verify_result.c 
$ gcc -o SSL_get_verify_result SSL_get_verify_result.c -lssl -lcrypto
$ ./SSL_get_verify_result 
ctx = 01d75820
SSL_CTX_load_verify_locations success!
BIO_new_ssl_connect success! bio = 01d78090
ssl = 01d78150
ssl_mode = 00000000
ssl_mode = 00000004
SSL_MODE_AUTO_RETRY
SSL_get_verify_result! ssl_result = 0
BIO_do_connect success! bio = 01d78090
HTTP/1.1 200 OK
Date: Wed, 17 May 2017 07:45:56 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=Shift_JIS
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=103=Yl-M1w_g4Ry_vJy8e1mtK4YuiHfH7dhrstOZdtfuGPFcPkKYXOW3C8wEkrQzbILrBsMKKecRjaHTtPyjoK2JI4DB5-NIIgH1wjRelP6f8699sTfQ9IKdyYmn2rEwEfnV; expires=Thu, 16-Nov-2017 07:45:56 GMT; path=/; domain=.google.co.jp; HttpOnly
Alt-Svc: quic=":443"; ma=2592000; v="37,36,35"
Accept-Ranges: none
Vary: Accept-Encoding
Connection: close

<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="

(長いので省略)

google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}
</script></div></body></html>$ 
$

200 OKが出ている。問題なく読み込めた模様。

Sample/openssl/SSL_get_verify_result/SSL_get_verify_result/src/SSL_get_verify_result at master · bg1bgst333/Sample · GitHub

BIO_set_conn_hostname

非セキュアな場合は、BIO_new_connectで接続先ホスト名とポートを指定していたが、セキュアな場合に、BIO_new_ssl_connectにはSSL_CTX型ポインタしか渡せないため、BIO_set_conn_hostnameを使う。

bio_set_conn_hostname(3): connect BIO - Linux man page

BIO_set_conn_hostname.cで、

BIO_set_conn_hostnameで、bioに"bgstation0.com:443"をセットする。
これでBIO_do_connectに成功すれば、接続できていることを確認できる。

$ vi BIO_set_conn_hostname.c 
$ gcc -o BIO_set_conn_hostname BIO_set_conn_hostname.c -lssl -lcrypto
$ ./BIO_set_conn_hostname ctx = 012ae820
SSL_CTX_load_verify_locations success!
BIO_new_ssl_connect success! bio = 012b1090
ssl = 012b1150
ssl_mode = 00000000
ssl_mode = 00000004
SSL_MODE_AUTO_RETRY
BIO_do_connect success! bio = 012b1090
$

接続できた。

Sample/openssl/BIO_set_conn_hostname/BIO_set_conn_hostname/src/BIO_set_conn_hostname at master · bg1bgst333/Sample · GitHub

SSL_set_mode

SSL_set_modeでSSLモードを設定する。

/docs/man1.1.0/ssl/SSL_get_mode.html

SSL_set_mode.cで、

SSL_get_modeでなにもセットされていないことを確認してから、SSL_set_modeでSSL_MODE_AUTO_RETRYをセットする。
SSL_get_modeを再び呼んで、ssl_modeにSSL_MODE_AUTO_RETRYがセットされていたら、"SSL_MODE_AUTO_RETRY"を出力。

$ vi SSL_set_mode.c 
$ gcc -o SSL_set_mode SSL_set_mode.c -lssl -lcrypto
$ ./SSL_set_mode 
ctx = 014d7820
SSL_CTX_load_verify_locations success!
BIO_new_ssl_connect success! bio = 014da090
ssl = 014da150
ssl_mode = 00000000
ssl_mode = 00000004
SSL_MODE_AUTO_RETRY
$

SSL_MODE_AUTO_RETRYがセットされていることがわかる。

Sample/openssl/SSL_set_mode/SSL_set_mode/src/SSL_set_mode at master · bg1bgst333/Sample · GitHub