2011-03-08 8 views
11

OK, esta es otra de esas preguntas de "no tengo ninguna idea real por dónde empezar", así que espero que la respuesta sea simple. Sin embargo, realmente no sé qué buscar, y mis intentos hasta ahora no han tenido mucho uso.¿Cómo leer una clave privada para usar con OpenSAML?

Quiero leer una clave privada de un archivo (actualmente en el disco). En última instancia, la clave residirá en una base de datos, pero esto será lo suficientemente bueno por el momento y esa diferencia no debería afectar realmente el análisis del material clave. He podido crear una instancia Credential que contiene la parte pública de la clave (confirmada por el depurador), pero parece que no puedo entender cómo leer la parte privada. El par de claves se generó como:.

openssl genrsa 512 > d:\host.key 
openssl req -new -x509 -nodes -sha1 -days 365 -key d:\host.key > d:\host.cert 

(, sé que las claves RSA de 512 bits se rompieron hace mucho tiempo Sin embargo, para tratar de conseguir la API para trabajar, no veo ninguna razón para agotar el sistema suministro de entropía innecesariamente)

el código hasta ahora es:.

import org.opensaml.xml.security.credential.Credential; 
import org.opensaml.xml.security.x509.BasicX509Credential; 

private Credential getSigningCredential() 
throws java.security.cert.CertificateException, IOException { 
    BasicX509Credential credential = new BasicX509Credential(); 

    credential.setUsageType(UsageType.SIGNING); 

    // read public key 
    InputStream inStream = new FileInputStream("d:\\host.cert"); 
    CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
    X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream); 
    inStream.close(); 
    credential.setEntityCertificate(cert); 

    // TODO: read private key 

    // done. 
    return credential; 
} 

Pero ¿Cómo se lee el archivo host.key en la parte de la clave privada de credential, para que pueda utilizar la generada Credential instancia para firmar datos?

Respuesta

19

BasicX509Credential no es parte del estándar Java; Supongo que estás hablando de org.opensaml.xml.security.x509.BasicX509Credential de OpenSAML.

Quiere un PrivateKey que configurará con credential.setPrivateKey(). Para obtener una PrivateKey, primero debe convertir la clave privada en un formato que Java puede leer, es decir, PKCS # 8:

openssl pkcs8 -topk8 -nocrypt -outform DER <D:\host.key> D:\host.pk8 

Luego, a partir de Java:

RandomAccessFile raf = new RandomAccessFile("d:\\host.pk8", "r"); 
byte[] buf = new byte[(int)raf.length()]; 
raf.readFully(buf); 
raf.close(); 
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf); 
KeyFactory kf = KeyFactory.getInstance("RSA"); 
PrivateKey privKey = kf.generatePrivate(kspec); 

y listo! usted tiene su PrivateKey.

Por defecto openssl, escribe clave en su propio formato (para claves RSA, PKCS # 8 pasa a ser una envoltura alrededor de ese formato), y que los codifica en el PEM, que base 64 con un encabezado y un pie de página. Ambas características no están respaldadas por Java simple, de ahí la conversión a PKCS # 8. La opción -nocrypt se debe a que PKCS # 8 admite encriptación opcional basada en contraseña de clave privada.

Advertencia: que realmente realmente desea utilizar una clave más larga RSA. 512 bits son débiles; una clave RSA de 512 bits se rompió en 1999 con unos pocos cientos de computadoras. En 2011, con 12 años de avances tecnológicos, uno debería suponer que una llave RSA de 512 bits puede ser rota por casi cualquier persona. Por lo tanto, use las claves RSA de 1024 bits al menos (preferiblemente, 2048 bits; la carga computacional al usar la clave no es tan grave, aún podrá realizar cientos de firmas por segundo).

+0

Sí, BasicX509Credential es de OpenSAML, lo de que la supervisión. Definitivamente voy a darle una oportunidad. Y sí, sé perfectamente que las claves RSA de 512 bits no son de ninguna manera seguras, pero esta configuración particular es * estrictamente * para tratar de hacer que las cosas funcionen, por lo que la longitud de la clave no es un problema. –

+0

Parece que funciona como un amuleto, ¡muchas gracias! Por supuesto, mi código de firma parece estar roto, pero al menos de acuerdo con el depurador, obtengo una 'Credencial' adecuada de los dos archivos en el disco. En la gira ... –

+0

Gracias. Tuve problemas misteriosos con la redirección de < and > en Windows, por lo que es posible que desee reemplazarlos por los interruptores de entrada y salida. –

1

Esta pregunta está relacionada con SAML y también es relevante para alguien que quiere recuperar una clave privada para firmar un XMLObject.La respuesta anterior funciona muy bien y que también es posible recuperar una clave privada de un almacén de claves, así:

 Properties sigProperties = new Properties(); 

    sigProperties.put("org.apache.ws.security.crypto.provider","org.apache.ws.security.components.crypto.Merlin"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.type","jks"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.password","keypass"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.alias","keyalias"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.file","keystore.jks"); 

    Crypto issuerCrypto = CryptoFactory.getInstance(sigProperties); 

    String issuerKeyName = (String) sigProperties.get("org.apache.ws.security.crypto.merlin.keystore.alias"); 

    //See http://ws.apache.org/wss4j/xref/org/apache/ws/security/saml/ext/AssertionWrapper.html 'signAssertion' method 
    // prepare to sign the SAML token 
    CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); 
    cryptoType.setAlias(issuerKeyName); 
    X509Certificate[] issuerCerts = issuerCrypto.getX509Certificates(cryptoType); 
    if (issuerCerts == null) { 
     throw new WSSecurityException(
       "No issuer certs were found to sign the SAML Assertion using issuer name: " 
         + issuerKeyName); 
    } 

    String password = ADSUnitTestUtils.getPrivateKeyPasswordFromAlias(issuerKeyName); 

    PrivateKey privateKey = null; 
    try { 
     privateKey = issuerCrypto.getPrivateKey(issuerKeyName, password); 
    } catch (Exception ex) { 
     throw new WSSecurityException(ex.getMessage(), ex); 
    } 


    BasicX509Credential signingCredential = new BasicX509Credential(); 
    signingCredential.setEntityCertificate(issuerCerts[0]); 
    signingCredential.setPrivateKey(privateKey); 

    signature.setSigningCredential(signingCredential); 

Esto es más código que la consulta original solicitado, pero parece que están tratando de conseguir en un BasicX509Credential.

Gracias, Yogesh

Cuestiones relacionadas