1.実行環境
・Windows10にVirtualBoxの仮想マシンがインストールされている
・仮想マシンのOSはCentOS8で、Apatch(HTTPサーバ)がインストールされている
(1)HTTPサーバのバージョンの確認
# httpd -v
(2)httpサーバの起動
# systemctl start httpd
# systemctl is-active httpd
(3)ブラウザから接続
/var/www/html
のフォルダにあるindex.html
が表示される
2.HttpサーバのSSL化
(1)SSLモジュールのインストール
ApacheでSSLを利用ため必要なソフトウェア
・OpenSSL:SSLを利用するために必要なソフトウェア
・mod_ssl:OpenSSLを使ってApacheをSSLに対応させるモジュール
OpenSSLはCentOSをデフォルト設定でインストールされる。OpenSSLがインストールされているかどうか確認する。
# rpm -qa | grep openssl
インストールされていないときは、下記のコマンドでインストールする。
# yum install openssl
バージョンの確認
# openssl version
CentOS8が2021年末にサポート切れでミラーサイトが停止され、パッケージのインストールに失敗した。
(対策)
下記のファイルで、参照先のリポジトリをミラーサイトからhttp://vault.centos.orgに変更する。
/etc/yum.repos.d/CentOS*repo
①CentOS-Linux-AppStream.repo
②CentOS-Linux-BaseOS.repo
:
変更前:
[appstream]
name=CentOS Linux $releasever – AppStream
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=AppStream&infra=$infra
#baseurl=http://mirror.centos.org/$contentdir/$releasever/AppStream/$basearch/os/
:
↓
mirrorlist=・・・をコメント化し、#baseurl=http://mirror.centos.org/・・・のコメントを外し、”mirror”を”vault”に変更
変更後:
[appstream]
name=CentOS Linux $releasever – AppStream
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=AppStream&infra=$infra
baseurl=http://vault.centos.org/$contentdir/$releasever/AppStream/$basearch/os/
参照先のリポジトリを変更したあと再度、下記コマンドでインストールする
# yum install mod_ssl
下記コマンドでインストールされたことを確認する
# rpm -qa | grep mod_ssl
※rpmコマンド
オプション-q:問い合わせ(パッケージ情報の表示と検索)
-a:情報問い合わせ関連(-q、-Vと一緒に使用するオプション)でall
(4)秘密鍵とサーバ証明書の作成
・秘密鍵の作成
# openssl genrsa > server.key
・サーバ証明書の作成
CSRファイル(認証局にサーバ証明書を発行してもらう時に使用するファイル)を作成
# openssl req -new -key server.key > server.csr
下記はEnterでテストでは入力無しとした
:
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server’s hostname) []:
Email Address []:
Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
・サーバ証明書への署名
本来はこのCSRファイルを認証局に渡して署名してもらう必要があるが、ここではテストのため、自分で署名するため、以下のコマンドを実行。
# openssl x509 -req -signkey server.key < server.csr > server.crt
(5)秘密鍵とサーバ証明書の配置
作成した鍵と証明書を/etc/httpd/以下に配置する。
ここでは
/etc/httpd/conf/ssl.keyおよび/etc/httpd/conf/ssl.crt配下に置く
# mkdir /etc/httpd/conf/ssl.key
# mkdir /etc/httpd/conf/ssl.crt
# mv server.key /etc/httpd/conf/ssl.key/
# mv server.crt /etc/httpd/conf/ssl.crt/
(6)SSLモジュールの設定
/etc/httpd/conf.d/ssl.confの中に、配置した鍵と証明書のパスを設定する。
# vi /etc/httpd/conf.d/ssl.conf
:
#SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
:
#SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
:
(7)Apacheを再起動して接続する
# systemctl restart httpd
# systemctl is-active httpd
ssl.confを修正したあと、起動に失敗する
SELinuxが影響していると考えられるため、テストではSELinuxを無効とする
現在
[root@localhost conf.d]# getenforce
Enforcing
一時的にpermissiveモードに変更
[root@localhost conf.d]# getenforce
Permissive
上記の変更をしてhttpサーバが起動できた
[root@localhost conf.d]# systemctl restart httpd
[root@localhost conf.d]# systemctl is-active httpd
active
(8)ブラウザからHttpsサーバに接続
CentOSのディスクトップのブラウザから接続
https://localhost
サーバから取得したサーバ証明書では、ルート証明書との正当性が確認できないため、エラーになったと考えられる。
「詳細情報」を選択して、次に進み、強制的に許可する。
また、ホストPC(Windows10)のブラウザからアクセスしたとき
http://localhostでは接続できるが、https://localhostでは接続できない
コマンドプロンプトからcurlコマンドで、SSL接続で証明書エラーをスキップして接続することで、httpsサーバからのレスポンスが正常に処理される。
# curl -k https://localhost
3.Httpsクライアントの作成
(1)openssl-devel パッケージのインストール
openssl-devel は各種の暗号化アルゴリズムとプロトコルをサポートしたアプリケーションを開発するために必要な静的ライブラリとヘッダーファイルが含まれている。
# yum install openssl-devel
(2)クライアントのソースファイル
client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
int main(void) {
int mysocket;
struct sockaddr_in server;// ホストのIPアドレスなど情報を保持する構造体
struct addrinfo hints, *res;
SSL *ssl;
SSL_CTX *ctx;
char msg[100];
char *host = "localhost";
char *path = "/";
int port = 443;
// IPアドレスの解決
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;//インターネットプロトコル
hints.ai_socktype = SOCK_STREAM;
char *service = "https";
int err = 0;
if ((err = getaddrinfo(host, service, &hints, &res)) != 0) {
fprintf(stderr, "Fail to resolve ip address - %d\n", err);
return EXIT_FAILURE;
}
//ソケット
if ((mysocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
fprintf(stderr, "Fail to create a socket.\n");
return EXIT_FAILURE;
}
//コネクト
if (connect(mysocket, res->ai_addr, res->ai_addrlen) != 0) {
printf("Connection error.\n");
return EXIT_FAILURE;
}
//SSLセットアップ
SSL_load_error_strings();/OpenSSLのエラー文の読み込み
SSL_library_init();//SSLの初期化
//SSL_CTX構造体生成
ctx = SSL_CTX_new(SSLv23_client_method()); //引数は使用するプロトコルの種類
//SSLの構造体生成
ssl = SSL_new(ctx);
err = SSL_set_fd(ssl, mysocket);//SSL構造体とソケットの関連付け
SSL_connect(ssl);/サーバとハンドシェイクを行う
printf("Conntect to %s\n", host);
//HTTPリクエストの送信
sprintf(msg, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", path, host);
SSL_write(ssl, msg, strlen(msg));
int buf_size = 256;
char buf[buf_size];
int read_size;
//レスポンスの受信
do {
read_size = SSL_read(ssl, buf, buf_size);
write(1, buf, read_size);
} while(read_size > 0);
//SSLとソケットの終了処理
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
ERR_free_strings();
close(mysocket);
return EXIT_SUCCESS;
}
(3)クライアントソースファイルのコンパイル
# gcc client.c -o client -lssl -lcrypto
(4)httpsサーバの起動
# setenforce 0
# systemctl start httpd
(5)httpsクライアントの起動
# ./client
Conntect to localhost
HTTP/1.1 200 OK
Date: Sun, 22 May 2022 00:50:46 GMT
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1k
Last-Modified: Sun, 08 May 2022 01:59:00 GMT
ETag: "c3-5de766f65c100"
Accept-Ranges: bytes
Content-Length: 195
Connection: close
Content-Type: text/html; charset=UTF-8
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>画像テスト</title>
</head>
<body>
<p>画像のテスト</p>
<img src="test.jpg">
</body>
</html>
httpサーバにsslで接続できて、レスポンスのhtmlファイルが返却された
The end