2010-07-02 24 views
7

Necesito ayuda con las rutinas criptográficas en Java.Verificación de certificados PKCS # 7 en Java

Dado que tengo una firma PKCS # 7, quiero verificar todos los certificados que contiene contra una tienda de confianza. Asumo que todos los certificados contenidos en la firma están en el orden correcto para formar una ruta válida certificado (o de la cadena, lo que sea), de modo que

  • superior (# 0) es un certificado de firma;
  • siguiente (# 1) es un certificado intermedio, utilizado para firmar # 0;
  • siguiente (# 2) es otro certificado intermedio, usado para firmar # 1;
  • y así sucesivamente.

El último certificado (#N) está firmado por CA.

Eso es lo que he conseguido hackear hasta ahora:

// 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()); 

Entonces la pregunta es - ¿cómo se puede hacer esto utilizando las clases de Java estándar como CertPath y amigos? Tengo la fuerte sensación de que estoy reinventando una bicicleta. O, si alguien tiene un ejemplo con la biblioteca BouncyCastle, eso también estaría bien.

Pregunta extra: cómo verificar un certificado en una tienda de confianza para que el certificado raíz se seleccione automáticamente?

+0

sabes que se supone que no debes utilizar las clases del sol. *, ¿Verdad? –

+0

Sí. Solo encuentro que esta es la forma más fácil de extraer certificados del sobre de CMS. Pero creo que realmente debería cambiar a BouncyCastle, incluso considerando una dependencia adicional. – hudolejev

Respuesta

12

Encontré la solución yo mismo. Así pues, aquí es cómo se puede extraer y validar una cadena de certificados en el almacén de confianza (manejo de excepciones omite para facilitar la lectura):

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() lanzará una excepción si falla la validación.

Docs: ASN1Set, ContentInfo, SignedData. Todos los demás nombres exóticos y documentos relacionados se pueden encontrar en java.security.cert.

No hay dependencias SUN aquí, solo BouncyCastle provider library es necesario.

This pregunta (y especialmente una respuesta) pueden ayudar también.

+0

¡Muy, muy bien! Felicidades, amigo –

2

Quiere CertificateFactory. El último ejemplo en los javadocs hace exactamente lo que quieres.

+0

No exactamente. El último ejemplo crea una lista de certificados fuera del blob codificado que contiene * solo * certificados. Lo que tengo es una estructura 'SignedData' que contiene la lista de certificados * como uno de los campos *, que tengo que extraer primero. De todos modos, 'CertificateFactory.generateCertPath()' parece el camino a seguir. Muchas gracias. – hudolejev