2022-12-28 (水)
* ADBのTLS接続
Android 11からADBのTLS接続がサポートされてるのでGoで実装してみる。もちろん標準のadbコマンドはTLS接続をサポートしているのだけど、https://github.com/binzume/adbproto で使いたかった。
TLSで接続すると、WiFi上でも安全に使えるのと、Androidの設定から有効にできるので再起動の度にUSBでつないでadb tcpip 5555
とかしなくて済む。
Androidのドキュメント読んでもどういう挙動をするのか特に書かれてなさそう。とりあえずAndroidの設定画面にIPとポートが表示されてるけど、接続してみてもTLSのハンドシェイクが始まるわけではなかった。
listenしてるのはadbdっぽいので、TCPで接続してADBのCNXNパケットを送信するとSTLSパケットが送られてくる。STLSを返答したあと、TLSのハンドシェイクを始めれば良さそう。
AdbKey-0
という証明書が要求されるけど、事前にadb pair
コマンドやQRコード経由で証明書を登録してある必要がある。ただ、ADBのRSA鍵がAndroidに登録済みならそれを使って接続できた。
OPENで開いたストリームを暗号化するのかとも思ったけど、ADBパケット自体を暗号化するっぽい。
接続できると、CNXNパケットがTLS越しに送られてきて、TLS越しにADBのパケットを送受信できるようになる。
最初なんか上手くいかないと思ったら、tls.ConfigのGetClientCertificateの実装がまずいだけだった。
GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { return &tls.Certificate{ PrivateKey: key, SupportedSignatureAlgorithms: cri.SignatureSchemes, Leaf: cert, }, nil },
としてたのだけど、Leafにx509.Certificateを入れても使ってくれなくて、Certificate.CertificateにDERエンコードした証明書を入れる必要があった。GetClientCertificateの説明を見るとちゃんと書いてあるのだけど、tls.CertificateのコメントにはPrivateKeyはLeafに対するものだと書いてあるし、Certificateが複数あってもPrivateKeyは一つだったり、なんだか騙された気分。。。
GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { return &tls.Certificate{ Certificate: [][]byte{der}, PrivateKey: key, }, nil },
GoのcryptoパッケージはOpenSSLと少し使い方が違うので、初めて何かするとき色々嵌まりやすい気がする。