Qt Tech. OpenSSL通信、HTTPS通信を行うプログラムが簡単じゃない!対処方法 新しいページはコチラ
提供: yonewiki
(→概要) |
|||
1行: | 1行: | ||
[[Qt#Qtテクニカルノート|Qtテクニンカルノート]]へ戻る | [[Qt#Qtテクニカルノート|Qtテクニンカルノート]]へ戻る | ||
== '''概要''' == | == '''概要''' == | ||
− | + | OpenSSLは数々の国々で武器輸出管理法の対象になることもあり、拠点を米国に置いていません。そして、Qtはフィンランドエスポーを拠点においていて、主要株主はフィンランドのノキアやデジアとなっています。開発の拠点はノルウェーのオスロという構造から、OpenSSLを抱き合わせる訳にはいかない技術になっています。( ゚д゚)ポカーン ソンナニスゴインダネ。でもQtだから使いやすいハズ。というわけで。 | |
+ | |||
+ | |||
+ | 説明書を読んでHTTP通信のプログラムを勉強しようとしたのですが、手に出来る説明書が古くて、HTTP通信とかやってるんすよ。今どきはhttp://のような通信プロトコルは、あまり使わない。https://これです。暗号化ですね。通信ログっていろいろな部分で確認できるようになっていて、暗号化していないと途中に待ち構えているルーティングの中にいるサーバの主が、悪意を持ってパスワードの入力や個人情報が飛んでくるのを待っていることがあります。これを防ぐのが暗号化です。 | ||
75行: | 78行: | ||
2020年4月21日のVersion1.1.1.gを使っているようです。 | 2020年4月21日のVersion1.1.1.gを使っているようです。 | ||
+ | |||
+ | |||
+ | ちなみにうまくSSLが使えていない場合は以下のようなエラーが取得できます。 | ||
+ | |||
+ | <syntaxhighlight2 lang="Cpp"> | ||
+ | qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed | ||
+ | </syntaxhighlight2> | ||
+ | |||
+ | 上記のメッセージは以下のようなシグナルとスロットの接続があった場合に | ||
+ | |||
+ | <syntaxhighlight2 lang="Cpp"> | ||
+ | … | ||
+ | connect(xxxxxNetAccess, SIGNAL(finished(QNetworkReply*)), | ||
+ | this, SLOT(readXml(QNetworkReply*)));//xxxxxNetAccess is QNetworkAccessManager Object. | ||
+ | … | ||
+ | xxxxxNetAccess->get(QNetworkRequest(QStringLiteral("https://www.yo-net.jp"))); | ||
+ | … | ||
+ | void xxx...xxx::readXml(QNetworkReply* reply){ | ||
+ | qDebug() << reply->error(); | ||
+ | } | ||
+ | </syntaxhighlight2> | ||
+ | |||
+ | 上記のように取得できるエラー出力で得られるモノです。処理は以下のような流れです。 | ||
+ | |||
+ | :1.QNetworkAccessManagerクラスのxxxxxNetAccessのシグナルfinished(QNetworkReply*)は状態通知を引数とする通信処理が完了関数が呼び出されたときに、reedXml(QNetworkReply*)関数を呼び出す仕組みにします。 | ||
+ | |||
+ | |||
+ | :2.xxxxxNetAccess->get()メンバ関数でQNetworkrequest(QStringLiteral("https://www.yo-net.jp"))の戻り値を引数にして通信処理を行います。これによりxxxxxNetAccessのfineshed(QNetworkReply*)が呼び出され、readXml関数が実行されます。 | ||
+ | |||
+ | |||
+ | :3.readXmlの引数である通信応答オブジェクトreplyからエラー内容を出力。 | ||
+ | |||
+ | |||
+ | というような流れです。 | ||
+ | |||
+ | |||
+ | これはSSL通信の準備が出来ていない事を示しています。ということですから、SSL設定を何かやらなくてはいけなくて、それをやっていないということらしい。 | ||
+ | |||
+ | |||
+ | そういうことなので、Qtのリファレンスを読んでみました。[https://doc.qt.io/qt-5/windows-requirements.html https://doc.qt.io/qt-5/windows-requirements.html]。するとやっぱり、自分でOpenSSLをセットアップしないとダメなんだそうな。ヘ(゚д゚)ノ ナンジャソリャ? | ||
+ | |||
+ | |||
+ | 上記のリンクの記事の見出し辺りを読むと、スグにオープンソースの本家[https://github.com/openssl/openssl https://github.com/openssl/openssl]のWinows版([https://slproweb.com/products/Win32OpenSSL.html https://slproweb.com/products/Win32OpenSSL.html])を提供しているサイトに出向いて、インストールしたくなりますが、実際はQtの追加コンポーネントとして、最適なOpenSSLが入手できるとなっています。そして、Qtのコンポーネントとして導入するOpenSSLは、最も最適化されているという文献を見つけたりしたのです。 | ||
+ | |||
+ | |||
+ | なので、まずはC:\QtにあるMaintenanceTool.exeを起動して、ログイン情報を入力して、[Next](※SignUpボタンは新規アカウント作成なので押し間違えない。)を押して、add or remove Components を選択して[Next]、追加コンポーネント選択画面でQt>>Developper and Designer Tools>>>>OpenSSL1.1.1j Toolkitを選択する。あとは[Next]を続けざまに押し行くだけです。これで、C:\Qt\Tool\OpenSSLに一式が配置されます。 | ||
+ | |||
+ | |||
+ | ネットの多くの文献によると、プロジェクトファイルのディレクトリに2つのdllを置くべきだと言っている。その二つはssleay32.dll、libeay32.dllだという(以降は二つを合わせて*eay32.dllと表現)。あるいはlibssl-1_1.dll、libcrypto-1_1.dll(以降は二つを合わせて*-1_1.dllと表現)。とは言いつつ*eay32.dllは手元に無い状態です。古いSSLにあるらしい。OpenSSL1.1.1j Toolkitで入手したファイル群のC:\Qt\Tool\OpenSSL\binはlibssl-1_1.dll、libcrypto-1_1.dllの二つしかない。 | ||
+ | |||
+ | |||
+ | *eay32.dllと*1_1.dllの違いは端的に言えば、古いか新しいかの違いがあるらしい。中身が似通っているかっていうとそうでもなないらしい。そして、Qt5.15.2では*1_1.dllが配置されている。なので、使い方があるのかどうかわからないにしても、*1_1.dllをなんとかして使うらしい。 | ||
+ | |||
+ | |||
+ | ここからが難しそうだなと思ったのですが、<span style = "background:linear-gradient(transparent 75%, #ff7f7f 75%); font-weight:bold; ">開発しているプログラムの実行ファイルが配置されるディレクトリと同じディレクトリに*1_1.dllを配置すると有効になりました。</span> | ||
+ | |||
+ | |||
+ | |||
+ | <syntaxhighlight2 lang="cpp"> | ||
+ | qDebug() << QSslSocket::supportsSsl(); | ||
+ | </syntaxhighlight2> | ||
+ | 出力結果 | ||
+ | <syntaxhighlight2 lang="cpp"> | ||
+ | true | ||
+ | </syntaxhighlight2> | ||
+ | |||
+ | |||
+ | とくに、SSL通信をするための準備をする必要も無くQNetworkAccessManageクラスだけで通信できるようになります。 | ||
+ | |||
+ | |||
+ | 簡単なプログラムの流れは以下になると思います。 | ||
+ | |||
+ | |||
+ | |||
+ | ===''' 処理の流れ '''=== | ||
+ | <syntaxhighlight2 lang="Cpp"> | ||
+ | void CqApp::Init() //CqApp は QObject を継承したQtの機能的クラスの派生クラス(QSystemTrayIcon,QPlainTextEdit,とか | ||
+ | //QNetworkAccessMangeの機能を使う以上は引数thisポインタが必要なので | ||
+ | //QObjectから派生しているクラスである必要がある。 | ||
+ | { | ||
+ | //ここでのInitメンバ関数は初期化とかコンストラクタのような処理 | ||
+ | |||
+ | qNetworkAcessManager_Data = new QNetworkAccessManager(this); | ||
+ | //QNetworkAccessManagerクラスのオブジェクトを生成します。左辺は自分で決めていいです。任意でどうぞ。 | ||
+ | //QNetworkAccessManager* qNetworkAcessManager_Data;のようなメンバ変数としての宣言が事前に必要です。 | ||
+ | … | ||
+ | |||
+ | connect(qNetworkAcessManager_Data, SIGNAL(finished(QNetworkReply*)), | ||
+ | this, SLOT(readData(QNetworkReply*))); | ||
+ | |||
+ | //こんな感じでQt独特のシグナルとスロットという考え方の関数で | ||
+ | //qNetworkAcessManager_Dataのfinishedという通知(引数は内部的にQNetworkRply*型)を受け取ると | ||
+ | //このクラスのreadDataメンバ関数を(内部的にQNetworkRply*型を引数として)呼び出すことを宣言します。 | ||
+ | //イベント駆動のやり方です。 | ||
+ | |||
+ | qDebug() << QSslSocket::supportsSsl(); | ||
+ | //SSL通信ができるか確認できる。true(=正常) or false(=ちゃんと設定出来ていない)。 | ||
+ | |||
+ | CqApp::request(); | ||
+ | … | ||
+ | } | ||
+ | … | ||
+ | void CqApp::request() | ||
+ | { | ||
+ | … | ||
+ | qNetworkAcessManager_Data->get( QNetworkRequest(QUrl(QStringLiteral("https://xxx.xx/data.xml")))); | ||
+ | //メンバ変数を利用してget関数に指定したアドレスの内容を読み込みます。 | ||
+ | //通信が終わったらシグナルスロットの仕組みによりthis::readData関数が呼び出されます。 | ||
+ | … | ||
+ | } | ||
+ | … | ||
+ | void CqApp::readData(QNetworkReply *qNetworkReply_Reply) | ||
+ | { | ||
+ | … | ||
+ | if(qNetworkReply_Reply->error() != QNetworkReply::NoError) { | ||
+ | // この区間でSSL通信エラーが発生した時の処理 | ||
+ | } | ||
+ | else{ | ||
+ | // この区間で通信成功時の処理 | ||
+ | } | ||
+ | … | ||
+ | } | ||
+ | </syntaxhighlight2> | ||
+ | |||
+ | 大まかな流れは、こんな感じですね。具体的なサンプルじゃなくて申し訳ない。 | ||
+ | |||
+ | |||
+ | |||
+ | ===''' 発展的な内容 '''=== | ||
+ | dll(動的リンク)で動作するのはわかった。じゃぁ静的リンクはどうなんだ?C:\Qt\Tools\OpenSSL\Win_x86\libにlibcrypt.libとlibssl.libの二つのライブラリがありました。これで取り込まれるようにできるのかなって思った。静的リンクに変更できるか確認をしてみたいと思います。もうちょっと時間かかるかもな。管理人にとっては割かし複雑な構造をしていると感じるQt手強い。 | ||
[[Qt#Qtテクニカルノート|Qtテクニンカルノート]]へ戻る | [[Qt#Qtテクニカルノート|Qtテクニンカルノート]]へ戻る |