针对标题上的问题的解决办法可以直接翻到最后, 下面的内容是一些过程记录, 可以跳过。
因为新型肺炎的原因, 这几天都窝在家里, 闲来无事想重新编译一下CEF2623版本的源码, 这个是最后一版支持XP系统的CEF内核版本(因为各种原因, 所以还需要兼容XP) , 其实在2018年就编译过一次, 当时也是根据百度到的一篇博客来按部就班的编译, 不过当时用的是VS2015, 后来又一次看到说2623这个版本用VS2015编译不稳定, XP下可能会崩溃, 所以这次就再用VS2013 u4试试。 我主要参考了这篇文章 https://www.twblogs.net/a/5b84bc232b71775d1cd19f8d/zh-cn
我再编译过程中主要遇到了几个问题, 做了一下记录如下:
1) 下载源码这个阶段经常失败, 要么是冲突的要么是依赖不存在的, 我用的机场速度比较快, 好几个服务器能达到5-10M/S的稳定高速, 但是还是失败,因为源码下载的数据量比较大, 接近20G, 我以为是下载数据多了之后梯子可能自动给踢下线或者并不稳定了, 所以我该用阿里云来测试, 直接在阿里云香港服务器上下载源码, 速度非常happy, 稳定10M以上的速度, 但是下了两次还是出现一样的错误, 所以我怀疑不是我梯子的问题, 而是2623这个版本太老了, 下载脚本可能不兼容老版本了, 不能再按原来的步骤下载了, 研究gclient这一套依赖相关的机制也必将麻烦, 我因为2018年编译过一次, 所以也不愿意过多的去折腾, 就干脆拿以前下载的代码来编译了, 另外我发现百度云盘上也有资源, 地址为:https://yun.baidu.com/s/1o8dOvDg 遇到问题的朋友可以考虑用这个下载, 下载速度你懂的, 我挂着让他下载, 不过当天晚上速度莫名爆发, 所以没有等到第二天。
2) 编译错误因为已经处理过了所以这次编译比较顺利, 但是编译完之后遇到了一个奇怪的问题,打开google首页时 提示错误如下:
Page failed to load.
URL: https://www.google.com/?gws_rd=ssl
Error: UNKNOWN (-150)
X.509 Certificate Information:
截图如下:
另外这个问题只有google有youtube出现, 百度和QQ等其他同样是https的网页确没有报错, 应该有一些区别在里面。
当时是很奇怪, 我编译用的代码和18年那次是同一份代码, 为什么当时编译出来的版本打开google首页是正常的, 现在就不行了呢? 我网上搜到过资料使用--ignore-certificate-errors这个参数可以让屏蔽这个错误, 但是这不能解释为什么18年编译的版本是正常的。 我还仔细用编译目录的源码和18年源码备份原始目录做了比较, 确定在编译过程中并没有打上新的补丁引入了什么心的变化。 这就有点奇幻了, 我实在猜不出来是什么原因, 没办法, 那就去看源码了, 根据错误提示的文本搜到了这个提示报错的入口, 在proof_verifier_chromium.cc的第310行, 有调用transport_security_state_->CheckPublicKeyPins失败后对错误码赋值 result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN(-150).
if (transport_security_state_ &&
(result == OK ||
(IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
!transport_security_state_->CheckPublicKeyPins(
HostPortPair(hostname_, 0),
cert_verify_result.is_issued_by_known_root,
cert_verify_result.public_key_hashes, cert_.get(),
cert_verify_result.verified_cert.get(),
TransportSecurityState::ENABLE_PIN_REPORTS,
&verify_details_->pinning_failure_log)) {
result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
}
而CheckPublicKeyPins函数会经过HasPublicKeyPins判断, 并调用GetStaticDomainState函数, 该函数里面有一个IsBuildTimely的判断, 如下:
bool TransportSecurityState::GetStaticDomainState(const std::string& host,
STSState* sts_state,
PKPState* pkp_state) const {
DCHECK(CalledOnValidThread());
sts_state->upgrade_mode = STSState::MODE_FORCE_HTTPS;
sts_state->include_subdomains = false;
pkp_state->include_subdomains = false;
if (!IsBuildTimely())
return false;
...//略
}
// static
bool TransportSecurityState::IsBuildTimely() {
// If the build metadata aren't embedded in the binary then we can't use the
// build time to determine if the build is timely, return true by default. If
// we're building an official build then keep using the build time, even if
// it's invalid it'd be a date in the past and this function will return
// false.
#if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
return true;
#else
const base::Time build_time = base::GetBuildTime();
// We consider built-in information to be timely for 10 weeks.
return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
#endif
}
跟到了这里, 我就恍然大悟了, 这个证书检验其实是会判断当前编译版本是不是已经比较老了, 如果距离编译时间已经过去70天, 那么本地的这一次校验就直接忽略了, 这就能解释为什么2018年的版本没有这个问题, 因为现在已经过去两年了, 早就超过70天了。 所以两个版本的关键区别就是IsBuildTimely判断返回是不同的。 不过2018年当初有没有遇到这个问题我没有留意。现在已经不记得了。
现在谜团解开了, 解决办法也就好办了, 一个是干脆不解决, 这个问题对我的使用场景是没有影响的, 而且70天之后,这个问题也会自动消失, 还有一个办法是修改本地时间后 删除out目录重新编译,把时间改到70天之前, 伪装一下编译时间。 当然直接修改源码让IsBuildTimely固定返回false也行, 知道了原因, 解决办法总是很多的。