文章目录
-
- openssl3.2 - linux脚本(.sh)调用openssl命令行参数的简单确认方法
- 概述
- 笔记
- 修改openssl实现的前置条件
- 修改debian12.4下编译好的openssl实现, 将入口参数记录下来
- 测试效果
- 备注
- 补充 - 将管道文件记录到本地文件
- 效果
- 备注
- 补充 - 要考虑到管道的读
- END
openssl3.2 - linux脚本(.sh)调用openssl命令行参数的简单确认方法
概述
在琢磨官方工程中的/test/certs中的2个脚本(setup.sh, mkcert.sh)
这2个脚本有不到500个openssl命令行调用, 应该是openssl内部测试证书操作的脚本.
确定这2个脚本是好东西(将证书操作一网打尽, 弄清了这2个脚本, 就没有不会的证书操作了).
但是脚本调用, 到了调用openssl时, 参数拼接很烦人, 我只想看具体到了openssl的可执行文件, 到底给了啥命令行参数.
有一些参数是用管道给的, 用stdin给的一个buffer代表一个参数文件, 这很烦啊.
官方给用户的正式例子, 都是用 in 参数, 然后给一个文件名. 这样多清爽.
.sh又不熟, 想将.sh改成可以传文件名给openssl的例子, 可能要花多一些时间.
一直在琢磨是否有更好的方法能确定最终的openssl命令行参数, 突然想到, 为啥不直接将openssl实现给改了, 在程序入口, 写几句日志, 将命令行参数记录下来, 这不一了百了啊. 研究啥.sh怎么写啊.
只要确定给了啥命令行参数, 那就好办了.
我已经编译好了在windows下可用的VS2019的openssl.exe的工程, 那就在自己工程中, 舒舒服服的调试好了(openssl3.2 - 自己构建openssl.exe的VS工程(在编译完的源码版本上), openssl3.2 - 在VS2019下源码调试openssl.exe).
笔记
修改openssl实现的前置条件
已经在debian12.4下, 配置, 编译, 测试, 安装都通过了.
且配置了debian12.4, 让本地普通目录中运行openssl命令行已经好使(openssl3.2 - 编译).
修改debian12.4下编译好的openssl实现, 将入口参数记录下来
参照我重建的win版openssl.exe工程, 可知 main()函数在openssl.c
去debian12.4下原版源码目录中确定是./apps/openssl.c
修改如下, 只在程序入口处, 加了一段日志文件的操作, 将openssl可执行文件的命令行参数附加到日志文件.
static char *help_argv[] = { "help", NULL }; static char *version_argv[] = { "version", NULL }; int main(int argc, char *argv[]) { FUNCTION f, *fp; LHASH_OF(FUNCTION) *prog = NULL; char *pname; const char *fname; ARGS arg; int global_help = 0; int global_version = 0; int ret = 0; int i = 0; FILE* pfLog = NULL; // 将入参全部写入文件待调试, 去看.sh太繁琐了 if (1) { pfLog = fopen("/home/lostspeed/openssl/my_openssl_log.txt", "a"); if (NULL != pfLog) { for (i = 0; i < argc; i++) { fwrite(argv[i], sizeof(char), strlen(argv[i]), pfLog); // 每个参数中间加一个空格 fwrite(" ", sizeof(char), 1, pfLog); } // 追加完一次openssl命令行调用, 换一行 fwrite(" ", sizeof(char), 2, pfLog); fclose(pfLog); pfLog = NULL; } } arg.argv = NULL; arg.size = 0;
在正常的工程中, 只进行make, make install
测试效果
在普通目录中运行了2个命令
openssl version -a openssl --help
查看自己指定的位置确实有日志文件.
lostspeed@debian12d4x64:~/openssl$ pwd /home/lostspeed/openssl lostspeed@debian12d4x64:~/openssl$ ls -l 总计 488136 -rw-r--r-- 1 lostspeed lostspeed 38 1月20日 22:29 my_openssl_log.txt drwxr-xr-x 26 lostspeed lostspeed 4096 1月20日 21:13 openssl-3.2.0_debian -rw-r--r-- 1 lostspeed lostspeed 482136966 1月20日 21:17 openssl-3.2.0_debian.tar.gz -rwxr-xr-x 1 root root 17698352 1月20日 13:55 openssl-3.2.0.tar.gz
查看此日志文件
lostspeed@debian12d4x64:~/openssl$ cat ./my_openssl_log.txt openssl version -a openssl --help lostspeed@debian12d4x64:~/openssl$
备注
这方法好使.
那我下一步就将setup.sh改成每次只执行一个命令的版本. e.g. setup1.sh, setup2.sh.
知道了具体的命令行操作, 那么就可以去win版的openssl.exe工程去查, 将stdin给出的参数文件流内容, 改为可以落地的参数和文件名.
那我也不用去改debian12.4下的那2个.sh脚本了, 调试强度一下子就降低好多.
补充 - 将管道文件记录到本地文件
脚本传递文件时, 到了openssl入口, 可以看到传进来的是一个管道文件名.
openssl req -new -sha256 -key root-key.pem -config /dev/fd/63
需要将这个管道文件也保存到日志中, 这样就知道了openssl命令行的所有参数, 就可以在windows下的openssl.exe的vs2019中开心的调试了.
将openssl.c又完善了一下, 对openssl.c的修改部分如下:
static char *help_argv[] = { "help", NULL }; static char *version_argv[] = { "version", NULL }; // /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt // D:\my_dev\my_local_git_prj\study\openSSL\test_certs\my_openssl_win_log.txt #ifdef _WIN32 #define MY_LOG_DIR "D:\my_dev\my_local_git_prj\study\openSSL\test_certs" #define MY_LOG_FILE "my_openssl_win_log.txt" #define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\" MY_LOG_FILE #define MY_PIPE_FILE "cmd_line_pipe_in_win.txt" #define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "\" MY_PIPE_FILE #else // -config /dev/fd/63 #define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs" #define MY_LOG_FILE "my_openssl_linux_log.txt" #define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE #define MY_PIPE_FILE "cmd_line_pipe_in_linux.txt" #define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "/" MY_PIPE_FILE #endif // #ifdef _WIN32 void read_file_write_to_another(const char* pszFileSrc, const char* pszFileDst) { FILE* fpSrc = NULL; FILE* fpDst = NULL; char szBuf[4096]; size_t nRdBk = 0; do { if ((NULL == pszFileSrc) || (NULL == pszFileDst)) { break; } fpSrc = fopen(pszFileSrc, "r"); if (NULL == fpSrc) { break; } fpDst = fopen(pszFileDst, "a"); if (NULL == fpDst) { break; } // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件 fwrite(" ", sizeof(char), 2, fpDst); fwrite(" ", sizeof(char), 2, fpDst); fwrite(" ", sizeof(char), 2, fpDst); do { nRdBk = fread(szBuf, sizeof(char), sizeof(szBuf), fpSrc); if (nRdBk <= 0) { break; } fwrite(szBuf, sizeof(char), nRdBk, fpDst); } while (1); } while (0); if (NULL != fpSrc) { fclose(fpSrc); fpSrc = NULL; } if (NULL != fpDst) { fclose(fpDst); fpDst = NULL; } } void wirte_cmd_line_param_to_log_file(int argc, char* argv[]) { int i = 0; FILE* pfLog = NULL; const char* psz_argv = NULL; // 将入参全部写入文件待调试, 去看.sh太繁琐了 if (1) { // 将程序的命令行参数记录进日志文件 pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a"); if (NULL != pfLog) { for (i = 0; i < argc; i++) { // 程序的名称都为"openssl" psz_argv = ((0 != i) ? argv[i] : "openssl"); fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog); // 每个参数中间加一个空格 fwrite(" ", sizeof(char), 1, pfLog); } // 追加完一次openssl命令行调用, 换一行 fwrite(" ", sizeof(char), 2, pfLog); fclose(pfLog); pfLog = NULL; } // 将管道文件记录进配置文件 for (i = 0; i < argc; i++) { // -config /dev/fd/63 if (0 == strcmp(argv[i], "-config")) { if ((i + 1) < argc) { if (0 == strcmp(argv[i + 1], "/dev/fd/63")) { read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME); } } break; } } } } int main(int argc, char *argv[]) { FUNCTION f, *fp; LHASH_OF(FUNCTION) *prog = NULL; char *pname; const char *fname; ARGS arg; int global_help = 0; int global_version = 0; int ret = 0; wirte_cmd_line_param_to_log_file(argc, argv); arg.argv = NULL; arg.size = 0;
修改后的openssl.c在windows下和debian12.4下是通用的. 编译安装后, 好使.
效果
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ pwd /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ ls -l 总计 104 -rwxr-xr-x 1 lostspeed lostspeed 11679 1月21日 14:05 mkcert.sh -rwxr-xr-x 1 lostspeed lostspeed 11679 1月21日 14:05 mkcert.sh.bk -rwxr-xr-x 1 lostspeed lostspeed 111 1月21日 14:05 my_lib.sh -rwxr-xr-x 1 lostspeed lostspeed 17315 1月21日 14:05 openssl.c -rwxr-xr-x 1 lostspeed lostspeed 1704 1月21日 14:05 root-key.pem -rwxr-xr-x 1 lostspeed lostspeed 388 1月21日 14:05 setup001.sh -rwxr-xr-x 1 lostspeed lostspeed 23948 1月21日 14:05 setup.sh -rwxr-xr-x 1 lostspeed lostspeed 23948 1月21日 14:05 setup.sh.bk lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ cat ./setup001.sh #! /bin/bash # file setup001.sh # printf "%s " "hello openssl" # my_lib.sh fn_to_file <(printf "hello 1") # ./my_lib.sh fn_to_file param1 param2 # fn_to_file() #{ # printf ">> fn_to_file " # # printf "%s " "$@" #} # printf ">> setup001.sh " # fn_to_file < <(printf "stdin to function ") # Primary root: root-cert ./mkcert.sh genroot "Root CA" root-key root-cert exit 0
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ ./setup001.sh
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ ls -l 总计 112 -rw-r--r-- 1 lostspeed lostspeed 87 1月21日 14:13 cmd_line_pipe_in_linux.txt // 记录管道输入给命令行的配置文件 -rwxr-xr-x 1 lostspeed lostspeed 11679 1月21日 14:05 mkcert.sh -rwxr-xr-x 1 lostspeed lostspeed 11679 1月21日 14:05 mkcert.sh.bk -rwxr-xr-x 1 lostspeed lostspeed 111 1月21日 14:05 my_lib.sh -rw-r--r-- 1 lostspeed lostspeed 64 1月21日 14:13 my_openssl_linux_log.txt // 记录命令行的日志文件 -rwxr-xr-x 1 lostspeed lostspeed 17315 1月21日 14:05 openssl.c -rwxr-xr-x 1 lostspeed lostspeed 1704 1月21日 14:05 root-key.pem // 干活后的输出文件 -rwxr-xr-x 1 lostspeed lostspeed 388 1月21日 14:05 setup001.sh -rwxr-xr-x 1 lostspeed lostspeed 23948 1月21日 14:05 setup.sh -rwxr-xr-x 1 lostspeed lostspeed 23948 1月21日 14:05 setup.sh.bk
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ cat ./my_openssl_linux_log.txt openssl req -new -sha256 -key root-key.pem -config /dev/fd/63
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ cat ./cmd_line_pipe_in_linux.txt string_mask=utf8only [req] prompt = no distinguished_name = dn [dn] CN = Root CA
备注
调试材料的准备:
将cmd_line_pipe_in_linux.txt中的原来管道传来的配置文件内容保存成一个配置文件. e.g. tmp.cfg
将my_openssl_linux_log.txt 记录的openssl命令行参数中的管道配置文件 /dev/fd/63 改为tmp.cfg
新的可以在本地单步调试的命令行为 : openssl req -new -sha256 -key root-key.pem -config tmp.cfg
这就可以正常单步调试了.
剩下的事情, 就是将官方原来的/test/certs/setup.sh中的不到500条证书操作命令, 全部整理成单条的脚本.
然后单独运行一条脚本, 得到一组openssl的命令行, 自己单步跟一下, 知道了openssl对命令行参数的要求就行了.
一天搞50个, 10天搞定:P
补充 - 要考虑到管道的读
管道读, 读一个字节, 管道里面少一个字节.
如果想将管道中的东西保存成文件供调试用, 那么程序用的管道数据就没有了.
想了一个解决方法, 我从管道读出的内容, 我是知道的. 将管道读出的内容保存成文件供调试.
然后再将自己读出的buffer, 再写入管道. 模拟自己没动过管道的数据
试了一下好使, 不影响openssl自带的功能.
#endif /* OPENSSL_NO_TRACE */ static char *help_argv[] = { "help", NULL }; static char *version_argv[] = { "version", NULL }; // /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt // D:\my_dev\my_local_git_prj\study\openSSL\test_certs\my_openssl_win_log.txt #ifdef _WIN32 #define MY_LOG_DIR "D:\my_dev\my_local_git_prj\study\openSSL\test_certs" #define MY_LOG_FILE "my_openssl_win_log.txt" #define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\" MY_LOG_FILE #define MY_PIPE_FILE "cmd_line_pipe_in_win.txt" #define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "\" MY_PIPE_FILE #else // -config /dev/fd/63 #define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs" #define MY_LOG_FILE "my_openssl_linux_log.txt" #define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE #define MY_PIPE_FILE "cmd_line_pipe_in_linux.txt" #define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "/" MY_PIPE_FILE #endif // #ifdef _WIN32 void read_file_write_to_another(const char* pszFileSrc, const char* pszFileDst) { #define MY_BUFFER_SIZE (1024 * 1024) FILE* fpSrc = NULL; FILE* fpDst = NULL; char* pSzBuf = NULL; // 开个1MB的空间, 从管道中读出来后, 保存进文件, 再写进管道, 这样相当于没有动管道 size_t nRdBk = 0; size_t nWrBk = 0; size_t nRdBkAll = 0; do { if ((NULL == pszFileSrc) || (NULL == pszFileDst)) { break; } pSzBuf = malloc(MY_BUFFER_SIZE); if (NULL == pSzBuf) { break; } fpSrc = fopen(pszFileSrc, "r"); if (NULL == fpSrc) { break; } fpDst = fopen(pszFileDst, "a"); if (NULL == fpDst) { break; } // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件 fwrite(" ", sizeof(char), 2, fpDst); fwrite(" ", sizeof(char), 2, fpDst); fwrite(" ", sizeof(char), 2, fpDst); nRdBkAll = 0; do { nRdBk = fread(pSzBuf + nRdBkAll, sizeof(char), 1024, fpSrc); if (nRdBk <= 0) { break; } nWrBk = fwrite(pSzBuf, sizeof(char), nRdBk, fpDst); if (nWrBk != nRdBk) { printf("error : write to fpDst => write to = %zu, return form write = %zu ", nRdBk, nWrBk); break; } nRdBkAll += nRdBk; } while (1); fclose(fpSrc); // 关掉源文件 // 管道读之后, 指针挪动了. 尝试将指针移动到管道开头 // fseek(fpSrc, 0, 0); // 不好使, 从管道中读了东西后, 管道中的东西就没有了 // 管道中的东西, 读出来后, 就消失了, 再模拟将读出来的东西, 写进入试试. 模拟我没动管道中的东西 fpSrc = fopen(pszFileSrc, "w"); if (NULL == fpSrc) { break; } nRdBk = fwrite(pSzBuf, sizeof(char), nRdBkAll, fpSrc); if (nRdBk != nRdBkAll) { printf("error : rewrite to pipe => nRdBkAll = %zu, nRdBk = %zu ", nRdBkAll, nRdBk); } } while (0); if (NULL != pSzBuf) { free(pSzBuf); pSzBuf = NULL; } if (NULL != fpSrc) { fclose(fpSrc); fpSrc = NULL; } if (NULL != fpDst) { fclose(fpDst); fpDst = NULL; } } void wirte_cmd_line_param_to_log_file(int argc, char* argv[]) { int i = 0; FILE* pfLog = NULL; const char* psz_argv = NULL; // 将入参全部写入文件待调试, 去看.sh太繁琐了 if (1) { // 将程序的命令行参数记录进日志文件 pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a"); if (NULL != pfLog) { for (i = 0; i < argc; i++) { // 程序的名称都为"openssl" psz_argv = ((0 != i) ? argv[i] : "openssl"); fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog); // 每个参数中间加一个空格 fwrite(" ", sizeof(char), 1, pfLog); } // 追加完一次openssl命令行调用, 换一行 fwrite(" ", sizeof(char), 2, pfLog); fclose(pfLog); pfLog = NULL; } // 将管道文件记录进配置文件 for (i = 0; i < argc; i++) { // -config /dev/fd/63 if (0 == strcmp(argv[i], "-config")) { if ((i + 1) < argc) { if (0 == strcmp(argv[i + 1], "/dev/fd/63")) { read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME); // 如果将管道指着移动到管道的头部还好使, 那就和未修改程序前相同 // 管道中的东西, 读出来就没有了, 不过, 我已经又将读出来的东西, 又写回去了 // read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME); } } break; } } } } int main(int argc, char *argv[]) { FUNCTION f, *fp; LHASH_OF(FUNCTION) *prog = NULL; char *pname; const char *fname; ARGS arg; int global_help = 0; int global_version = 0; int ret = 0; // 打印自己的版本号标记 if ((2 == argc) && (0 == strcmp("-v", argv[1]))) { printf("ls modify openSSL3.2.0_build_002 last build 2024/1/21 17:27:00 "); } wirte_cmd_line_param_to_log_file(argc, argv); arg.argv = NULL; arg.size = 0; /* Set up some of the environment. */ bio_in = dup_bio_in(FORMAT_TEXT); bio_out = dup_bio_out(FORMAT_TEXT); bio_err = dup_bio_err(FORMAT_TEXT);