Use OpenSSL API to connect to Lighttpd Server

0. 前提条件

关于SSL和OpenSSL的工作原理比较复杂,我只是了解一二,

所以这里并不会讲解SSL和OpenSSL到底是如何工作的,下面

仅给出一些相关参考资料:

在继续往下看之前,请确保已经了解SSL/OpenSSL/Lighttpd如何工作。


1. 使用openssl命令生成证书和密钥

$openssl req -new -x509 -keyout lighttpd.pem -out lighttpd.pem -days 365 -nodes
$chmod 400 lighttpd.pem
$sudo chown root lighttpd.pem
$sudo mv lighttpd.pem /etc/lighttpd/lighttpd.pem
为了安全考虑,所以要确保对lighttpd.pem设置合适的权限。

另外由于lighttpd运行的时候具有root权限,所以不用担心lighttpd无法读取lighttpd.pem


2.  配置lighttpd

先确保lighttpd支持ssl:

输入lighttpd -v , 如果输出包含(ssl)就OK。

再来配置lighttpd.conf,加上下面的配置:

$SERVER["socket"] == ":443" {
	ssl.engine		= "enable"
	ssl.pemfile		= "/etc/lighttpd/lighttpd.pem"
}
然后我们运行lighttpd服务器:

$sudo lighttpd -f /etc/lighttpd/lighttpd.conf

最后我们用浏览器打开https://localhost来测试一下ssl能否工作,由于我们的证书是自己

生成的,浏览器不信任它,所以浏览器会警告我们,我们可以手动添加信任,这时候ssl

已经可以正常工作了。


3. 使用OpenSSL API与lighttpd建立连接:

关于API的说明请参考前面给出的链接,我这里就不说明了(其实我只知道怎么用)

下面给出两个版本的程序,一个使用非安全连接,另一个使用安全连接。

非安全连接:

#include <stdio.h>
#include <stdlib.h>
/* OpenSSL headers */
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

int main(int argc, char *argv[])
{
        BIO *bio;
        char host_port[100];
        char buf[1024], req[1024];
        int n;

        if (argc != 3) {
                fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
                exit(EXIT_FAILURE);
        }

        snprintf(host_port, sizeof(host_port) - 1,
                 "%s:%s", argv[1], argv[2]);

        /* Initializing OpenSSL */
        SSL_load_error_strings();
        ERR_load_BIO_strings();
        OpenSSL_add_all_algorithms();

        bio = BIO_new_connect(host_port);
        if (bio == NULL) {
                fprintf(stderr, "error: BIO_new_connect");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }
        if (BIO_do_connect(bio) <= 0) {
                fprintf(stderr, "error: BIO_do_connect");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }

        printf("connected to %s\n\n", host_port);

        snprintf(req, sizeof(req),
                 "GET / HTTP/1.1\r\n"
                 "Host: %s\r\n"
                 "\r\n", argv[1]);

        BIO_write(bio, req, strlen(req));

        while (1) {
                n = BIO_read(bio, buf, sizeof(buf));

                if (n > 0)
                        write(fileno(stdout), buf, n);
                else if (n == 0)
                        break;
                else {
                        if (!BIO_should_retry(bio))
                                break;
                        else
                                continue;
                }
        }

#if 0
        /* To reuse the connection, use this line */
        BIO_reset(bio);
#endif
        /* To free it from memory, use this line */
        BIO_free_all(bio);

        return 0;
}

安全连接:

安全连接要复杂一点,其中SSL_CTX_load_verify_locations()需要加载证书库,

我们可以用刚才生成的lighttpd.pem(注意路径),由于lighttpd也是使用这个证书,所以我们

可以顺利连接。我们还可以另外生成一个新的证书,测试一下能否通过验证。

#include <stdio.h>
#include <stdlib.h>
/* OpenSSL headers */
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

int main(int argc, char *argv[])
{
        BIO     *bio;
        SSL_CTX *ctx;
        SSL     *ssl;
        char     host_port[100];
        char     buf[1024], req[1024];
        int      n;

        if (argc != 3) {
                fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
                exit(EXIT_FAILURE);
        }

        snprintf(host_port, sizeof(host_port) - 1,
                 "%s:%s", argv[1], argv[2]);

        /* Initializing OpenSSL */
        SSL_load_error_strings();
        ERR_load_BIO_strings();
        OpenSSL_add_all_algorithms();
        /**
         * I need to call this before SSL_CTX_new(),
         * or it ctx will be null.
         *
         * May be a bug ?
         **/
        SSL_library_init();

        ctx = SSL_CTX_new(SSLv23_client_method());
        if (ctx == NULL) {
                fprintf(stderr, "error: SSL_CTX_new\n");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }

        if (!SSL_CTX_load_verify_locations(ctx, "lighttpd.pem", NULL)) {
                fprintf(stderr, "error: SSL_CTX_load_verify_locations\n");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }

        bio = BIO_new_ssl_connect(ctx);
        if (bio == NULL) {
                fprintf(stderr, "error: BIO_new_ssl_connect");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }
        BIO_get_ssl(bio, &ssl);
        SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

        /* Attempt to connect */
        BIO_set_conn_hostname(bio, host_port);
        /* Verify the connection opened and perform the handshake */
        if (BIO_do_connect(bio) <= 0) {
                fprintf(stderr, "error: BIO_do_connect\n");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }

        if (SSL_get_verify_result(ssl) != X509_V_OK) {
                fprintf(stderr, "error: SSL verify failed.\n");
                ERR_print_errors_fp(stderr);
                exit(EXIT_FAILURE);
        }

        printf("connected to %s\n\n", host_port);

        snprintf(req, sizeof(req),
                 "GET / HTTP/1.1\r\n"
                 "Host: %s\r\n"
                 "\r\n", argv[1]);

        BIO_write(bio, req, strlen(req));

        while (1) {
                n = BIO_read(bio, buf, sizeof(buf));

                if (n > 0)
                        write(fileno(stdout), buf, n);
                else if (n == 0)
                        break;
                else {
                        if (!BIO_should_retry(bio))
                                break;
                        else
                                continue;
                }
        }

#if 0
        /* To reuse the connection, use this line */
        BIO_reset(bio);
#endif
        /* To free it from memory, use this line */
        BIO_free_all(bio);
        SSL_CTX_free(ctx);

        return 0;
}

Makefile:

LDFLAGS = -lssl -lcrypto

secure: openssl_test.c
    gcc -o $@ $^ $(LDFLAGS)

nosecure: openssl_test_nosecure.c
    gcc -o $@ $^ $(LDFLAGS)

最后测试一下:

$./nosecure localhost 80
$./secure localhost 443
注意:两个程序都是请求localhost的主页,所以要确保相关的设置都正确。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值