国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

坑爹微信之讀取PKCS12流時出現的java.io.IOException: DerInputStr

calx / 2516人閱讀

摘要:背景微信退款接口需要使用到證書,我參考微信的官方進行,部分代碼如下上面的代碼,在本地調試的時候正常跑過,沒有出現任何異常,但是放到測試環境之后便會出現下面的異常,這三種異常都是從這里拋出來的。

背景

微信退款接口需要使用到證書,我參考微信的官方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.(DerValue.java:332)
    at sun.security.util.DerValue.(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.(DerValue.java:332)
    at sun.security.util.DerValue.(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)

結論: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());
 
    // 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不能被正常加載,故出現了上面的問題。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74978.html

相關文章

  • HttpsURLConnection使用,并實現雙向認證

    摘要:添加信任所有服務端證書也可在方法中控制信任所有證書使用發送請求默認端口測試客戶端證書路徑證書密碼發送請求導入客戶端證書添加信任證書為信任所有證書創建上下文初始化參數為,則不上傳客戶端證書通常情況都是如此驗證系統默認證書導出服務端證書, 添加信任所有服務端證書也可在方法中控制 package something; import java.security.cert.Certificat...

    layman 評論0 收藏0
  • Java? 教程(捕獲和處理異常)

    捕獲和處理異常 本節描述如何使用三個異常處理程序組件 — try、catch和finally塊 — 來編寫異常處理程序,然后,解釋了Java SE 7中引入的try-with-resources語句,try-with-resources語句特別適用于使用Closeable資源的情況,例如流。 本節的最后一部分將介紹一個示例,并分析各種場景中發生的情況。 以下示例定義并實現名為ListOfNumbe...

    Yujiaao 評論0 收藏0
  • Java編程基礎21——IO(字節)

    摘要:流按操作類型分為兩種字節流字節流可以操作任何數據因為在計算機中任何數據都是以字節的形式存儲的字符流字符流只能操作純字符數據,比較方便。 1_IO流概述及其分類 1.概念 IO流用來處理設備之間的數據傳輸 Java對數據的操作是通過流的方式 Java用于操作流的類都在IO包中 流按流向分為兩種:輸入流,輸出流。 流按操作類型分為兩種: 字節流 : 字節流可以操作任何數據,因為在...

    yanbingyun1990 評論0 收藏0
  • Java編程基礎22——IO(字符)&字符其他內容&遞歸

    摘要:字符流字符流是什么字符流是可以直接讀寫字符的流字符流讀取字符就要先讀取到字節數據然后轉為字符如果要寫出字符需要把字符轉為字節再寫出類的方法可以按照字符大小讀取通過項目默認的碼表一次讀取一個字符賦值給將讀到的字符強轉后打印字符流類的方法可以 1_字符流FileReader 1.字符流是什么 字符流是可以直接讀寫字符的IO流 字符流讀取字符, 就要先讀取到字節數據, 然后轉為字符. ...

    BoYang 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<