一、 了解数字证书

在HTTPS的传输过程中,有一个非常关键的角色——数字证书,那什么是数字证书?又有什么作用呢?

所谓数字证书,是一种用于电脑的身份识别机制。由数字证书颁发机构(CA)对使用私钥创建的签名请求文件做的签名(盖章),表示CA结构对证书持有者的认可。数字证书拥有以下几个优点:

使用数字证书能够提高用户的可信度 数字证书中的公钥,能够与服务端的私钥配对使用,实现数据传输过程中的加密和解密

在证认使用者身份期间,使用者的敏感个人数据并不会被传输至证书持有者的网络系统上 X.509证书包含三个文件:keycsrcrt

key【密钥/私钥 Private Key】是服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密
csr【证书认证签名请求 Certificate signing request】是证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名
crt【证书 Certificate】是由证书颁发机构(CA)签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息。
备注:在密码学中,X.509是一个标准,规范了公开秘钥认证、证书吊销列表、授权凭证、凭证路径验证算法等。

此外还会涉及到不同平台的相关不同格式证书,这些证书可以在不同格式间相互转换

  • cer【俗称数字证书】,目的就是用于存储公钥证书,任何人都可以获取这个文件
  • pem -【Privacy Enhanced Mail】打开看⽂本格式,以"-----BEGIN…"开头, "-----END…"结尾,内容是BASE64编码。Apache和*NIX服务器偏向于使⽤这种编码格式.
  • p12 【是PKCS12的缩写】同样是一个存储私钥的证书库,由.jks文件导出的,用户在PC平台安装,用于标示用户的身份
  • bksAndroid平台支持的证书库格式】由于Android平台不识别.keystore__和.jks**格式的证书库文件,因此Android平台引入一种的证书库格式,BKS。
  • jks 【数字证书库】。JKS里有KeyEntry和CertEntry,在库里的每个Entry都是靠别名(alias)来识别的。

二、生成数字证书

数字证书的生成需要使用到openssl,这里只是简单介绍一下,详细咨询请自行查阅相关资料

  1. 安装 openssl
yum install openssl -y
  1. 常用命令
-req 产生证书签发申请命令
-newkey 生成新私钥 rsa:4096 生成秘钥位数
-nodes 表示私钥不加密
-sha256 使用SHA-2哈希算法
-keyout 将新创建的私钥写入的文件名
-x509 签发X.509格式证书命令。X.509是最通用的一种签名证书格式。
-out 指定要写入的输出文件名
-subj 指定用户信息
-days 有效期(3650表示十年)
-storepass 设置密码
-import 导入证书
-importkeystore 导入已有证书(转换格式)
-export 导出证书
-genkeypair 生成相关证书
-genkey 生成密钥

三、双向认证

1. 单向认证

操作系统或者浏览器一般都内置了一堆相关CA的证书,所以可以直接访问;若是自签发的,浏览器会提示该证书不受信任。适用场景是站点访问,非高机密数据传输。

https一般是单向认证,通常由客户端来校验服务器证书。

2. 双向认证

双向认证,即不仅客户端校验服务器,服务器也校验客户端,通常用于高机密数据传输。

客户端持有服务端的公钥证书,并持有自己的私钥,服务端持有客户的公钥证书,并持有自己私钥。

建立连接的时候,客户端利用服务端的公钥证书来验证服务器是否上是目标服务器;服务端利用客户端的公钥来验证客户端是否是目标客户端。(请参考RSA非对称加密以及HASH校验算法)

服务端给客户端发送数据时,需要将服务端的证书发给客户端验证,验证通过才运行发送数据,同样,客户端请求服务器数据时,也需要将自己的证书发给服务端验证,通过才允许执行请求。

四、生成自签名私有证书

1. 单向认证(只需要服务端证书)

1、生成服务端密钥(配置了jdk的环境变量即可用keytool命令)
命令

keytool -genkey -keystore server_ks.jks -storepass server_password -keyalg RSA -keypass server_password

结果:会生成server_ks.jks密钥文件
操作:将生成的server_ks.jks密钥文件配置到服务端

2、生成服务端证书
命令

keytool -export -keystore server_ks.jks -storepass server_password -file server.cer

结果:会生成server.cer证书文件
操作:将生成的server.cer证书文件配置到客户端

2. 双向认证(还需要客户端证书,和信任证书)

1、生成客户端密钥
命令

keytool -genkey -keystore client_ks.jks -storepass client_password -keyalg RSA -keypass client_password

结果:会生成client_ks.jks密钥文件
操作:将生成的client_ks.jks密钥文件配置到客户端

2、生成客户端证书
命令

keytool -export -keystore client_ks.jks -storepass client_password -file client.cer

结果:会生成client.cer证书文件

下面重点:证书交换
将客户端证书导入服务端keystore中,再将服务端证书导入客户端keystore中, 一个keystore可以导入多个证书,生成证书列表。

3、将server端证书添加到serverTrust_ks.jks文件中
命令

keytool -import -keystore serverTrust_ks.jks -storepass client -file server.cer

结果:会生成serverTrust_ks.jks密钥文件
操作:将生成的serverTrust_ks.jks密钥文件配置到客户端

4、将client端证书添加到clientTrust_ks.jks文件中
命令

keytool -import -keystore clientTrust_ks.jks -storepass server -file client.cer

结果:会生成clientTrust_ks.jks密钥文件
操作:将生成的clientTrust_ks.jks密钥文件配置到服务端

有些人可能有疑问,为什么有些博客操作只需要共用一个证书文件,而这里需要生成二个Trust文件?

因为有时客户端可能需要访问多个服务器,而每个服务器的证书都不相同,因此客户端需要制作一个truststore来存储受信任的服务器的证书列表。因此为了规范创建一个truststore.jks用于存储受信任的服务器证书,创建一个client.jks来存储客户端自己的私钥。对于只涉及与一个服务端进行双向认证的应用,将server.cer导入到client.jks中也可

3、将证书转换为Android平台支持的BKS格式

转换之前需要准备一些工具
格式转换工具下载
1.解压后将bcprov-ext-jdk15on-1.54.jar 放到
window系统:JDK路径/jre/lib/ext
mac系统:/Library/Java/JavaVirtualMachines/jdk1.8.0_341.jdk/Contents/Home/jre/lib/ext 文件夹中

2.修改,上面JDK路径/jre/lib/security 中的 java.security配置
找到如下的配置 再最后一行添加

security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider

注意这个 11 是版本 ,根据你电脑实际配置来改,如果原生文件最后一行版本是 n ,下一行就是n+1 ,这里我的最后一行版本是10,所以加的版本就是11。

服务端信任证书jks转bks

keytool -importkeystore -srckeystore serverTrust_ks.jks -destkeystore serverTrust_ks.bks -srcstoretype JKS -deststoretype BKS -srcstorepass client -deststorepass client -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-154.jar

客户端信任证书jks转bks

keytool -importkeystore -srckeystore clientTrust_ks.jks -destkeystore clientTrust_ks.bks -srcstoretype JKS -deststoretype BKS -srcstorepass server -deststorepass server -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-154.jar

服务端证书jks转bks

keytool -importkeystore -srckeystore server_ks.jks -destkeystore server_ks.bks -srcstoretype JKS -deststoretype BKS -srcstorepass server_password -deststorepass server_password -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-154.jar

客户端证书jks转bks

keytool -importkeystore -srckeystore client_ks.jks -destkeystore client_ks.bks -srcstoretype JKS -deststoretype BKS -srcstorepass client_password -deststorepass client_password -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-154.jar

做完这些操作,目录下应该有这些文件

至此准备工作做完,开始coding

五、Android项目配置

  1. 服务端代码(如果是使用NanoHttpd,可以继承SimpleWebServer进行测试)
public void init() {//生成秘钥的managerKeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");//加载信任的证书TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");//加载秘钥KeyStore keyStoreKey = KeyStore.getInstance("BKS");KeyStore keyStoreTrust = KeyStore.getInstance("BKS");//这里要把相关证书文件放到res-raw文件夹下,(放到assets下也行,读取方法不一样)InputStream keyStream = AppContext.getApp().getResources().openRawResource(R.raw.server_ks);InputStream trustStream = AppContext.getApp().getResources().openRawResource(R.raw.client_trust_ks);keyStoreKey.load(keyStream, "server_password".toCharArray());keyStoreTrust.load(trustStream, "server".toCharArray());//秘钥初始化keyManagerFactory.init(keyStoreKey, "server_password".toCharArray());trustManagerFactory.init(keyStoreTrust);//初始化SSLContextSSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();//设置ServerSocketFactory,需重写相关方法
setServerSocketFactory(new MutualAuthSecureServerSocketFactory(sslServerSocketFactory, null));
}

//如果是使用NanoHttpd,需要重写SecureServerSocketFactory,将ss.setNeedClientAuth(false);中的值改为true,这样就开启了服务端校验客户端功能。

 /*** Creates a new SSLServerSocket*/public static class MutualAuthSecureServerSocketFactory implements ServerSocketFactory {private SSLServerSocketFactory sslServerSocketFactory;private String[] sslProtocols;public MutualAuthSecureServerSocketFactory(SSLServerSocketFactory sslServerSocketFactory,String[] sslProtocols) {this.sslServerSocketFactory = sslServerSocketFactory;this.sslProtocols = sslProtocols;}@Overridepublic ServerSocket create() throws IOException {SSLServerSocket ss = null;ss = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket();if (this.sslProtocols != null) {ss.setEnabledProtocols(this.sslProtocols);} else {ss.setEnabledProtocols(ss.getSupportedProtocols());}ss.setUseClientMode(false);ss.setWantClientAuth(false);ss.setNeedClientAuth(true);return ss;}}
  1. 客户端代码
    以okhttp为例:
  /*** 关联Https请求验证证书*/public static SSLSocketFactory getSSLContext(Context context) {KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");//生成信任证书Manager,默认系统会信任CA机构颁发的证书,自定的证书需要手动的加载TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");KeyStore keyStoreKey = KeyStore.getInstance("BKS");KeyStore keyStoreTrust = KeyStore.getInstance("BKS");InputStream keyStream= AppContext.getApp().getResources().openRawResource(R.raw.client_ks);InputStream trustStream= AppContext.getApp().getResources().openRawResource(R.raw.server_trust_ks);//加载client端密钥keyStoreKey.load(keyStream, "client_password".toCharArray());//信任证书keyStoreTrust.load(trustStream, "client".toCharArray());keyManagerFactory.init(keyStoreKey, "client_password".toCharArray());trustManagerFactory.init(keyStoreTrust);SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null/* new SecureRandom()*/);SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();return sslSocketFactory;} catch (CertificateException e) {e.printStackTrace();} catch (KeyStoreException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();} catch (UnrecoverableKeyException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}
SSLSocketFactory sslSocketFactory = HttpsUtils.getClientSSLContext(context);OkHttpClient okHttpClient = new OkHttpClient.Builder()//.connectionSpecs(Collections.singletonList(spec)) //开启全部的tls协议和加密.sslSocketFactory(sslSocketFactory, new HttpsUtils.HttpsTrustManager()).hostnameVerifier((hostname, session) -> true)//这里可以校验域名.build();Request request = new Request.Builder().url(url).build();okHttpClient.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {Log.e("request", "error:" + e.toString());e.printStackTrace();}@Overridepublic void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {ResponseBody body = response.body();if (response.isSuccessful()) {Log.e("request", "success:${}" + body.string());} else {Log.e("request", "error,statusCode=" + response.code() + ",body" + body.string());}}});

完整代码 https://github.com/MirkoWu/HttpsSSLAuthDemo

Android本地服务器NanoHttpd配置Https双向认证相关推荐

  1. (转载)Android 让WebView完美支持https双向认证(SSL)

    (转载)https://blog.csdn.net/kpioneer123/article/details/51491739 这是@happyzhang0502   关于webview https的建 ...

  2. soapui 证书_配置https双向认证,以及用soapui调试

    maxThreads="150" scheme="https" secure="true" clientAuth="false&q ...

  3. nginx 配置 https双向认证

    参考文章: https://blog.csdn.net/xiangguiwang/article/details/76400805 https://blog.csdn.net/qq_37049781/ ...

  4. Wamp apache 配置 Https 双向 认证 全过程

    1.我安装的是Wampserver 2.2.11,  d:\wamp目录 2.本机操作系统Win7 32位 3.D:\wamp\bin\apache\Apache2.2.11\bin  下有  ope ...

  5. HTTPS双向认证配置

    最近看了下HTTPS相关的,概念性的东西各位就去查查资料吧.主要找到两篇比较靠谱的文章,收藏下. xiooa面复制自https://my.oschina.net/jjface/blog/339144 ...

  6. Nginx配置ssl双向认证

    最近公司项目需要配置双向认证,使用的是阿里云Linux服务器以及nginx,对应的ssl证书也使用的是阿里云的免费证书.特此记录配置流程. CA与自签名 # 制作CA私钥 openssl genrsa ...

  7. Https双向认证Android客户端配置

    Https双向认证啊  做了两遍,第一遍懵懂状态处于 好不容易做好了,换服务器,一下子懵了,使出浑身解数又找了一遍,这下终于好了  快哭啦,必须滴要记录一下,以免以后遇到继续懵,这里用retrofit ...

  8. tomcat实现https双向认证配置

    Tomcat实现https双向认证配置 1.生成证书库 2.jks转p12 3.证书库导出cer文件 4.证书库生成证书请求 5.对证书请求进行签名 6.例子 6.1创建证书库 6.2导出根证书 6. ...

  9. 服务器双向认证 原理,https认证方式以及HTTPS双向认证过程

    https认证方式以及HTTPS双向认证过程 分类:建站推广 编辑: 浏览量:100 2021-07-15 14:29:14 很多网站都配置了HTTPS而不是HTTP,因为安全性得到了极大的提高,如果 ...

最新文章

  1. R中控制输出数值的小数点位数round,和有效数字位数signif
  2. 我的阿里梦——淘宝前端必备技能
  3. 太骚了!Python模型完美切换SAS,还能这么玩。。
  4. c 语言登录系统源代码,c语言源代码---------------个人图书管理系统
  5. element ui 菜单右侧展开_Elementui Vue 菜单固定展开的问题
  6. BroadcastReceiver广播接受者简单使用
  7. Spring Cloud教程合集
  8. mysql drop_MySQL DROP TABLE语句语法
  9. 关于选课系统的的界面设计、类图设计、数据库设计。
  10. Mobento:能搜索视频中说过的话
  11. php怎么判断qq内置浏览器,PHP判断是否是微信打开,浏览器打开的方法
  12. 苹果HomeKit与谷歌 Home对比:谁是最佳选择?
  13. 电脑开机遇见a disk read error occurred场景:
  14. initramfs进不了系统
  15. NXP JN5169 使用看门狗定时器
  16. Mac 卸载 隐蔽软件 Core_Sync 的步骤
  17. dreamspark 注册,wp7 app hub微软手机开发者帐号(全新3步注册)
  18. 树莓派教程(1)——手把手教你在无显示器的情况下使用树莓派
  19. 幼儿园 计算机课教案,幼儿园信息技术教案
  20. 替代兼容矽力杰SY6982E双电池5V升压锂离子电池充电器充电IC

热门文章

  1. Portraiture Mac(PS磨皮滤镜插件) v3.5.1已注册版
  2. python生成带背景的字符图片(crnn数据集制作)
  3. 【技巧】浅谈Johnson算法
  4. 【Unity3D】纹理贴图 ( 纹理 Texture 简介 | 为 3D 模型设置纹理贴图 )
  5. 国产浏览器通过meta指定急速模式
  6. 做的最简单的APP-计数器
  7. 高通平台开发系列讲解(PCIE篇)MHI (Modem Host Interface)驱动详解
  8. 决策报表里使用延时函数实现某些js效果
  9. 畅捷通(chanjet)T+各版本
  10. dota是java中的_用java开发dota英雄最华丽的技能