SSLを使った通信がうまくいかない

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
顔顔プリン
記事: 10
登録日時: 15年前

SSLを使った通信がうまくいかない

#1

投稿記事 by 顔顔プリン » 13年前

今HTTPクライアントを作っていてHTTP通信はうまくいきopenSSLを使いHTTPS通信をしています。
http://www.verisign.co.jp、こちらのページへのHTTPS通信は以下のコードでうまくいったのですが
secure.nicovideo.jp(ニコニコ)へのログインをするためのHTTPS通信がうまくいきません。
SSL_connect()の部分で止まっているのでSSLの設定がいけないと思っています。
↑のほうはリクエストがGET ニコニコはPOSTなのですがこの辺も関係してるんでしょうか?
何かアドバイスお願いします。

コード:

#include <iostream>
#include <string>
#include <winsock2.h>

#include <openssl\ssl.h>
#include <openssl\crypto.h>
#include <openssl\err.h>
#include <openssl\rand.h>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")

int main(void) {

	WSADATA wsaData;
	struct sockaddr_in server;
	SOCKET sock;
	std::string req;		// リクエスト
	std::string res;		// レスポンス
	//std::string host_url = "www.verisign.co.jp";	// URLのホスト名
	//req = "GET / HTTP/1.0\r\n\r\n";
	std::string host_url = "secure.nicovideo.jp";
	req = "POST /secure/login?site=nicolive_antenna HTTP/1.0\r\n";
	req += "mail=&password=\r\n\r\n";

	SSL *ssl;
	SSL_CTX *ctx;

	// Winsockの設定
	WSAStartup(MAKEWORD(2, 0), &wsaData);

	sock = socket(AF_INET, SOCK_STREAM, 0);

	server.sin_family = AF_INET;
	server.sin_port = htons(443);

	server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str());
	if (server.sin_addr.S_un.S_addr == 0xffffffff) {
		struct hostent *host;
		unsigned int **addrptr;

		host = gethostbyname(host_url.c_str());
		if (host == NULL) {
			return 1;
		}

		addrptr = (unsigned int **)host->h_addr_list;
		while (*addrptr != NULL) {
			server.sin_addr.S_un.S_addr = *(*addrptr);
			if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
				break;
			}
		}

		if (*addrptr == NULL) {
			return 1;
		}
	}
	else {
		if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0)
			return 1;
	}
	
	SSL_load_error_strings();
	SSL_library_init();
	ctx = SSL_CTX_new(SSLv23_client_method());
	if (ctx == NULL) {
		return 1;
	}

	ssl = SSL_new(ctx);
	if (ssl == NULL) {
		return 1;
	}

	if (SSL_set_fd(ssl, sock) == 0) {
		return 1;
	}

	RAND_poll();
	
	while (RAND_status() == 0) {
		unsigned short rand_ret = rand() % 65536;
		RAND_seed(&rand_ret, sizeof(rand_ret));
	}

	if (SSL_connect(ssl) != 1) {
		ERR_print_errors_fp(stderr);
		return 1;
	}
	SSL_write(ssl, req.c_str(), req.length());

	std::cout << "サーバからのレスポンス" << std::endl;
	while (1) {
		char buf[1024] = {0};
		if (SSL_read(ssl, buf, sizeof(buf)-1) <= 0)
			break;
		res += buf;
	}

	std::cout << res << std::endl;

	SSL_shutdown(ssl);
	SSL_free(ssl);
	SSL_CTX_free(ctx);
	ERR_free_strings();

	closesocket(sock);

	WSACleanup();

	return 0;		
}
追記:
rubyはやったことが無いのですがこのようなコードで実装できるようです。
http://hai3.net/blog/tag/%E3%83%8B%E3%8 ... %E7%94%BB/
ただ、C/C++で長くやってきたのでなんとか実装させたい・・・

たろ

Re: SSLを使った通信がうまくいかない

#2

投稿記事 by たろ » 13年前

POSTリクエストの形式が正しくないように見えます。
----------------------------------------
POST /path HTTP/1.0
Content-Length: データバイト数

データ
----------------------------------------
という仕様だったように思います。
ソースから推測すると以下のような感じかな・・
------------------------------------------------------------------------
POST /secure/login?site=nicolive_antenna HTTP/1.0\r\n
Content-Length: 15\r\n
\r\n
mail=&password=
------------------------------------------------------------------------
改行コード修正、Content-Lengthヘッダ生成処理を追加してみてください。

#ソースコード見ただけでコメントしています悪しからず・・・

顔顔プリン
記事: 10
登録日時: 15年前

Re: SSLを使った通信がうまくいかない

#3

投稿記事 by 顔顔プリン » 13年前

たろ さんが書きました:POSTリクエストの形式が正しくないように見えます。
----------------------------------------
POST /path HTTP/1.0
Content-Length: データバイト数

データ
----------------------------------------
という仕様だったように思います。
ソースから推測すると以下のような感じかな・・
------------------------------------------------------------------------
POST /secure/login?site=nicolive_antenna HTTP/1.0\r\n
Content-Length: 15\r\n
\r\n
mail=&password=
------------------------------------------------------------------------
改行コード修正、Content-Lengthヘッダ生成処理を追加してみてください。

#ソースコード見ただけでコメントしています悪しからず・・・
ありがとうございます><
Content-Length: を足したらうまくいきました。
またニコニコのセキュア通信なんですがopenSSLライブラリを使う場合、SSLv2 SSLv3だとうまくハンドシェイクが行われずTLSv1のみうまくいくみたいでした。
(他のものは使ってないので詳細についてはわからないです)
ので
ctx = SSL_CTX_new(SSLv23_client_method());

ctx = SSL_CTX_new(TLSv1_method());にすることでうまく動作ようです。

閉鎖

“C言語何でも質問掲示板” へ戻る