openssl3.2 - 官方demo学习 - guide - tls-client-block.c

news2024/11/26 22:50:25

文章目录

    • openssl3.2 - 官方demo学习 - guide - tls-client-block.c
    • 概述
    • 记录问题
    • server和client IP都为localhost
    • server和client IP都为127.0.0.1
    • 想到解决问题的方法1
    • 想到解决问题的方法2
    • 笔记
    • END

openssl3.2 - 官方demo学习 - guide - tls-client-block.c

概述

tls 客户端
官方demo有问题, 无法建立客户端socket, 可以确认sSever没问题, 用tcping试过了.

启动server和Client时, 都用127.0.0.1是可以建立socket的, 可以通讯.
但是说IP不匹配, 以后再玩.(等自己做了靠谱的证书实验, 再继续验证这个官方demo)

记录问题

程序编译完, 做了2个脚本来实验.
分为2种情况记录

server和client IP都为localhost

@echo off
rem run_tls_server.cmd
echo tls server
set path=c:\openssl_3d2\bin;%path%
echo begin : %date% %time%
openssl s_server -www -accept localhost:23456 -cert servercert.pem -key serverkey.pem
echo end : %date% %time%
pause

@echo off
echo run_tls_client.cmd
set path=c:\openssl_3d2\bin;%path%
echo begin : %date% %time%
set SSL_CERT_FILE=rootcert.pem
prj_template.exe localhost 23456
echo end : %date% %time%
pause

先启动server的bat, 再启动client的bat
在这里插入图片描述
客户端报错信息显示建立socket失败.
服务器端一点反应没有, 说明客户端没连上服务器.
用tcping试试端口
在这里插入图片描述
ping localhost 23456 时, 端口是能访问的.
ping 127.0.0.1 23456时, 端口是不能访问的.
说明客户端访问服务时, 用localhost要能访问才对.
这是不是官方demo有问题啊…

server和client IP都为127.0.0.1

@echo off
rem run_tls_server.cmd
echo tls server
set path=c:\openssl_3d2\bin;%path%
echo begin : %date% %time%
openssl s_server -www -accept 127.0.0.1:23456 -cert servercert.pem -key serverkey.pem
echo end : %date% %time%
pause

@echo off
echo run_tls_client.cmd
set path=c:\openssl_3d2\bin;%path%
echo begin : %date% %time%
set SSL_CERT_FILE=rootcert.pem
prj_template.exe 127.0.0.1 23456
echo end : %date% %time%
pause

在这里插入图片描述
显示IP不匹配.
莫非只能用远程域名来访问? 不能用绝对IP来访问? 说不通啊.
只能先放这里, 等有头绪了再来尝试解决.

想到解决问题的方法1

我已经编译好了可以run的openssl.exe工程(openssl3.2 - 自己构建openssl.exe的VS工程(在编译完的源码版本上))

给好启动server的参数和环境变量
在这里插入图片描述
在这里插入图片描述
跑起来效果是一样的
在这里插入图片描述
那么, 用127.0.0.1 23456 连上来的客户端, 如果有啥错误提示(e.g. IP不匹配), 那我可以在openssl.exe源码中单步查啊. 就知道为啥报错了.

想到解决问题的方法2

既然openssl.exe可以模拟一个服务, 那么也可以模拟一个客户端.
看了openssl.exe的实现, 确实有.
在这里插入图片描述
那我可以用openssl.exe模拟一个客户端,带着相同的参数跑起来, 如果正常, 我就移植(抄代码), 就实现了一个客户端.

等后续按照这2个思路试试.
openssl提供的demo不可能全部正确的, 前面已经发现了官方应用的demo实现有问题(e.g. openssl3.2 - 官方demo学习 - cms - cms_uncomp.c(官方应用实现错误, 需要修正)).

但是原版的openssl.exe实现是没有问题的(那么多openssl用户, 很多人都用openssl.exe直接来干活, 如果有啥bug, 早就修正了, 不可能埋雷).
所以参照openssl.exe的客户端实现, 是绝对没问题的.

笔记

/*!
    \file tls-client-block.c
    \note 
    openssl3.2 - 官方demo学习 - guide - tls-client-block.c
    tls 客户端
    官方demo有问题, 无法建立客户端socket, 可以确认sSever没问题, 用tcping试过了.
  
    启动server和Client时, 都用127.0.0.1是可以建立socket的, 可以通讯.
    但是说证书不匹配, 以后再玩.
*/

/*
 *  Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
 *
 *  Licensed under the Apache License 2.0 (the "License").  You may not use
 *  this file except in compliance with the License.  You can obtain a copy
 *  in the file LICENSE in the source distribution or at
 *  https://www.openssl.org/source/license.html
 */

/*
 * NB: Changes to this file should also be reflected in
 * doc/man7/ossl-guide-tls-client-block.pod
 */

#include <string.h>

/* Include the appropriate header file for SOCK_STREAM */
#ifdef _WIN32 /* Windows */
# include <winsock2.h>
#else /* Linux/Unix */
# include <sys/socket.h>
#endif

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#include "my_openSSL_lib.h"

/* Helper function to create a BIO connected to the server */
static BIO *create_socket_bio(const char *hostname, const char *port, int family)
{
    int sock = -1;
    BIO_ADDRINFO *res;
    const BIO_ADDRINFO *ai = NULL;
    BIO *bio;

    /*
     * Lookup IP address info for the server.
     */
    if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_STREAM, 0,
                       &res))
        return NULL;

    /*
     * Loop through all the possible addresses for the server and find one
     * we can connect to.
     */
    for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
        /*
         * Create a TCP socket. We could equally use non-OpenSSL calls such
         * as "socket" here for this and the subsequent connect and close
         * functions. But for portability reasons and also so that we get
         * errors on the OpenSSL stack in the event of a failure we use
         * OpenSSL's versions of these functions.
         */
        sock = BIO_socket(BIO_ADDRINFO_family(ai), SOCK_STREAM, 0, 0);
        if (sock == -1)
            continue;

        /* Connect the socket to the server's address */
        if (!BIO_connect(sock, BIO_ADDRINFO_address(ai), BIO_SOCK_NODELAY)) {
            BIO_closesocket(sock);
            sock = -1;
            continue;
        }

        /* We have a connected socket so break out of the loop */
        break;
    }

    /* Free the address information resources we allocated earlier */
    BIO_ADDRINFO_free(res);

    /* If sock is -1 then we've been unable to connect to the server */
    if (sock == -1)
        return NULL;

    /* Create a BIO to wrap the socket */
    bio = BIO_new(BIO_s_socket());
    if (bio == NULL) {
        BIO_closesocket(sock);
        return NULL;
    }

    /*
     * Associate the newly created BIO with the underlying socket. By
     * passing BIO_CLOSE here the socket will be automatically closed when
     * the BIO is freed. Alternatively you can use BIO_NOCLOSE, in which
     * case you must close the socket explicitly when it is no longer
     * needed.
     */
    BIO_set_fd(bio, sock, BIO_CLOSE);

    return bio;
}

/*
 * Simple application to send a basic HTTP/1.0 request to a server and
 * print the response on the screen.
 */
int main(int argc, char *argv[])
{
    SSL_CTX *ctx = NULL;
    SSL *ssl = NULL;
    BIO *bio = NULL;
    int res = EXIT_FAILURE;
    int ret;
    const char *request_start = "GET / HTTP/1.0\r\nConnection: close\r\nHost: ";
    const char *request_end = "\r\n\r\n";
    size_t written, readbytes;
    char buf[160];
    char *hostname, *port;
    int argnext = 1;
    int ipv6 = 0;

    if (argc < 3) {
        printf("Usage: tls-client-block [-6]  hostname port\n");
        goto end;
    }

    if (!strcmp(argv[argnext], "-6")) {
        if (argc < 4) {
            printf("Usage: tls-client-block [-6]  hostname port\n");
            goto end;
        }
        ipv6 = 1;
        argnext++;
    }
    hostname = argv[argnext++];
    port = argv[argnext];

    /*
     * Create an SSL_CTX which we can use to create SSL objects from. We
     * want an SSL_CTX for creating clients so we use TLS_client_method()
     * here.
     */
    ctx = SSL_CTX_new(TLS_client_method());
    if (ctx == NULL) {
        printf("Failed to create the SSL_CTX\n");
        goto end;
    }

    /*
     * Configure the client to abort the handshake if certificate
     * verification fails. Virtually all clients should do this unless you
     * really know what you are doing.
     */
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

    /* Use the default trusted certificate store */
    if (!SSL_CTX_set_default_verify_paths(ctx)) {
        printf("Failed to set the default trusted certificate store\n");
        goto end;
    }

    /*
     * TLSv1.1 or earlier are deprecated by IETF and are generally to be
     * avoided if possible. We require a minimum TLS version of TLSv1.2.
     */
    if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) {
        printf("Failed to set the minimum TLS protocol version\n");
        goto end;
    }

    /* Create an SSL object to represent the TLS connection */
    ssl = SSL_new(ctx);
    if (ssl == NULL) {
        printf("Failed to create the SSL object\n");
        goto end;
    }

    /*
     * Create the underlying transport socket/BIO and associate it with the
     * connection.
     */
    bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET);
    if (bio == NULL) {
        printf("Failed to crete the BIO\n");
        goto end;
    }
    SSL_set_bio(ssl, bio, bio);

    /*
     * Tell the server during the handshake which hostname we are attempting
     * to connect to in case the server supports multiple hosts.
     */
    if (!SSL_set_tlsext_host_name(ssl, hostname)) {
        printf("Failed to set the SNI hostname\n");
        goto end;
    }

    /*
     * Ensure we check during certificate verification that the server has
     * supplied a certificate for the hostname that we were expecting.
     * Virtually all clients should do this unless you really know what you
     * are doing.
     */
    if (!SSL_set1_host(ssl, hostname)) {
        printf("Failed to set the certificate verification hostname");
        goto end;
    }

    /* Do the handshake with the server */
    if (SSL_connect(ssl) < 1) {
        printf("Failed to connect to the server\n");
        /*
         * If the failure is due to a verification error we can get more
         * information about it from SSL_get_verify_result().
         */
        if (SSL_get_verify_result(ssl) != X509_V_OK)
            printf("Verify error: %s\n",
                X509_verify_cert_error_string(SSL_get_verify_result(ssl)));
        goto end;
    }

    /* Write an HTTP GET request to the peer */
    if (!SSL_write_ex(ssl, request_start, strlen(request_start), &written)) {
        printf("Failed to write start of HTTP request\n");
        goto end;
    }
    if (!SSL_write_ex(ssl, hostname, strlen(hostname), &written)) {
        printf("Failed to write hostname in HTTP request\n");
        goto end;
    }
    if (!SSL_write_ex(ssl, request_end, strlen(request_end), &written)) {
        printf("Failed to write end of HTTP request\n");
        goto end;
    }

    /*
     * Get up to sizeof(buf) bytes of the response. We keep reading until the
     * server closes the connection.
     */
    while (SSL_read_ex(ssl, buf, sizeof(buf), &readbytes)) {
        /*
        * OpenSSL does not guarantee that the returned data is a string or
        * that it is NUL terminated so we use fwrite() to write the exact
        * number of bytes that we read. The data could be non-printable or
        * have NUL characters in the middle of it. For this simple example
        * we're going to print it to stdout anyway.
        */
        fwrite(buf, 1, readbytes, stdout);
    }
    /* In case the response didn't finish with a newline we add one now */
    printf("\n");

    /*
     * Check whether we finished the while loop above normally or as the
     * result of an error. The 0 argument to SSL_get_error() is the return
     * code we received from the SSL_read_ex() call. It must be 0 in order
     * to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN.
     */
    if (SSL_get_error(ssl, 0) != SSL_ERROR_ZERO_RETURN) {
        /*
         * Some error occurred other than a graceful close down by the
         * peer.
         */
        printf ("Failed reading remaining data\n");
        goto end;
    }

    /*
     * The peer already shutdown gracefully (we know this because of the
     * SSL_ERROR_ZERO_RETURN above). We should do the same back.
     */
    ret = SSL_shutdown(ssl);
    if (ret < 1) {
        /*
         * ret < 0 indicates an error. ret == 0 would be unexpected here
         * because that means "we've sent a close_notify and we're waiting
         * for one back". But we already know we got one from the peer
         * because of the SSL_ERROR_ZERO_RETURN above.
         */
        printf("Error shutting down\n");
        goto end;
    }

    /* Success! */
    res = EXIT_SUCCESS;
 end:
    /*
     * If something bad happened then we will dump the contents of the
     * OpenSSL error stack to stderr. There might be some useful diagnostic
     * information there.
     */
    if (res == EXIT_FAILURE)
        ERR_print_errors_fp(stderr);

    /*
     * Free the resources we allocated. We do not free the BIO object here
     * because ownership of it was immediately transferred to the SSL object
     * via SSL_set_bio(). The BIO will be freed when we free the SSL object.
     */
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    return res;
}

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1393232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【HTML】-- 01 初识HTML

HTML 1.初识HTML Hyper Text Markup Language&#xff1a;超文本标记语言 1.1 W3C标准 W3C World Wide Web Consortium(万维网联盟)成立于1994年&#xff0c;Web技术领域最权威和最具影响力的国际中立性技术标准机构http://www.w3.org/http://www.chinaw3c.org/ W3C标准包括…

虚幻UE 特效-Niagara特效实战-火焰、烛火

在上一篇笔记中&#xff1a;虚幻UE 特效-Niagara特效实战-烟雾、喷泉 我们进行了烟雾和喷泉的实战&#xff0c;而今天这篇笔记 我们在不使用模板的前提下对火焰和烛火特效进行实战 文章目录 一、火焰1、创建火焰的Niagara系统2、分析火焰是怎样的特征3、优化设置 二、烛火1、创…

windows编译TensorFlowServing

概述 整个编译打包过程的总体思路&#xff0c;是参照在linux下的编译流程&#xff0c;配置环境&#xff0c;执行编译命令&#xff0c;根据编译器/链接器反馈的错误&#xff0c;修改相应的源码或者相关库文件的存放路径&#xff0c;编译出windows平台下静态库和二进制执行文件。…

深入了解Transformer:先进语言模型背后的两个强大引擎

Transformer模型的出现对自然语言处理&#xff08;NLP&#xff09;领域来说堪称革命性。在Transformer崛起之前&#xff0c;循环神经网络&#xff08;RNNs&#xff09;是处理序列数据的标准。然而&#xff0c;Transformer的引入在各种NLP任务中大大超越了RNN的性能&#xff0c;…

RTMP对接腾讯云问题记录

RTMP对接腾讯云问题分析报告 问题现象及原因分析 1. 连不上腾讯云RTMP服务器 连不上腾讯云RTMP服务器&#xff0c;抓包显示服务器在握手完成后&#xff0c;主动断开了当前TCP链接。问题原因可能是connect中的tcUrl不能把域名转为IP&#xff0c;导致在握手不久服务器主动断开…

vue3前端开发,感受一下组合式api和VUE2选项式的差异

vue3前端开发,感受一下组合式api和VUE2选项式的差异&#xff01;今天开始&#xff0c;正式开始&#xff0c;进入学习Vue3的内容。以后代码&#xff0c;案例分享&#xff0c;都会采用组合式api的模式为大家做展示。 今天是第一节&#xff0c;带大家感受一下&#xff0c;Vue3的组…

【C++入门到精通】智能指针 auto_ptr、unique_ptr简介及C++模拟实现 [ C++入门 ]

阅读导航 引言一、std::auto_ptr1. 简介2. 使用示例3. C模拟实现 二、std::unique_ptr1. 简介2. 使用示例3. C模拟实现 温馨提示 引言 在 C 中&#xff0c;智能指针是一种非常重要的概念&#xff0c;它能够帮助我们自动管理动态分配的内存&#xff0c;避免出现内存泄漏等问题。…

axios的原理及源码解析

面试官&#xff1a;你了解axios的原理吗&#xff1f;有看过它的源码吗&#xff1f; 一、axios的使用 关于axios的基本使用&#xff0c;上篇文章已经有所涉及&#xff0c;这里再稍微回顾下&#xff1a; 发送请求 import axios from axios;axios(config) // 直接传入配置 axio…

Python实战 -- PySide6 制作天气查询软件

一、环境准备 开发环境&#xff1a;Python 3.9.2 pycharm PySide6 申请天气情况 API &#xff1a;https://console.amap.com/dev/key/app designer 设计 ui 目录下 Weather.ui 转换为 Weather.py 结果显示 二、完整代码 import sysfrom PySide6 import QtWidgetsimport…

安全牧场,保障优质奶源 追溯羊奶品质

安全牧场&#xff0c;保障优质奶源 追溯羊奶品质 近年来&#xff0c;人们对食品安全和健康越来越关注&#xff0c;而安全牧场的兴起正能够满足人们对优质奶源的需求。安全牧场以严格的品质监控和科学的管理&#xff0c;为消费者提供可追溯的高品质羊奶产品。本文小编羊大师将为…

机器学习算法理论:贝叶斯

贝叶斯定理对于机器学习来说是经典的概率模型之一&#xff0c;它基于先验信息和数据观测来得到目标变量的后验分布。具体来说&#xff0c;条件概率&#xff08;也称为后验概率&#xff09;描述的是事件A在另一个事件B已经发生的条件下的发生概率&#xff0c;公式表示为P(A|B)&a…

前端公共组件库优化

背景 前段时间入职了新公司后&#xff0c;做一些内部前端基建的工作&#xff0c;其中一个工作就是优化现有的frontend-common公共组件库。之前的组件库一直是以源码依赖的形式存在&#xff0c;即各个项目通过git submodule的方式将该仓库引入到各个项目中&#xff0c;作为一个…

Linux学习记录——사십삼 高级IO(4)--- Epoll型服务器(1)

文章目录 1、理解Epoll和对应接口2、简单实现 1、理解Epoll和对应接口 poll依然需要OS去遍历所有fd。一个进程去多个特定的文件中等待&#xff0c;只要有一个就绪&#xff0c;就使用select/poll系统调用&#xff0c;让操作系统把所有文件遍历一遍&#xff0c;哪些就绪就加上哪…

基于SURF算法的图像匹配

基础理论 2006年Herbert Bay提出了SURF算法&#xff0c;该算法是对SIFT算法的改进&#xff0c;不仅继承了SIFT算法的优点&#xff0c;而且比SIFT算法速度快。下面是SURF算法的步骤。 &#xff08;1&#xff09;建立积分图像 &#xff08;2&#xff09;构建尺度空间 &#x…

python使用Apache+mod_wsgi部署Flask

python使用Apachemod_wsgi部署Flask 一、安装python环境&#xff08;V3.10.10&#xff09;二、安装mod_wsgi三、安装Apache1、下载2、解压3、配置 四、安装项目依赖五、启动六、基于多端口部署多个flask项目 一、安装python环境&#xff08;V3.10.10&#xff09; 安装时勾选&q…

Elasticsearch:将数据从 Snowflake 摄取到 Elasticsearch

作者&#xff1a;来自 Elastic Ashish Tiwari 为了利用 Elasticsearch 提供的强大搜索功能&#xff0c;许多企业在 Elasticsearch 中保留可搜索数据的副本。 Elasticsearch 是一种经过验证的技术&#xff0c;适用于传统文本搜索以及用于语义搜索用例的向量搜索。 Elasticsearch…

C#,入门教程(38)——大型工程软件中类(class)修饰词partial的使用方法

上一篇&#xff1a; C#&#xff0c;入门教程(37)——优秀程序员的修炼之道https://blog.csdn.net/beijinghorn/article/details/125011644 一、大型&#xff08;工程应用&#xff09;软件倚重 partial 先说说大型&#xff08;工程应用&#xff09;软件对源代码的文件及函数“…

【白皮书下载】GPU计算在汽车中的应用

驾驶舱域控制器 (CDC) 是汽车 GPU 的传统应用领域。在这里&#xff0c;它可以驱动仪表板上的图形&#xff0c;与车辆保持高度响应和直观的用户界面&#xff0c;甚至为乘客提供游戏体验。随着车辆屏幕数量的增加和分辨率的提高&#xff0c;对汽车 GPU 在 CDC 中进行图形处理的需…

基础+常用的数据结构

基础 java基础 JDK 和 JRE JDK&#xff0c;它是功能齐全的 Java SDK&#xff0c;是提供给开发者使用&#xff0c;能够创建和编译 Java 程序的开发套件。它包含了 JRE,同时还包含了编译 java 源码的编译器 javac 以及一些其他工具比如 javadoc&#xff08;文档注释工具&#…

贪心算法-活动安排-最详细注释解析

贪心算法-活动安排-最详细注释解析 题目&#xff1a; 学校在最近几天有n个活动&#xff0c;这些活动都需要使用学校的大礼堂&#xff0c;在同一时间&#xff0c;礼堂只能被一个活动使用。由于有些活动时间上有冲突&#xff0c;学校办公室人员只好让一些活动放弃使用礼堂而使用…