Windows10 64位编译OpenSSL

作者 Hstb 日期 2019-07-26
Windows10 64位编译OpenSSL

说明


本文仅记录编译OpenSSL的过程和一些心得, 并非按顺序一一列举操作的教程文. 因此, 显得啰嗦是正常的.

本文使用的系统环境为Windows10家庭版64位, Intel芯片, 用于指导Windows10其他版本的编译应该没有问题, Windows7用户应该也可以, 应该只有在配置环境变量那步有所区别.

前言


因为Python的requests库在使用HTTPS代理时会出现警告, 需要导入证书才能从根本上解决这个问题.
但Fiddler和BurpSuite的证书又是cer文件, 需要转换成pem才能给requests使用, 所以需要借助OpenSSL库进行转换, 只是没有找到可用的现成程序, 所以选择编译一份.

等一下, 其实并不是没有现成的程序, 比如我的Windows就带了, 但是运行会出现错误, 提示无配置文件:

最开始以为是WPS的库, 但也能用CMD运行, 可报错中提到的Linux版文件路径又是什么鬼.

出于麻烦, 我还是选择重新编译一份.

准备工作


下载

个人习惯先去项目官网看看Download中有没有源代码or安装包, 当然, 有安装包是最好的(大部分情况下).

看上去没有安装包, 只有源代码, 而源代码也有很多版本分支的样子:

因为有点英文盲, 所以其他内容都没看, 只在像版本列表的地方下了openssl-1.0.2s.tar.gz

关于下载这件事 — 大概只适用于那些看上去很古老的下载页吧~
一般只要下载.tar.gz这类文件就行了, 括号里的文件是用来验证.tar.gz文件是否被篡改等, 不过在有https加持的情况下, 一般不需要关注这个, 至于用于验证发布者的PGP签名, 也是一样的道理.

此后, 看了下说明文档以及网上的一堆教程后, 试着编译了几次, 也算是踩了点坑后才来写这篇文章.

后面仔细阅读了下载页的英文说明:

The latest stable version is the 1.1.1 series. This is also our Long Term Support (LTS) version, supported until 11th September 2023. Our previous LTS version (1.0.2 series) will continue to be supported until 31st December 2019 (security fixes only during the last year of support). The 1.1.0 series is currently only receiving security fixes and will go out of support on 11th September 2019. All users of 1.0.2 and 1.1.0 are encouraged to upgrade to 1.1.1 as soon as possible. The 0.9.8, 1.0.0 and 1.0.1 versions are now out of support and should not be used.

简而言之, 就是官方还会更新三四年的1.1.1x版本(简称技术支持), 而1.0.2x版本过完今年后(写文时是2019年)就不再更新, 所以不要再用旧版本.

所以改成下载第三个(版本号: 1.1.1c), 打开压缩包会看到以下内容:

  • openssl-1.1.1c – 源代码文件夹, 将其解压到任意目录下,
    但不建议所在目录的绝对路径中含有任何中文(常识), 否则可能出现一些奇奇怪怪的问题.
  • pax_global_header – 该文件不需要处理, 看了下内容, 盲猜误打包, 但确实用不上.

我是将源代码解压至当前账户的文档目录(C:\Users\用户名\Documents\), 解压后的完整路径是C:\Users\i\Documents\Scripts\openssl-1.1.1c\

配置环境


打开源代码目录, 查看README文件:

INSTALLATIONREADME
1
2
3
See the appropriate file ---- 查看相应的文件: 
INSTALL Linux, Unix, Windows, OpenVMS, ...
NOTES.* INSTALL addendums for different platforms ---- 不同平台的安装附录

也就是说, 我们要阅读「INSTALL」和「NOTES.WIN」这两个文件. 文件里给出了多种编译方式, 但都需要用到Perl, 所以先去下载该程序(可能需要注册账户), 我下的是5.28版本.

安装类型随意, 硬件资源优秀的可以选Complete, 这里用Typical足够.

猜测perl是负责生成编译参数的, 而真正负责编译的是nmake, 当然官方也给了mingwCygwin的编译步骤, 这边只讨论nmake的使用.

以鄙人目前所了解到的, vs(不是vs code)有提供nmake(在附加工具里), 电脑上刚好装了2017个人版, 就拿来用了. 这里使用的是VS 2017的开发人员命令提示符

键盘按住Win + R, 运行以下代码大概也能打开

1
%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\VsDevCmd.bat"

装了其他版本(如201[0359])的同学, 请自行修改路径或使用开始菜单打开.

初次编译


根据INSTALL文件的说明, 在Windows下编译需要执行以下命令:

On WindowsINSTALL
1
2
3
4
perl Configure { VC-WIN32 | VC-WIN64A | VC-WIN64I | VC-CE }
nmake
nmake test
nmake install

还有一些编译选项, 但篇幅过长, 这边不一一贴出了.

除非需要某些特性, 否则可以不带任何编译选项.

打开该工具后, 切换运行目录到源代码目录下(C:\Users\i\Documents\Scripts\openssl-1.1.1c\)

运行

1
perl Configure VC-WIN64A no-asm --prefix="C:\Users\i\Documents\Scripts\openssl"

相关解释

  • Configure — 实际上是源代码目录下的一个文件
  • VC-WIN64A — 大部分64位Windows只需要用到该参数, 32位的直接用VC-WIN32就好.
    后面突然觉得, 「会不会A是AMD,I是Intel」, 差点就要改成VC-WIN64I.
  • no-asm — 不使用汇编优化, 否则命令执行出错, 提示要安装NASM
  • --prefix= — 指定编译文件后存放的目录
  • C:\Users\i\Documents\Scripts\openssl — 目标路径, 前后加引号是为了防止路径中存在空格等特殊字符, 导致程序解析错参数

出现警告


执行命令后出现了类似警告的文本(白底红字)

大概意思是没有配置nmake或者dmake的环境变量, 之前编译1.0.2s的时候也有出现, 不过不配置是可以编译成功的, 所以觉得这边做不做都不影响, 如有严重强迫症的同学可以参考这篇文章操作(未验证)

接下来执行nmake的时候也验证了我的想法, 确实可以正常工作,

编译错误


只是到最后会爆出错误, 导致编译终止:

1
2
3
4
5
6
ml64  /c /Cp /Cx /nologo /Zi /Focrypto\uplink-x86_64.obj "crypto\uplink-x86_64.asm"
'ml64' 不是内部或外部命令,也不是可运行的程序或批处理文件。
NMAKE : fatal error U1077: “ml64”: 返回代码“0x1”
Stop.
NMAKE : fatal error U1077: “"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\bin\HostX86\x86\nmake.exe"”: 返回代码“0x2”
Stop.

然后百度查了下, 其实是有ml64.exe这个文件, 就在nmake.exe那个目录里, 只是因为没有配置环境变量, cmd又切换到openssl源代码目录下运行, 所以更找不到这个文件.

但仔细想想, 其实这不就是微软自己下的坑吗? 毕竟打开的是你家的工具, 却没把自带的附加工具变成全局可用, 真是迷惑行为. 不过想归想, 问题还是要解决的.

解决环境问题


大部分的做法

大部分旧文章是这样做的: 把ml64.exe复制到openssl源代码目录下, 不过我嫌可能存在其他隐患问题就没有做.

添加环境变量

而前面出现的警告文本也让我想到: 如果在环境变量的PATH里添加nmake程序所在的目录, 是不是也可以解决?
于是打开VS安装目录, 搜索nmake, 发现有两个同名exe, 仔细看了下, 分别在x86x64目录里, 搜了下ml64也是一样结果,

然后引发我强迫症的事情就出现了: 到底是添加x86还是x64到环境变量?
出于懒癌, 我也放弃了这个想法, 而且未添加环境变量的情况下, vs工具优先调用的竟然是x86版的nmake, 而用x86工具编译x64程序, 先不管会不会有问题, 反正对于这操作我是无力吐槽的.

其实还有一点也让我很迷惑, 就是为什么vs会安装在x86程序目录里(指Program Files (x86)), 不过已经忘记安装VS过程的我还是不追究这个问题了.

(至于为什么不启用索引, 是因为开启后, 会有个Windows服务时不时地NTR你的硬盘. 如果设置不当, 不仅生成文件树, 还会打开文件扫一扫, 简直就是噩梦)

安装dmake模块

除了添加环境变量以外, 警告还提示可以在Perl中执行ppm install dmake安装dmake模块,

然而这个命令并不能在cmd执行, 提示'ppm' 不是内部或外部命令,也不是可运行的程序或批处理文件。,
好吧, 其实这很正常, 警告还说了要在Perl的模块管理程序中执行.

但整了好一会也没能找到模块管理这个程序.

那好吧, 我去perl里面执行看看, 结果也没找到能运行Perl命令的程序(类似WPS - Windows Power Shell), 翻了下开始菜单的最近添加, 也只看到Perl Critic, 打开看了下, 画风是这样的:

你觉得这是命令行页面? 我怎么觉得更像MinGW的插件管理窗口?

然后就想到, 是不是没配环境变量?

但在安装时已经勾选配置环境变量, 而且执行perl -v也有输出, 总不能要重启才正常运行吧?
如果是, 那输perl之后应该更是「程序不存在」之类的错误, 最后我也重启了, 依旧是老样子.

然后去Perl的bin目录看了下, 根本没有pip这个文件, 对不起, 我出戏了, 不知道怎么的就写到python去了, 但确实也没有ppm, 看样子八九凉了.

然后我就想,在命令行下运行某些程序, 不带参数的话好像会进入一个单独的页面(比如mysql,python,openssl), 那我也试下perl

确实有反应, 但我换行输了好几个命令都没反应, 反倒跟我以前写的c语言的控制台程序一样, 把用户输入的内容原样输出.

C语言代码:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <conio.h>
int main() {
char c;
while(true) {
c = getch();
putchar(c);
}
return 0;
}

效果图:

当然实际情况下, 用户输入肯定不止这些, 比如回车、删除亦或是或者输入中文等等, 这里就只是调侃下.

百度查了下Perl执行单个语句的方法

1
2
$ perl -e 'ppm -h'
[无输出]

又百度了下Perl安装模块的方法, 好吧, 没有Windows的, 教程实在太少了, 没辙.

虽然谷歌或者英文文档应该有,但我不想接着折腾了=-=

那么还有什么办法整呢?

切换执行目录

我先想到的是, 既然是提示ml64.exe不存在, 那我切换到它所在的目录下去执行应该是可以的.

而前面说过, “Configure实际上是源代码目录下的一个文件”, 所以可以把它指定成完整路径.

首先映入眼帘的是权限不足, win10的蛋疼设定真坑人, 不过问题不大, 使用管理员模式运行.

不过随之想到一件事, 是不是因为在VS目录下做了什么文件操作, 所以才会权限不足?

检查了下VS目录, 果然, 文件列表里多出了configdata.pmmakefile, 这操作真是令人忧愁.

看样子编译过程是准备发生在这个目录了, 那先删了这两个破文件, 然后再看看INSTALL.

先试试--libdir=, 为了安全起见, 这次还是用无管理员权限的CMD窗口接着运行.

还是权限错误, 改用--openssldir=依旧不行, 看样子是没戏了.

萌新: “那不是有个--with-zlib-include=, 可能可以?”
Me: “大锅啊, 你也得搞清楚, 这个zlib, 是个库, 你觉得行?”

那似乎真的没戏了, 但, 我突然又有了个骚操作,

如果在Perl前加上openssl的目录去执行会怎样?

好吧, 我还是太能飞了, 系统跟不上.

那能不能像java那样指定代码路径呢?

先看看Perl有啥选项好了, -h来一波, 把允许带参数的选项都试过去了, 均不行, 佛了.

难道只能原路返回?

切换编译工具

刚刚看了下开始菜单, 发现VS还有好几个工具, 打开「适用于VS 2017的x64本机工具命令提示」, 发现换到openssl目录后ml64还能用, 就决定再试一试.

二次编译


执行第一步的代码

啥, 你说这次的命令好像和之前的有些不一样? 这是因为写文期间以不同的操作反复编译了N多次.

当然, 肯定是要解释一下的:

  • 为什么执行mkdir

首先, mkdir是cmd中创建目录的命令, 如果不熟悉的话, 请自行补充下相关知识.

那么, 为什么要创建目录?
因为前面也说过了, (以本人目前掌握的知识水平来看), perl只会在当前的执行目录下生成编译文件, 即configdata.pmmakefile, 还有尝试编译期间生成的一堆中间文件, 总之, 这会把源代码目录搞得一团糟, 如果中间操作出现失误, 也会影响二次编译.
当然, 为了不跑偏, 我选择在源代码目录下新建一build目录, 用于存放编译时创建的临时文件.
所以最终执行命令的目录是C:\Users\i\Documents\Scripts\openssl-1.1.1c\build\

  • 为什么把Configure改成..\Configure

在前面执行路径还是C:\Users\i\Documents\Scripts\openssl-1.1.1c\的时候就已经说过了, Configure只是当前目录下的一个文件, 所以不论是写相对路径, 还是绝对路径都是可以的. 这句话其实太过绝对, 主要还是程序(这里指perl)会转换成完整路径去执行.

所以为了省点字数, 我就用相对路径了, 但还是建议用绝对路径, 前后带引号的那种.

  • 为啥报错

因为Configure这个编译脚本中要求的参数--prefix=(安装目录,即编译输出位置)必须是绝对路径, 所以, 这里就老老实实地用前后带引号的路径吧.

修改后接着重新编译, 运行成功, 还是有警告输出, 不过还是可以不管, 毕竟nmakeml64都可以用了不是?

然后, 让我们来看看build这个目录下有啥.

突然想起之前还在VS目录中运行过, 看了下也多了这些东西, 赶紧带权删一波.

然后准备执行nmake编译(算了, 这个明天再写, 垃圾电脑要花很长时间)

编译与测试

于是过了两天后, 咸鱼的我终于接着开工了, 虽然还是晚上才操作.

执行nmake后, cmd大概输出20分钟后才停止, 中间只有出现如warning C4267: “=”: 从“size_t”转换到“int”,可能丢失数据之类的警告, 猜测是因为用x64工具编译造成的( 补充: 其实并不是, 应该是OpenSSL的开发者们没有做强制类型转换, 比如在变量前加(int) ), 不过似乎不影响后续步骤.

本来是有录制该过程的gif, 但文件过大(稍微压缩后也有70M), 而且没有太大参考意义, 所以就不附图了.

接着执行nmake test, 猜测该命令是用于测试编译的中间文件是否正常.

这里有所删减, 实际大概花了8分钟(主要还是电脑垃圾).

中间出现skipped之类的关键词都不用慌, 只是因为生成编译文件时没有附加一些选项而已, 只要最后的ResultPASS就成.

安装编译文件

然后执行nmake install,

这里的话, 其实会不出意外的抛出错误, (太困了, 明天再继续)

最根本的错误是Cannot create directory C:/Program Files/Common Files/SSL: No such file or directory.

这个其实和前面在VS目录中执行编译脚本的错误是同一个原因, 就是没有管理员权限, 无法写入受系统保护的目录.

解决办法有两个,

  1. 「以管理员身份」运行该工具;
  2. 在编译命令中使用--openssldir=修改OpenSSL配置文件存放目录.

我选择的是后者.

然后又要执行命令重新生成一次编译脚本, 再重新编译了.

不过其实也不用这样折腾, 可以先执行生成编译脚本命令, 再执行安装命令, 即

1
2
$ perl ..\Configure VC-WIN64A no-asm --prefix="C:\Users\i\Documents\Scripts\openssl" --openssldir="C:\Users\i\Documents\Scripts\openssl\config"
$ nmake install

如果觉得不保险的话, 也可以选择重新编译一次, 不过要记得先清空nmake缓存

1
2
3
4
5
$ nmake clean
$ perl ..\Configure VC-WIN64A no-asm --prefix="C:\Users\i\Documents\Scripts\openssl" --openssldir="C:\Users\i\Documents\Scripts\openssl\config"
$ nmake
$ nmake test
$ nmake install

前面测试了下, --openssldir=的值改成config也是可以的, 等于在openssl的生成目录下创建该文件夹.

配置环境变量


常规情况

从目前测试来看, 只需要两处变更:

  1. 新建一环境变量: OPENSSL, 值为C:\Users\i\Documents\Scripts\openssl\bin\openssl.exe;
  2. 修改环境变量PATH, 增加新值: C:\Users\i\Documents\Scripts\openssl\bin.

重新打开cmd窗口, 执行openssl version,
如果输出OpenSSL 1.1.1c [Day] [Month] [Year], 就说明配置成功.

特殊情况

这里并不探讨xx不是内部或外部命令,也不是······的情况, 而是说输出了其他版本信息:

最有可能是你装了其他程序, 而该程序目录中刚好有openssl.exe( 比如OpenVPN ), 而安装程序时又( 主动 / 被动的 )添加了程序目录到PATH中, 这点也是前面配置完环境变量时才发现的( 原来不是WPS自带的啊 ).

遇到这种情况不用慌, 也不用删掉另一个程序的目录, 只需要试着调高你添加的那个值的优先级即可,

  • win8/10可以点击上移/下移调整,
  • win7的同学大概只能把整个值带着;放前一点或者到值最前方了.

测试


测试的方法有很多, 可以用openssl生成证书, 我是测试从cerpem, 也就是从写文的最初目的开始, 这边就不详细说明了, 有兴趣的可以去TIPS阅读另一篇文章(还没写好, 后面再补).

后记

快写完这篇文章的时候, 我终于在百度上看到OPENSSL安装包了(大吐血), 亏我之前搜了那么多内容, 垃圾百度.

不过当初在谷歌上好像有看到, 但是点开后没滑下去(因为是英文网站), 所以与安装列表相失交臂.

放下网址, 有兴趣的同学去试一试吧, 可以参考另一个博主写的文章, 应该没我这么麻烦.

你以为这就结束了?

NO NO NO

完善编译流程


安装NASM

在编译命令那边说过, 用no-asm是不使用汇编优化, 否则要安装NASM,

而我接下来, 就是要安装NASM后重新操作(滑稽).

首先, 到该项目官网下载安装包,

目前官网是下面那样, 估计没那么快变更网站样式, 如果有改的话, 就自己看着办吧.

下载Stable就可以了, 点击版本号进入**实际的下载页

这里根据系统类型选择即可, 进入win64文件夹后才会看到exe安装包.

两个都是安装包文件, 选择其中一个下载即可. 下载zip文件的话需要解压文件.

出于下载最小的文件会快一点的想法(因为我国出口宽带紧缺), 我下载了zip, 然后发现不是我想的那回事.

用最熟悉的说法, 就是绿色免安装版.

将文件夹解压后, 在环境变量里添加程序根目录, 如果不放心的话可以再把rdoff文件夹添加到环境变量.

然后重新打开cmd, 输入nasm -v, 有输出版本号的话就代表配置成功.

重新编译

然后再打开「适用于VS 2017的x64本机工具命令提示」, 切换执行路径到原来的build文件夹下.

然后执行nmake clean, 清除原来的编译文件. 如果不放心的话, 可以删除并重新创建一个build文件夹.

另外也要删除原来的openssl文件夹, 避免编译冲突, 也可以重命名.

然后执行命令(不用带no-asm), 如果没有报错的话, 说明NASM已经可用.

如果像这样报错的话, 说明环境变量没配好.

然后依次执行nmakenmake testnmake install, 使用汇编优化的OpenSSL就编译好了.

程序比较

用汇编优化编译出来的程序好像偏大一些, 运行速度就不知道怎样了, 据说会好一点吧.

这里没有后记, 目前算是把这篇文章写完了吧(其实已经8月6号了).

补几个加速的资源包?