我有一个https云服务器,在手机端的app发出请求后,获得服务端返回的内容,服务端存放了自制ca以及sever证书。
const https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync("./myserver.key"),
cert: fs.readFileSync('./myserver.crt'),
ca: fs.readFileSync('./MyCARoot.crt'),
requestCert: true,
rejectUnauthorized:true
这样的配置,就需要手机端安装client证书
但我并不想让使用者都来安装client证书,这样就把私钥泄漏出去了,能不能把*.pfx证书打包,然后以代码去加载证书呢?可以的,下面是实现的步骤:
1、在\Embarcadero\Studio\21.0\source\rtl\net下找到System.Net.HttpClient.Android.pas文件 ,复制一份到你的工程文件夹下,然后重命名。
2、把implementation下的所有类定义,移动到interface下
TAndroidHTTPRequest = class;
TAliasCallback = class(TJavaLocal, JKeyChainAliasCallback)
protected
[Weak] FRequest: TAndroidHTTPRequest;
public
procedure alias(alias: JString); cdecl;
constructor Create(const ARequest: TAndroidHTTPRequest);
TJHostnameVerifier = class(TJavaLocal, JHostnameVerifier)
public
function verify(hostname: JString; session: JSSLSession): Boolean; cdecl;
3、找到TAndroidHTTPClient = class(THTTPClient),增加两个私有成员
private
FMyTrustManagerFactory : JTrustManagerFactory;
FMyKeyManagerFactory: JKeyManagerFactory;
再添加两个procedure
procedure TAndroidHTTPClient.SetTrustManagerFactory(const ATmf: JTrustManagerFactory);
begin
FMyTrustManagerFactory := ATmf;
procedure TAndroidHTTPClient.setKeyManagerFactory(const AKMF: JKeyManagerFactory);
begin
FMyKeyManagerFactory := AKMF;
同样的,找到TAndroidHTTPRequest = class(THTTPRequest),增加这两个私有成员
4、找到procedure TAndroidHTTPRequest.DoPrepare,做修改,替换原来的处理方式
// TrustManager
//LJTrustManagers := FMyTrustManagerFactory.getTrustManagers;
LJOldTrustManager := TJX509TrustManager.Wrap(FMyTrustManagerFactory.getTrustManagers[0]); // Get Current Trust Manager.
FJTrustManager := TX509TrustManager.Create(LJOldTrustManager, Self);
LJTrustManagers := TJavaObjectArray<JTrustManager>.Create(1);
LJTrustManagers.Items[0] := TJTrustManager.Wrap(FJTrustManager);
LJCerts := FJTrustManager.getAcceptedIssuers;
FJTrustManager.checkClientTrusted(LJCerts, StringToJString('RSA'));
FJTrustManager.checkServerTrusted(LJCerts, StringToJString('RSA'));
// KeyManager
LJOldKeyManager := TJX509KeyManager.Wrap(FMyKeyManagerFactory.getKeyManagers[0]); // Get Current Key Manager.
FJKeyManager := TX509KeyManager.Create(LJOldKeyManager, Self);
LJKeyManagers := TJavaObjectArray<JKeyManager>.Create(1);
LJKeyManagers.Items[0] := TJKeyManager.Wrap(FJKeyManager);
5、找到function TAndroidHTTPClient.DoGetHTTPRequestInstance,把两个前面定义的私有成员传递给Request
function TAndroidHTTPClient.DoGetHTTPRequestInstance(const AClient: THTTPClient; const ARequestMethod: string;
const AURI: TURI): IHTTPRequest;
begin
Result := TAndroidHTTPRequest.Create(TAndroidHTTPClient(AClient), ARequestMethod, AURI);
//把两个工厂实例传递给创建的HttpRequest
(Result as TAndroidHTTPRequest).setTrustManagerFactory(FMyTrustManagerFactory);
(Result as TAndroidHTTPRequest).setKeyManagerFactory(FMyKeyManagerFactory);
6、找到procedure TX509TrustManager.checkServerTrusted,做修改
// 检查是否是权威CA,对于自制证书,无法通过
//FJOrigOldTrustManager.checkServerTrusted(chain, authType);
if not isServerTrusted(FRequest.FServerCertificate) then
raise ECertificateException.Create('无效服务端证书!');
把原生的checkServerTrusted(chain, authType);注释掉,以自定义的函数isServerTrusted
替换,这个函数很简单,判断CA证书和Server证书的序列号
function TX509TrustManager.isServerTrusted(const ADCert: TCertificate):boolean;
begin
//only check SN
if (UpperCase(ADCert.SerialNum) = '1AFE100A09D8E894') or
(UpperCase(ADCert.SerialNum) = '40F2768CE4B83190') then
Result := True
Result := False;
7、下面看看这两个工厂实例是如何初始化的
fname := System.IOUtils.TPath.GetDocumentsPath + PathDelim + 'myclient.pfx';
F := TFileStream.Create(fname, fmOpenRead);
R := X509Cert.LoadFromStreamPFX(F, 'XF@dM1n');
if R = 0 then
begin
ms := TMemoryStream.Create;
if X509Cert.PrivateKeyExists then
begin
X509Cert.SaveKeyToStreamPEM(ms, 'password');
fname := System.IOUtils.TPath.GetSharedDocumentsPath + PathDelim + 'mykey.pem';
ms.SaveToFile(fname);
KeyManager.ImportFromFile(fname, 3, 'RSA', '', '', 2);
vKey := KeyManager.Key.Key;
vSize := Length(vKey);
raise ECertificateException.Create('Failed to load certificate, PFX error ' + IntToHex(R, 4));
finally
F.Free;
ms.Free;
SetLength(vBytes, X509Cert.CertificateSize);
Move(X509Cert.CertificateBinary^, vBytes[0], X509Cert.CertificateSize);
LJArray := TJavaArray<Byte>.Create(Length(vBytes));
Move(vBytes[0], LJArray.Data^, Length(vBytes));
LJStream := TJByteArrayInputStream.JavaClass.init(LJArray);
LJArray.Free;
LJClientCert := TJCertificateFactory.JavaClass.getInstance(StringToJString('X.509')).generateCertificate(LJStream);
LJCertChain := TJavaObjectArray<JCertificate>.create(1);
LJCertChain.Items[0] := LJClientCert;
LJArray := TJavaArray<Byte>.Create(vSize);
move(vKey[0], LJArray.Data^, vSize);
LJkeySpec := TJPKCS8EncodedKeySpec.JavaClass.Init(LJArray);
LJKeyFactory := TJKeyFactory.JavaClass.getInstance(StringToJString('RSA'));
LJKey := TJRSAPrivateKey.Wrap(LJkeyFactory.generatePrivate(TJKeySpec.Wrap(LJkeySpec)));
// 實例化密鑰庫
LJAlgorithm := TJKeyManagerFactory.JavaClass.getDefaultAlgorithm;
s := JStringToString(LJAlgorithm);
kmf := TJKeyManagerFactory.JavaClass.getInstance(LJAlgorithm);
// 獲得密鑰庫
key_store_type := TJKeyStore.JavaClass.getDefaultType;
s := JStringToString(key_store_type);
LJKS_PK := TJKeyStore.JavaClass.getInstance(StringToJString('AndroidKeyStore'));
//只能是此方式,源码显示不接收非空参数
LJKS_PK.load(nil, nil);
LJKS_PK.setKeyEntry(StringToJString('mykey'), TJKey.Wrap(LJKey), nil, LJCertChain);
kmf.init(LJKS_PK, StringToJString('XF@dM1n').toCharArray);
//证书管理工厂
LJKS_Cert := TJKeyStore.JavaClass.getInstance(StringToJString('AndroidKeyStore'));
LJKS_Cert.load(nil, nil);
//key_Store.setCertificateEntry(StringToJString('ca'), ca);
LJKS_Cert.setCertificateEntry(StringToJString('LJClientCert'), LJClientCert);
LJAlgorithm := TJTrustManagerFactory.JavaClass.getDefaultAlgorithm;
s := JStringToString(LJAlgorithm); //#BKS
tmf := TJTrustManagerFactory.JavaClass.getInstance(LJAlgorithm);
tmf.init(LJKS_Cert);
//设置自己的两个工厂
FClient.SetTrustManagerFactory(tmf);
FClient.setKeyManagerFactory(kmf);
这里面用到SecureBlackBox的两个商业控件:KeyManager: TsbxCryptoKeyManager;
X509Cert: TElX509Certificate;这套控件是跨平台的,很贵,但很方便。也可以用免费的Bouncy Castle来替换,但要对导出的JNI做大量修改,很费神,还要导出一些大D没提供的JNI。
之前我的电脑有天突然触摸板失灵了 但我没怎么在意 直到最近有点受不了了我就赶紧看看怎么解决 我的是无法连接至synaptics定点装置驱动程序
看了许多回答都没用 偶然间看到要安装sio驱动程序 然后重启 试了后没用 然后就看到还要把触摸板驱动卸载后才能使用 结果果真有用 官方说的是用驱动精灵升级触摸板后会变成elan设备反正我的是这样 如果有人跟我一样情况 希望能帮助到你
「就这个sio驱动 一定要安装」
链接: https://pan.baidu.com/s/1bpZ1FLNnS8-pusX6K5I7dw 提取码: 5a18 复制这段内容后打开百度网盘手机App,操作更方便哦
主板(我没下,可能有用)
链接: https:...
本人安装了Ubuntu、windows10、Mac(黑苹果)三系统,用的是四叶草引导,但是某一天开机进入win10的时候突然发现声音不能用,显示未插入扬声器或耳机,然后控制面板里面的Realtek音频管理器也打不开,最后安装驱动精灵,装了驱动,却又导致触摸板不能使用了,于是,本人在多次尝试之后,将新装的触摸板驱动卸载,然后从主板进入windows,所有功能均正常
总结:从主板进入windows,卸...
笔记本电脑触控板突然失灵的解决办法
我使用的是联想拯救者Y7000,试过Fn+F11的禁用触控板热键以后发现没有恢复,检查触摸板驱动也发现这个笔记本触控是自识别不需要驱动
再通过设备管理器检查硬件情况,即设备管理器—人机接口设备—I2C HID设备发现没有感叹号,硬件检测正常
之后尝试通过关机—断开外接设备—长按电源键放电试图释放静电仍然无效
最后发现自己把最简单的一步漏了:只需在Windows设置—设备—触摸板选项界面选择开启即可,出于某种原因在此关闭后热键就没办法控制触摸板的开关,开启以后才能正常控制
忙里偷闲,写写最近发生的事情!
我的Y7000P 2018版,过保后大修一次,耗费1500大洋在官方售后换了主板,起因是,2020年冬天突然充不进去电,我以为是电池没插好,自己打开D壳,发现电池连接的好好的,但是装好D壳后发现,电脑无法开机,由于硬盘有重要课题资料,所以赶紧去了官方3C,售后告诉我,找不到什么原因,只能换主板,1500rmb很是心疼(到最后那个售后也没告诉我到底出了什么故障),去取电脑的途中,打开了短视频app,第一条推送便是“静电导致Y7000p无法开机,如何解决”,是官方出的,只需要把纽
解决联想拯救者电脑触控板失灵问题
解决联想拯救者Y9000X触控板失灵问题
Y9000X到手不久后,忽然有一天触控板失灵了,感觉莫名其妙,我啥也没干啊,折腾了一上午,才解决这个问题。
各位打开一下自己的设备管理器,找到人体学输入设备,看看I2C HID设备这一栏是不是有感叹号,如果有,咱们可能遇到了一样的问题。
第一种:首先讲一下我解决这个问题用的方法
拯救者电脑都有一个NO...
今天不小心点击了笔记本上面的飞行模式,关闭飞行模式后,发现触摸板没反应了,没有禁用、更新驱动都没用。最后将设备管理器里面**“鼠标和其他指针设备”中的“ELAN pointing device”禁用就可以了。**
之前也出过两次触控板失效的问题,不过之前按照:拯救者r7000p触摸板用不了是什么情况啊? - 缘枫光年外的回答里面的方法三,到联想官网下载“I2C HID设备”驱动,然后打开设备管理器(windows键 + X,即可找到设备管理器),在“人机接口设备”那里先卸载此驱动,再用下载的文件重新安装驱动,之后就好了。
但是这次一直都没成功,而且在设备管理器里都没找到“I2C HID设备”驱动:
之后把下载的驱动安装了几次,而且还重启了一下电脑,还是没解决问题。
然后捣鼓半.
解决方法 1 —— 使用 Driver Booster 还原驱动
如果使用的是 Driver Booster Pro,使用还原点还原驱动
(很可惜,当时本人更新的时候用的不是 Pro 版本)
解决方案 2 —— Windows 创建还原点
参考视频(需翻墙)
Touchpad Not Working on Lenovo Laptop - How To Fix Lenovo