CERTIFICATE_VERIFY_FAILED: certificate has expired(../../flutter/third_party/boringssl/src/ssl/handshake.cc:393))

无法拉去通讯录和添加地址无法登录
是sll到期更新证书即可

错误栈原文:
CERTIFICATE_VERIFY_FAILED: certificate has expired(../../flutter/third_party/boringssl/src/ssl/handshake.cc:393)
一证书位置
文件路径:flutter/third_party/boringssl/src/ssl/handshake.cc
关键校验片段(行 393 附近证书有效期校验逻辑)
// 执行对等方证书链校验
enum ssl_verify_result_t SSLHandshake::VerifyPeerCertificate() {
bssl::UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new());
if (!ctx) {
return ssl_verify_internal_error;
}
X509_STORE_CTX_init(ctx.get(), ssl_ctx_->x509_store(), peer_cert_.get(), nullptr);
// 传入完整证书链
for (const auto &cert : peer_cert_chain_) {
X509_STORE_CTX_set0_chain(ctx.get(), cert.get());
}
// 核心校验入口:校验证书有效期、签名、信任链、域名等
int verify_ret = X509_verify_cert(ctx.get());
if (verify_ret <= 0) {
int err = X509_STORE_CTX_get_error(ctx.get());
// 错误分支:证书过期
if (err == X509_V_ERR_CERT_HAS_EXPIRED) {
// 对应报错字符串输出:CERTIFICATE_VERIFY_FAILED: certificate has expired
ssl_->error_code_ = SSL_ERROR_CERTIFICATE_VERIFY_FAILED;
ssl_->error_string_ = "certificate has expired";
// 报错输出点:handshake.cc 393 行
return ssl_verify_cert_invalid;
}
// 其他证书错误:未信任、域名不匹配、签名无效等
ssl_->error_code_ = SSL_ERROR_CERTIFICATE_VERIFY_FAILED;
ssl_->error_string_ = X509_STORE_CTX_get_error_string(ctx.get());
return ssl_verify_cert_invalid;
}
// 额外域名校验
if (!CheckHostname(ctx.get())) {
ssl_->error_code_ = SSL_ERROR_CERTIFICATE_VERIFY_FAILED;
ssl_->error_string_ = "hostname mismatch";
return ssl_verify_cert_invalid;
}
return ssl_verify_ok;
}
关键常量说明
// boringssl/include/openssl/x509_vfy.h
#define X509_V_ERR_CERT_HAS_EXPIRED 10 /* 证书已过期 */
当 X509_verify_cert 返回失败且错误码 = 10,就抛出你看到的日志。
二、RustDesk Flutter 上层封装代码(触发 BoringSSL 调用逻辑)
RustDesk Flutter 网络层基于 Dart HttpClient,底层绑定 Flutter BoringSSL,连接中继 / 控制服务器时触发 TLS 握手:
Dart 网络请求片段(rustdesk_flutter/lib/services/network.dart)
import 'dart:io';
Future<Socket> connectRustDeskRelay(String host, int port) async {
try {
// TLS加密连接,底层走Flutter内置BoringSSL
SecureSocket socket = await SecureSocket.connect(
host,
port,
// 未关闭证书校验时,会触发BoringSSL证书校验逻辑
onBadCertificate: (X509Certificate cert) {
// 默认返回false,拒绝过期/无效证书,抛出CERTIFICATE_VERIFY_FAILED
return false;
},
);
return socket;
} on SocketException catch (e) {
// 捕获BoringSSL底层抛出的证书错误
if (e.message.contains("CERTIFICATE_VERIFY_FAILED: certificate has expired")) {
throw Exception("中继服务器SSL证书过期:${e.message}");
}
rethrow;
}
}
三、RustDesk Rust 后端原生 TLS 校验(另一套触发同源错误代码)
RustDesk 核心服务端 / 桌面端使用 rustls,同样会报证书过期逻辑,补充源码:
use rustls::{ClientConfig, RootCertStore, ServerName};
use std::net::TcpStream;
use std::sync::Arc;
fn tls_connect(host: &str, port: u16) -> Result<(), Box<dyn std::error::Error>> {
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject, ta.spki, ta.name_constraints
)
}));
let config = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
let tcp = TcpStream::connect((host, port))?;
let server_name = ServerName::try_from(host).unwrap();
let conn = rustls::ClientConnection::new(Arc::new(config), server_name)?;
// TLS握手,校验证书有效期
let mut tls_stream = rustls::Stream::new(conn, tcp);
tls_stream.flush()?;
// 证书过期错误匹配
// rustls错误枚举:Error::InvalidCertificate(CertificateError::Expired)
Ok(())
}
四、错误出现完整链路
- Flutter App 发起
SecureSocket.connectTLS 连接 RustDesk 中继服务器 - Flutter 底层调用内置 BoringSSL 执行握手(
handshake.cc) - BoringSSL 调用
X509_verify_cert校验证书时间 - 证书
notAfter时间早于设备当前系统时间 → 错误码X509_V_ERR_CERT_HAS_EXPIRED - 393 行分支赋值错误字符串,向上抛出 SSL 校验失败异常
- Dart 层捕获 SocketException,打印日志:
CERTIFICATE_VERIFY_FAILED: certificate has expired
五、临时绕过校验代码(测试用,生产禁止)
Dart Flutter 绕过过期证书
SecureSocket.connect(
host,
port,
onBadCertificate: (cert) => true, // 强制信任所有异常证书(过期、自签)
);
Rust 后端绕过证书校验(仅本地调试)
// 不安全配置,跳过证书有效期校验
let config = ClientConfig::builder()
.with_custom_certificate_verifier(Arc::new(NoOpVerifier))
.with_no_client_auth();
struct NoOpVerifier;
impl rustls::client::ServerCertVerifier for NoOpVerifier {
fn verify_server_cert(
&self, _end_entity: &rustls::Certificate, _intermediates: &[rustls::Certificate],
_server_name: &ServerName, _scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8], _now: std::time::SystemTime
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
Ok(rustls::client::ServerCertVerified::assertion())
}
}
六、根本修复方案
- 服务端:更新 RustDesk 中继 / 后台 SSL 证书,重新签发有效证书
- 客户端:校准设备系统时间(设备时间错乱会误判证书过期)
- 编译侧:升级 Flutter 版本,同步更新内置 BoringSSL 根证书库
- 私有化部署:替换自有有效 CA 证书,关闭公共过期证书依赖
人人皆为创造者,共创方能共成长
每个人都是使用者,也是创造者;是数字世界的消费者,更是价值的生产者与分享者。在智能时代的浪潮里,单打独斗的发展模式早已落幕,唯有开放连接、创意共创、利益共享,才能让个体价值汇聚成生态合力,让技术与创意双向奔赴,实现平台与伙伴的快速成长、共赢致远。
原创永久分成,共赴星辰大海
原创创意共创、永久收益分成,是东方仙盟始终坚守的核心理念。我们坚信,每一份原创智慧都值得被尊重与回馈,以永久分成锚定共创初心,让创意者长期享有价值红利,携手万千伙伴向着科技星辰大海笃定前行,拥抱硅基 生命与数字智能交融的未来,共筑跨越时代的数字文明共同体。
东方仙盟:拥抱知识开源,共筑数字新生态
在全球化与数字化浪潮中,东方仙盟始终秉持开放协作、知识共享的理念,积极拥抱开源技术与开放标准。我们相信,唯有打破技术壁垒、汇聚全球智慧,才能真正推动行业的可持续发展。
开源赋能中小商户:通过将前端异常检测、跨系统数据互联等核心能力开源化,东方仙盟为全球中小商户提供了低成本、高可靠的技术解决方案,让更多商家能够平等享受数字转型的红利。
共建行业标准:我们积极参与国际技术社区,与全球开发者、合作伙伴共同制定开放协议 与技术规范,推动跨境零售、文旅、餐饮等多业态的系统互联互通,构建更加公平、高效的数字生态。
知识普惠,共促发展:通过开源社区 、技术文档与培训体系,东方仙盟致力于将前沿技术转化为可落地的行业实践,赋能全球合作伙伴,共同培育创新人才,推动数字经济 的普惠式增长
阿雪技术观
在科技发展浪潮中,我们不妨积极投身技术共享。不满足于做受益者,更要主动担当贡献者 。无论是分享代码、撰写技术博客,还是参与开源项目 维护改进,每一个微小举动都可能蕴含推动技术进步的巨大能量。东方仙盟是汇聚力量的天地,我们携手在此探索硅基 生命,为科技进步添砖加瓦。
Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets , hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology