坑爹微信之读取PKCS12流时出现的java.io.IOException: DerInputStream.getLength
背景
微信退款接口需要使用到证书,我参考微信的官方Demo进行,部分代码如下:
char[] password = config.getMchID().toCharArray();
InputStream certStream = config.getCertStream();
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(certStream, password);
上面的代码,在本地调试的时候正常跑过,没有出现任何异常,但是放到测试环境之后便会出现下面的异常,这三种异常都是从ks.load(certStream, password)这里抛出来的。定位这个问题花费了一些时间,且让我小小总结一下,供大家遇到相同问题时有个参考。
异常类型1
java.io.IOException: Short read of DER length
at sun.security.util.DerInputStream.getLength(DerInputStream.java:582)
at sun.security.util.DerValue.init(DerValue.java:391)
at sun.security.util.DerValue.<init>(DerValue.java:332)
at sun.security.util.DerValue.<init>(DerValue.java:345)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
at java.security.KeyStore.load(KeyStore.java:1445)
at com.lingyejun.authenticator.ReadPKCS12File$LoadCertInputStream.run(ReadPKCS12File.java:53)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
异常类型2
java.io.IOException: DerInputStream.getLength(): lengthTag=7, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:599)
at sun.security.util.DerValue.init(DerValue.java:391)
at sun.security.util.DerValue.<init>(DerValue.java:332)
at sun.security.util.DerValue.<init>(DerValue.java:345)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
at java.security.KeyStore.load(KeyStore.java:1445)
at com.lingyejun.authenticator.ReadPKCS12File$LoadCertInputStream.run(ReadPKCS12File.java:53)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
异常类型3
java.io.IOException: toDerInputStream rejects tag type 54
at sun.security.util.DerValue.toDerInputStream(DerValue.java:874)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1915)
at java.security.KeyStore.load(KeyStore.java:1445)
at com.lingyejun.authenticator.ReadPKCS12File$LoadCertInputStream.run(ReadPKCS12File.java:53)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
结论:keyStore.load(InputStream stream, char[] password)中的InputStream在尝试加载的过程中,如果有其他的线程正在使用或者进行同样的读加载,那么就会抛出上面的异常。
模拟复现
package com.lingyejun.authenticator; import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; /**
* 模拟加载certStream问题
*
* @Author: lingyejun
* @Date: 2019/6/24
* @Describe:
* @Modified By:
*/
public class ReadPKCS12File { // 线程个数
private static final int THREAD_POOL_SIZE = 10; // 初始化线程池
private ExecutorService executorService = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()); // HTTPS证书的本地路径
private static final String CERT_LOCAL_PATH = "apiclient_cert.p12"; // HTTPS证书密码,默认密码等于商户号MCHID
private static final String CERT_PASSWORD = "1509107311"; private static InputStream certStream = ReadPKCS12File.class.getClassLoader().getResourceAsStream(CERT_LOCAL_PATH); public static void main(String[] args) { ReadPKCS12File readPKCS12File = new ReadPKCS12File();
for (int threadNo = 0; threadNo < THREAD_POOL_SIZE; threadNo++) {
readPKCS12File.executorService.execute(readPKCS12File.new LoadCertInputStream());
}
readPKCS12File.executorService.shutdown();
} public class LoadCertInputStream implements Runnable { @Override
public void run() {
// 证书
char[] password = CERT_PASSWORD.toCharArray();
InputStream certStream = ReadPKCS12File.certStream;
try {
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(certStream, password); // 实例化密钥库 & 初始化密钥工厂
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password); // 创建 SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); // 余下代码就不写了,,, System.out.println("初始化SSL成功!"); } catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
}
}
知道问题之后,我们只需要将certStream由全局唯一更改为方法的局部变量即可
InputStream certStream = ReadPKCS12File.certStream
改为
InputStream certStream = ReadPKCS12File.class.getClassLoader().getResourceAsStream(CERT_LOCAL_PATH)
究其原因
微信的官方Demo中的,InputStream certStream = config.getCertStream(),这行代码把我给'误导'了,我是在外部读取的pkcs12文件输入流且config对象是单例的,导致多个线程共同访问这行代码时,certStream不能被正常加载,故出现了上面的问题。
参考回答:
坑爹微信之读取PKCS12流时出现的java.io.IOException: DerInputStream.getLength的更多相关文章
- 学习mybatis时出现了java.io.IOException: Could not find resource EmployeeMapper.xml
使用mybatis时出现了Could not find resource EmployeeMapper.xml和Could not find resource mybatis-config.xml两种 ...
- Android开发中与服务器交互时,遇到java.io.IOException: Target host must not be null的问题
当我遇到这个问题的时候,也在网上查找好半天.找到了一个和这个问题很类似的问题——java.lang.IllegalStateException: Target host must not be nul ...
- POI 导入导出时异常[java.io.IOException: Broken pipe]
使用用POI导出文件时抛出异常java.io.IOException: Broken pipe ERROR: 'java.io.IOException: Broken pipe' org.apache ...
- kafka启动时出现FATAL Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer) java.io.IOException: Permission denied错误解决办法(图文详解)
首先,说明,我kafk的server.properties是 kafka的server.properties配置文件参考示范(图文详解)(多种方式) 问题详情 然后,我启动时,出现如下 [hadoop ...
- 关于ActiveMQ+Zookeeper做集群时,解决启动报错:java.io.IOException: com/google/common/util/concurrent/internal/InternalFutureFailureAccess
这个问题我也是无意间碰到的,之前一直是使用单机的ActiveMQ,所以也没这个问题,但是做集群时碰到这个问题,问题是这样子出现的: 首先,我准备了三台虚拟机,然后使用 Replicated Level ...
- 对象反序列化时,抛出java.io.StreamCorruptedException: invalid type code: AC异常
问题描述:在使用java.io.ObjectInputStream类的readObject()方法去读取包含有序列化了多个(两个及两个以上)类的文件时,当读取到第二个类时,会抛出题目中提到的异常. 原 ...
- 在HttpClient请求的时候,返回结果解析时出现java.io.IOException: Attempted read from closed stream. 异常,解决
原因是EntityUtils.toString(HttpEntity)方法被使用了多次.所以每个方法内只能使用一次.
- hive运行query语句时提示错误:org.apache.hadoop.ipc.RemoteException: java.io.IOException: java.io.IOException:
hive> select product_id, track_time from trackinfo limit 5; Total MapReduce jobs = 1 Launching Jo ...
- Hadoop: HDFS 格式化时,出现 “ERROR namenode.NameNode: java.io.IOException: Cannot create directory /usr/hadoop/tmp/dfs/name/current”
原因是 没有设置 /usr/hadoop/tmp 的权限没有设置, 将之改为: chown –R hadoop:hadoop /usr/hadoop/tmp 查看:
随机推荐
- Jmeter:内存配置 -- 转发
在压测过程中jmeter报内存溢出,可能的原因有很多.要注意下面三点: 1.单击压测过程中使用过多的线程,官网建议1000-2000.具体看机器的配置和启动应用的情况.(A single JMeter ...
- 【开发笔记】- 发送邮件(通过JavaMail发送)
前段时间在工作中用到了邮件发送监控的报警信息,今天在这个记录一下JavaMail的邮件工具类. 下边为用到的JavaMail的jar包的pom依赖.这里用的是JavaMail的1.4.6的版本. &l ...
- 已知IP地址算子网掩码
子网掩码计算方法有两种: 方法一:利用子网数来计算: 1.首先,将子网数目从十进制数转化为二进制数: 2.接着,统计得到的二进制数的位数,设为N: 3.最后,先求出此IP地址对应的地址类别的子网掩码. ...
- oracle 数据库导入导出语句
oracle的exp/imp命令用于实现对数据库的导出/导入操作;exp命令用于把数据从远程数据库服务器导到本地,生成.dmp文件;imp命令用于把本地的数据库.dmp文件从本地导入到远程的oracl ...
- tcp、udp协议栈
tcp struct tcphdr { __be16 source; //源端口 __be16 dest; //目的端口 __be32 seq; //序列号 __be32 ack_seq; //确认号 ...
- Python学习日记(三十三) Mysql数据库篇 一
背景 Mysql是一个关系型数据库,由瑞典Mysql AB开发,目前属于Oracle旗下的产品.Mysql是目前最流行的关系型数据库管理系统之一,在WEB方面,Mysql是最好的RDBMS(Relat ...
- EFK(Elasticsearch+Filebeat+Kibana)收集容器日志
介绍 Elasticsearch 是一个实时的.分布式的可扩展的搜索引擎,允许进行全文.结构化搜索,它通常用于索引和搜索大量日志数据,也可用于搜索许多不同类型的文档. Beats 是数据采集的得力工具 ...
- linux绝大部分命令集合(自己需要的时候方便查找)
原网页:https://www.linuxidc.com/Linux/2018-04/151726.htm 系统信息显示命令arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构 ...
- HDU4091:Zombie’s Treasure Chest (分类-数学)
题意:给两种宝石,体积S1,S2,价值V1,V2,背包容量n,求最大收益. 所有数据都在32位整数范围内. 思路:只有两种物品的背包,显然不是常见的背包,应该从背包之外的思路下手. 1:可以猜想其中一 ...
- string长度问题
原文地址: https://toutiao.io/shares/2029578/url String是Java中很重要的一个数据类型,除了基本数据类型以外,String是被使用的最广泛的了,但是,关于 ...