2010-07-02 15 views
7

Java의 암호화 루틴에 대한 도움이 필요합니다.Java에서 PKCS # 7 인증서 확인

PKCS # 7 서명이 있으면 신뢰할 수있는 저장소에 대해 포함 된 모든 인증서를 확인하려고합니다. 나는 서명에 포함 된 모든 인증서가 유효한 인증서 경로 (또는 체인)를 구성하기 위해 올바른 순서로 있다고 가정합니다. 따라서

  • 최상위 (# 0)는 서명 인증서입니다.
  • 다음 인증서 (# 1)는 # 0에 서명하는 데 사용되는 중간 인증서입니다.
  • 다음 중 하나 (# 2)는 # 1에 서명하는 데 사용되는 다른 중간 인증서입니다.
  • 등등.

마지막 인증서 (#N)는 CA가 서명합니다.

지금까지 해킹을 관리했습니다 무엇 그것은 :

// Exception handling skipped for readability 

//byte[] signature = ... 
pkcs7 = new PKCS7(signature); // `sun.security.pkcs.PKCS7;` 

// *** Checking some PKCS#7 parameters here 

X509Certificate prevCert = null; // Previous certificate we've found 
X509Certificate[] certs = pkcs7.getCertificates(); // `java.security.cert.X509Certificate` 
for (int i = 0; i < certs.length; i++) { 
    // *** Checking certificate validity period here 

    if (cert != null) { 
     // Verify previous certificate in chain against this one 
     prevCert.verify(certs[i].getPublicKey()); 
    } 
    prevCert = certs[i]; 
} 

//String keyStorePath = ... 
KeyStore keyStore = KeyStore.getInstance("JKS"); // `java.security.KeyStore` 
keyStore.load(new FileInputStream(keyStorePath), null); 

// Get trusted VeriSign class 1 certificate 
Certificate caCert = keyStore.getCertificate("verisignclass1ca"); // `java.security.cert.Certificate` 

// Verify last certificate against trusted certificate 
cert.verify(caCert.getPublicKey()); 

그래서 질문입니다 - 이것은 CertPath과 친구 같은 표준 자바 클래스를 사용하여 어떻게 할 수 있는가? 나는 자전거를 다시 발명한다는 강한 느낌을 가지고 있습니다. 또는 누군가가 BouncyCastle 라이브러리 예제를 가지고 있다면 괜찮을 것입니다.

보너스 질문 : 루트 인증서가 자동으로 선택되도록 신뢰할 수있는 저장소에 대한 인증서를 확인하는 방법은 무엇입니까?

+0

당신은 태양의 수업을 사용하지 않아도된다는 것을 알고 있습니다. *, 맞습니까? –

+0

예. 난 그냥 CMS를 봉투에서 인증서를 추출하는 가장 쉬운 방법을 찾으십시오. 하지만 BouncyCastle로 전환해야한다고 생각합니다. – hudolejev

답변

12

해결책을 직접 찾았습니다. 그래서, 여기에 (예외 처리는 가독성을 위해 생략) 하나를 추출하고 신뢰할 수있는 저장소에 대한 인증서 체인의 유효성을 검사하는 방법은 다음과 같습니다 검증이 실패했을 경우

CertificateFactory cf = CertificateFactory.getInstance("X.509"); 

// Get ContentInfo 
//byte[] signature = ... // PKCS#7 signature bytes 
InputStream signatureIn = new ByteArrayInputStream(signature); 
DERObject obj = new ASN1InputStream(signatureIn).readObject(); 
ContentInfo contentInfo = ContentInfo.getInstance(obj); 

// Extract certificates 
SignedData signedData = SignedData.getInstance(contentInfo.getContent()); 
Enumeration certificates = signedData.getCertificates().getObjects(); 

// Build certificate path 
List certList = new ArrayList(); 
while (certificates.hasMoreElements()) { 
    DERObject certObj = (DERObject) certificates.nextElement(); 
    InputStream in = new ByteArrayInputStream(certObj.getDEREncoded()); 
    certList.add(cf.generateCertificate(in)); 
} 
CertPath certPath = cf.generateCertPath(certList); 

// Load key store 
//String keyStorePath = ... 
KeyStore keyStore = KeyStore.getInstance("JKS"); 
keyStore.load(new FileInputStream(keyStorePath), null); 

// Set validation parameters 
PKIXParameters params = new PKIXParameters(keyStore); 
params.setRevocationEnabled(false); // to avoid exception on empty CRL 

// Validate certificate path 
CertPathValidator validator = CertPathValidator.getInstance("PKIX"); 
CertPathValidatorResult result = validator.validate(certPath, params); 

validate() 예외가 발생합니다.

문서 : ASN1Set, ContentInfo, SignedData. 다른 모든 이국적인 이름과 관련 문서는 java.security.cert에서 찾을 수 있습니다.

여기에 SUN 종속성이 없으면 BouncyCastle provider library 만 필요합니다.

This 질문 (특히 답변)도 도움이 될 수 있습니다.

+0

아주 좋았어! 축하, 친구 –

2

당신은 CertificateFactory을 원합니다. javadoc의 마지막 예제는 원하는 것을 정확하게 수행합니다.

+0

정확하지 않습니다. 마지막 예제는 * only * 인증서를 포함하는 인코딩 된 blob에서 인증서 목록을 작성합니다. 내가 가지고있는 것은 먼저 추출해야하는 필드 * 중 하나로 인증서 목록을 포함하는'SignedData' 구조입니다. 어쨌든,'CertificateFactory.generateCertPath()'가가는 길 같습니다. 고마워. – hudolejev

관련 문제