openssl

Too hot so ..

梅雨入り前の数日、糞みたいに暑かった。これはかなわんと、Debian機を持って涼しい所に避難。そこでWebサーフィンするも、日本語の設定をしてなかったものだから、やるはめに。

Debian系の日本語入力をFcitx & Mozcにする

ググル様のなすがままに、流行り系を入れてみた。エンジンがMozcで、インプットメソッドがFcitxって事になるのかな。

英語、日本語の切り替えは、元から定義されてた、Ctl-SPC に加えて、Win-SPCも登録しておいた。

調子に乗って、emacsも設定する。

Emacsで快適な日本語入力

を取り入れてみた。切り替えは、Ctl-\ になってた。本来なら、init.elをごにょごにょしてみたいんだけど、面倒なのデフォなまま。まあ、余り入力する事もないから、そのままでいいか。

QRコード

近頃、やけにQRコードが眼につく。毎日見せられるNHKの、コロナ特設サイトとか、某パンの梱包袋に掲載されてる、懸賞応募とか、etc,etc …

また、某国では、公共機関に入場する時、スマホをかざして、連絡方法をQRコードにより登録するとか。そういう時代なんですかねぇ。日本もまねして、図書館に行く時はスマホを持参してくださいってならないかねぇ。ああ、図書カードがデフォだから、大丈夫か。

まて、飛行機の搭乗券は、便利さのため、スマホでQRコードだけで運用します、とかなったら、原始人はどうしたらいいの?

時代に乗り遅れないように、少し調査。スマホは無いけど、3Gのガラケー携帯はかろうじて持ってるぞ。これでQRコードのオペレーションって出来るの?

カメラのメニューに、バーコードとQRコードの読み取りがあった。ああ良かった。試してみるか。

役場から以前に貰ってきておいた、マイナンバーカードのお勧めパンフレットにQRコードが付いてた。読んでみると、URLに変換されて、いざ飛ぼうとすると、認証に失敗しましただと。

ガラケーには理解出来ない、認証方式が使われているのかな?

マイナンバーカード総合サイト

コロナが落ち着いたら、役場で申請してこよう。総務のおばちゃんが、口座登録を義務化するなんて、ほざいているよ。それがプチ気になるけど。

openssl(本家)

で、ふと、前からやってる鍵の元締めのopensslに触ってみたくなった。debian機では

debian:~$ openssl version
OpenSSL 1.0.2l  25 May 2017

なんか、ちょっと古いみたい。新しいのを取り寄せて、入れてみた。コンパイルに5分。インストールはマニュアルが膨大だったので、随分と時間がかかった。

debian:~$ /usr/local/openssl/1_1_1g/bin/openssl version
OpenSSL 1.1.1g  21 Apr 2020 (Library: OpenSSL 1.1.1d  10 Sep 2019)

1.1系では一番新しいっぽい。次は1.3系とか。OpenBSDの人達と連携するのかな?

openssl(分家)

山のようにコマンドが用意されてて、容易に踏み込めないので、ガイドを探してみた。 opensslコマンドの使い方

s_client

httpsなサーバーに接続して、鍵の扱いを調べてくれるとな。マイナンバーカードの情報を探ってみるか。

ob$ openssl s_client -connect www.kojinbango-card.go.jp:443                     CONNECTED(00000003)                                                             depth=2 C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA     verify return:1                                                                 depth=1 C = BE, O = GlobalSign nv-sa, CN = GlobalSign CloudSSL CA - SHA256 - G3 verify return:1                                                                 depth=0 C = US, ST = Delaware, L = Dover, O = Incapsula Inc, CN = incapsula.com verify return:1                                                                 write W BLOCK                                                                   ---                                                                             Certificate chain                                                                0 s:/C=US/ST=Delaware/L=Dover/O=Incapsula Inc/CN=incapsula.com                    i:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign CloudSSL CA - SHA256 - G3            1 s:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign CloudSSL CA - SHA256 - G3              i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA                  ---
 :                                                                     
SSL handshake has read 3193 bytes and written 343 bytes
---
New, TLSv1/SSLv3, Cipher is AEAD-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : AEAD-AES128-GCM-SHA256
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1591850037
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)

メッセージのやり取りは、下記のようにしてモニターするとな。

ob$ openssl s_client -connect www.kojinbango-card.go.jp:443 -msg |grep -e ">>>" -e "<<<"
>>> TLS 1.3 Handshake [length 0118], ClientHello
<<< TLS 1.3 Handshake [length 007a], ServerHello
<<< TLS 1.3 Handshake [length 0006], EncryptedExtensions
<<< TLS 1.3 Handshake [length 0a6a], Certificate
depth=2 C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
verify return:1
depth=1 C = BE, O = GlobalSign nv-sa, CN = GlobalSign CloudSSL CA - SHA256 - G3
verify return:1
depth=0 C = US, ST = Delaware, L = Dover, O = Incapsula Inc, CN = incapsula.com
verify return:1
<<< TLS 1.3 Handshake [length 0108], CertificateVerify
<<< TLS 1.3 Handshake [length 0024], Finished
>>> TLS 1.3 Handshake [length 0024], Finished

いきなり TLS 1.3 が出て来るじゃ、10年以上前のガラケーが太刀打ち出来る訳はない。携帯屋のおねーちゃんが言ってたように、早く機種変更しろよ。

ciphers

これが、多分、共通鍵暗号の種類

ob$ openssl list-cipher-commands| cut -f1 -d'-' | sort | uniq
aes
base64
bf
camellia
cast
cast5
chacha
des
des3
desx
idea
rc2
rc4
sm4

それらを、公開鍵暗号、署名と組み合わせると、実際にWebで使えるものになるって事かな。

ob$ openssl ciphers -v
AEAD-AES256-GCM-SHA384  TLSv1.3 Kx=TLSv1.3  Au=TLSv1.3 Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
AES256-GCM-SHA384       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(256) Mac=AEAD

-V を付けるともっと詳しく表示され

-V      Verbose.  List ciphers with cipher suite code in hex format,
        cipher name, and a complete description of protocol version, key
        exchange, authentication, encryption, and mac algorithms.

と言う事らしい。

public-key-algorithms

公開鍵にも色々有りまして、、、

ob$ openssl list-public-key-algorithms
Name: OpenSSL RSA method
        Type: Builtin Algorithm
        OID: rsaEncryption
        PEM string: RSA
Name: rsa
        Type: Alias to rsaEncryption
Name: OpenSSL EC algorithm
        Type: Builtin Algorithm
        OID: id-ecPublicKey
        PEM string: EC

ここで出ているPEMってのは、バイナリー値をBase64エンコードした(一応)文字列になったやつ。これに対してDERは、バイナリー値で表現されるファイル形式。 こういうのが、いきなり出て来るので、面喰らうぞ。

ssl(3)

に、Web用の秘密鍵とサーバー証明書の作り方が解説されてた。OpenBSDは、ここまで親切なドキュメントが用意されてるんですねぇ。いち早くこれを見つけられなかったオイラーはアホだな。

RSAの特許まみれの話とか、それをかいくぐる為にECDSAを用意したとか、歴史の話が出て来て興味深い。

SSL/TLS session

SSL/TLSのプロトコル構造

SSL/TLSセッション確立手順

まあ、大変な手間をかけて、安全対策をやってるのね、ぐらいが分かれば宜しいかなと。

毎度お馴染みのウィキペディアに、Transport Layer Security が解説されてて、よく網羅されてた(上から目線って、どうよ)。RSAによる鍵交換は、サツに踏み込まれて秘密鍵を押収されるとヤバいんで、余りお勧めしない。 ディフィー・ヘルマン鍵共有 が、例のスノーデン事件後に、注目されるようになった。スパイな世界の話である。

lib{ssl,tls}

折角なので、OpenBSDでopensslのコードを鑑賞してみる。

ob$ cd /usr/src/usr.bin/openssl/
ob$ ls
Makefile        dh.c            nseq.c          progs.h         smime.c
apps.c          dhparam.c       ocsp.c          rand.c          speed.c
apps.h          dsa.c           openssl.1       req.c           spkac.c
apps_posix.c    dsaparam.c      openssl.c       rsa.c           testdsa.h
asn1pars.c      ec.c            passwd.c        rsautl.c        testrsa.h
ca.c            ecparam.c       pkcs12.c        s_apps.h        timeouts.h
certhash.c      enc.c           pkcs7.c         s_cb.c          ts.c
ciphers.c       errstr.c        pkcs8.c         s_client.c      verify.c
cms.c           gendh.c         pkey.c          s_server.c      version.c
crl.c           gendsa.c        pkeyparam.c     s_socket.c      x509.c
crl2p7.c        genpkey.c       pkeyutl.c       s_time.c
dgst.c          genrsa.c        prime.c         sess_id.c

これって、openssl xxx の、xxx相当なのね。いわゆるサブコマンドって奴だ。本家の方では、appsって表現してたけどね。

ソースを紐解いてみると、冒頭にこれでもかと言う程、クレジットが表示されている。大変な世界なんですなあ。

で、例によってgdbにかけられるようにコンパイルしてってやってもいいんだけど、毎回代わり映えしないとクレームになりそうなので、切口をちょいと変えてみる。

これらのアプリが共通に使っているライブラリィーに、眼をつけた(目の付け所が違うのだ)。 /usr/src/lib/の下をざっと見すると、当たり前のように、libcryptoが有る。中身は各種暗号とかハッシュアルゴリズムのソース類の詰め合わせセット。

これには、うんざりしたんで、他の部分に眼を凝らすと、libsslが有る。大分ソースが詰め合わせてある。ssl2とかに混じってtls13とかも置いてあった。そうか、通信規約を表現してるんだな。doc/standards.txt に、参照したRFCが山のように列挙されてた。日々進化中。

libssl/に並置して、興味深いlibtls/も有った。 tls_server.c とか tls_client.c なんてのが置いてあるって事は、tlsなサーバーを作る為の材料なんだな。

どんな所で、このlibtlsが使われているのかな? 直ぐに思い付くのは、あれだ。

ob$ ldd /usr/sbin/httpd | awk '{print $7}'

Name
/usr/sbin/httpd
/usr/lib/libevent.so.4.1
/usr/lib/libtls.so.20.1
/usr/lib/libssl.so.48.1
/usr/lib/libcrypto.so.46.1
/usr/lib/libutil.so.15.0
/usr/lib/libc.so.96.0
/usr/libexec/ld.so

前回やったOpenBSDに備え付けのWebサーバーの成分表をlddで取り出して、ぐたぐた並べられているフィールドから、ライブラリィー名だけを、拾い出してみた。暗号とsslとtlsが合有されてて、思った通りだ。

早速ご対面するか。まて、httpdって見るには巨大過ぎないか。openssl(1)のSEE ALSOにnc(1)が列挙されたぞ。 成分表を調べてみたら、httpdと同じように使われていた。

How to use nc

ネットワーク界のアイドルじゃなくて、アーミーナイフと称されるアプリである。まずは、Webクライアント(要するブラウザーね)の真似。

ob$ printf "GET / HTTP/1.0\r\n\r\n" | nc localhost 80
HTTP/1.0 200 OK
Connection: close
  :

これぐらいなら、他のやつでも、簡単に出来るぞ。

Open a TCP connection to port 443 of www.example.com, and negotiate TLS
 with any supported TLS protocol version and "compat" ciphers:

       $ nc -cv -T protocols=all -T ciphers=compat www.example.com 443

こんな例が載ってた。

ob$ printf "GET / HTTP/1.0\r\n\r\n" |
> nc  -cv -T protocols=all -T ciphers=compat localhost 443
Connection to localhost (127.0.0.1) 443 port [tcp/https] succeeded!
nc: tls handshake failed (certificate verification failed: self signed certificate)

オレオレ証明書は駄目よと、nc がブレーキをかけてくれたぞ。そんじゃ、オイラーがご厄介になってるSAKURAさんの所へ繋いでみるか。

ob$ printf "GET / HTTP/1.0\r\n\r\n" |
> nc  -cv -T protocols=all -T ciphers=compat hamesspam.sakura.ne.jp 443
Connection to hamesspam.sakura.ne.jp (219.94.129.63) 443 port [tcp/https] succeeded!
TLS handshake negotiated TLSv1.2/ECDHE-RSA-AES256-GCM-SHA384 with host hamesspam.sakura.ne.jp
Peer name: hamesspam.sakura.ne.jp
Subject: /OU=Domain Control Validated/CN=*.sakura.ne.jp
Issuer: /C=JP/ST=Tokyo/L=Chiyoda-ku/O=Gehirn Inc./CN=Gehirn Managed Certification Authority - RSA DV
Valid From: Thu Jun 28 09:00:00 2018
Valid Until: Sun Jun 28 08:59:59 2020
Cert Hash: SHA256:d80293e0830658934cad245ea6aa8690dbdd6008c9127575ef214559691a9232
OCSP URL: http://ocsp.usertrust.com
HTTP/1.1 403 Forbidden
Server: nginx
Date: Thu, 11 Jun 2020 23:27:07 GMT
Content-Type: text/html
Connection: close

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html lang="ja">
   :

今度は大丈夫。ちゃんと証明書の確認が出来た。もうすぐ証明書の有効期限が満了になるけど、ちゃんと更新してね。

detect fail point

オレオレ証明書なサーバーに接続した時、どんな風にブレーキがかかるか調べてみる。エラーになった時に、errxを使って表示してるようなので、それを頼りにbreakさせる。

(gdb) b errx
Function "errx" not defined.
Breakpoint 1 (errx) pending.
(gdb) r -cv -T protocols=all -T ciphers=compat localhost 443
Starting program: /tmp/nc/a.out -cv -T protocols=all -T ciphers=compat localhost 443

Breakpoint 1, _libc_errx (eval=1, fmt=0x44e8e256026 "tls handshake failed (%s)") at /usr/src/lib/libc/gen/errx.c:39
39              va_start(ap, fmt);
gdb) bt
#0  _libc_errx (eval=1, fmt=0xb1f0aab9026 "tls handshake failed (%s)") at /usr/src/lib/libc/gen/errx.c:39
#1  0x00000b1f0aabfaa7 in tls_setup_client (tls_ctx=0xb216eae0a00, s=3, host=0x7f7fffff2f45 "localhost") at netcat.c:834
#2  0x00000b1f0aabd9be in main (argc=2, argv=0x7f7fffff2de8) at netcat.c:740

巨大なmainから呼ばれている。

       if (timeout_tls(s, tls_ctx, tls_handshake) == -1) {
                if ((errstr = tls_error(tls_ctx)) == NULL)
                        errstr = strerror(errno);
=>              errx(1, "tls handshake failed (%s)", errstr);
        }

こんな所で、検出された。大事な内容は tls_ctx に入っている。

(gdb) p *tls_ctx
$4 = {
  config = 0x95ce9343a00,
  keypair = 0x95c1cec6d80,
  error = {
    msg = 0x95c67637d80 "certificate verification failed: self signed certificate",
    num = -1,
    tls = 1
  },
  flags = 1,
  state = 10,
  servername = 0x95c93860710 "localhost",
  socket = -1,
  :

この構造体のどれかが関数アドレスを保持してて、ハンドシェイクを実行してるはず。詳しくはソース嫁。

強引にやる

ob$ printf "GET / HTTP/1.0\r\n\r\n" |
nc -cv -T protocols=all -T ciphers=compat -T noverify -T noname localhost 443
Connection to localhost (127.0.0.1) 443 port [tcp/https] succeeded!
TLS handshake negotiated TLSv1.2/ECDHE-RSA-AES256-GCM-SHA384 with host localhost
Peer name: localhost
Subject: /C=JP/ST=Tokyo/L=edo/O=Yama/OU=devel/CN=ob.local.jp/emailAddress=hoge@openbsd.org
Issuer: /C=JP/ST=Tokyo/L=edo/O=Yama/OU=devel/CN=ob.local.jp/emailAddress=hoge@openbsd.org
Valid From: Mon Jun  8 09:01:17 2020
Valid Until: Tue Jun  8 09:01:17 2021
Cert Hash: SHA256:660197768a246a858731cdd46f0ec5c451afedd17305eba1da764ba140c37861
HTTP/1.0 200 OK
Connection: close
Content-Length: 33
Content-Type: text/html
Date: Fri, 12 Jun 2020 07:51:09 GMT
Last-Modified: Sun, 07 Jun 2020 21:05:02 GMT
Server: OpenBSD httpd

Hello, world. from OpenBSD httpd

証明書をチェックしない、名前も無視って言う、オレオレな人には嬉しいオプションを付けてあげたら、認証書を表示しつつ、Webにアクセス出来たよ(さっぱり嬉しくは無いけど)。

curl

普通なら、この辺でPythonどうよってなるんだろうけど、へそ曲がりなんで、カールおじさんです。

ob$ curl https://localhost
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

やっぱりブレーキがかかりましたねぇ。

ob$ curl -k https://localhost
Hello, world. from OpenBSD httpd

でも、ちゃんと抜け道は用意されてるよ。これって、オレオレほう助罪にならないかなあ?

gnutls

opensslと同族っぽいのにGNU系の、gnutlsが有る。訳も分からずに試してみた。

ob$ gnutls-cli -p 443 localhost
Processed 135 CA certificate(s).
Resolving 'localhost:443'...
Connecting to '127.0.0.1:443'...
 - Certificate type: X.509
 - Got a certificate list of 1 certificates.
 - Certificate[0] info
   :
 - Status: The certificate is NOT trusted. The certificate issuer is unknown. The name in the certificate does not match the expected.
 *** PKI verification of server certificate failed...
 *** Fatal error: Error in the certificate.

This year's Index

Home