2011-07-11 14 views
5

Estoy trabajando en un IBM iSeries anterior (IBM-i, i5OS, AS/400, etc.), con Java 5 JVM (Classic, no ITJ J9) en la versión de O/S V5R3M0.¿Por qué aparece el error "No se pueden almacenar claves no privadas" al crear un socket SSL en Java?

Aquí está el panorama en pocas palabras:

  1. que crea una clave-tienda de tipo JKS usando Portecle 1.7 (Nota: Yo probé la conversión de mi llave-tienda para JCEKS pero que fue rechazado como un formato no compatible , por lo que parece que JKS es la única opción con la máquina iSeries (al menos la versión en la que estoy)
  2. Luego creé un par de claves y CSR y envié el CSR a Thawte para su firma.
  3. I importé el certificado firmado de Thawte utilizando con éxito el formato PKCS # 7 para importar toda la cadena de certificados, que incluía mi certif icate, el intermediario Thawte y la raíz del servidor Thawte.

Todo funcionó como se esperaba.

Sin embargo, cuando ejecuté la JVM, configuré correctamente para apuntar a la tienda y proporcionar su contraseña (que he hecho en el pasado con certificados autofirmados creados en Portecle para pruebas) y tratar de iniciar mi web servidor en el 443, me sale el siguiente excepción de seguridad:

java.security.KeyStoreException: Cannot store non-PrivateKeys 

¿Puede alguien decirme que hice mal, o lo que debe comprobar a continuación?

Respuesta

3

lugar de utilizar un almacén de claves efímeras, que podría manejar todo dentro de un solo SSLContext.

Debería inicializar su SSLContext utilizando un X509KeyManager personalizado en lugar de usar el predeterminado KeyManagerFactory. En este X509KeyManager, chooseServerAlias(String keyType, Principal[] issuers, Socket socket) debe devolver un alias diferente dependiendo de la dirección local obtenida del socket.

De esta manera, no tendría que preocuparse por copiar la clave privada de un almacén de claves a otro, y esto incluso funcionaría para los tipos de almacén de claves de los que no puede extraer (y copiar) pero solo utiliza los archivos privados clave, por ejemplo PKCS # 11.

+0

Gracias; Voy a ver esto. –

28

El mensaje de error "Can not store non-PrivateKeys" generalmente indica que está tratando de usar claves simétricas secretas con un tipo de almacén de claves JKS. El tipo de almacén de claves JKS solo admite claves asimétricas (públicas/privadas). Debería crear un nuevo almacén de claves de tipo JCEKS para admitir claves secretas.

+0

Gracias, sí. El misterio era * por qué * crear un socket SSL estaba tratando de agregar * cualquier * claves al almacén de claves. Resultó que estaba tratando de agregar una clave nula a una tienda de claves; los detalles están en mi auto-respuesta a esta pregunta. –

3

Como resultado, este fue un problema sutil, y vale la pena dar la respuesta aquí en caso de que alguien más tenga algo similar.

La respuesta TLDR es que no verifiqué que mi clave y certificado no eran nulos y, como resultado, intenté agregar una clave nula y un certificado a un almacén de claves. La respuesta más larga sigue. La forma en que configuramos nuestro servidor web para usar SSL, específicamente para soportar la configuración típica de nuestro usuario donde la dirección IP se usa para configurar la dirección de escucha del sitio web en lugar de un nombre DNS, es que ubica el certificado en la clave de la tienda maestro usando el alias, y crea una clave-tienda efímera que contiene sólo el certificado para ese sitio web, utilizando esa clave-tienda para configurar un contexto SSL y una fábrica de sockets SSL, así:

// CREATE EPHEMERAL KEYSTORE FOR THIS SOCKET USING THE DESIRED CERTIFICATE 
try { 
    final char[]  BLANK_PWD=new char[0]; 
    SSLContext  ctx=SSLContext.getInstance("TLS"); 
    KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
    Key    ctfkey=mstkst.getKey(svrctfals,BLANK_PWD); 
    Certificate[]  ctfchn=mstkst.getCertificateChain(svrctfals); 
    KeyStore   sktkst; 

    sktkst=KeyStore.getInstance("jks"); 
    sktkst.load(null,BLANK_PWD); 
    sktkst.setKeyEntry(svrctfals,ctfkey,BLANK_PWD,ctfchn); 
    kmf.init(sktkst,BLANK_PWD); 
    ctx.init(kmf.getKeyManagers(),null,null); 
    ssf=ctx.getServerSocketFactory(); 
    } 
catch(java.security.GeneralSecurityException thr) { 
    throw new IOException("Cannot create server socket factory using ephemeral keystore ("+thr+")",thr); 
    } 

Observe que utiliza una contraseña en blanco para extraer la clave privada y los certificados del almacén de claves maestro. Ese era mi problema: por costumbre, al usar keytool, creé el par de claves privadas con una contraseña (la misma contraseña que el almacén de claves).

porque tenía una contraseña en el certificado, la clave y el certificado no se extrajeron, y nulo se pasó a sktkst.setKeyEntry(svrctfals,ctfkey,BLANK_PWD,ctfchn); Sin embargo, setKeyEntry comprueba el pasado Key utilizando instanceof y llega a la conclusión (correctamente) que null no es una instanceof PrivateKey, resultando en el error engañoso que estaba viendo.

El código corregido comprueba que la clave y el certificado se encontraron errores y envía apropiadas:

// CREATE EPHEMERAL KEYSTORE FOR THIS SOCKET USING THE DESIRED CERTIFICATE 
try { 
    final char[]  BLANK_PWD=new char[0]; 
    SSLContext  ctx=SSLContext.getInstance("TLS"); 
    KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
    Key    ctfkey=mstkst.getKey(svrctfals,BLANK_PWD); 
    Certificate[]  ctfchn=mstkst.getCertificateChain(svrctfals); 
    KeyStore   sktkst; 

    if(ctfkey==null) { 
     throw new IOException("Cannot create server socket factory: No key found for alias '"+svrctfals+"'"); 
     } 
    if(ctfchn==null || ctfchn.length==0) { 
     throw new IOException("Cannot create server socket factory: No certificate found for alias '"+svrctfals+"'"); 
     } 

    sktkst=KeyStore.getInstance("jks"); 
    sktkst.load(null,BLANK_PWD); 
    sktkst.setKeyEntry(svrctfals,ctfkey,BLANK_PWD,ctfchn); 
    kmf.init(sktkst,BLANK_PWD); 
    ctx.init(kmf.getKeyManagers(),null,null); 
    ssf=ctx.getServerSocketFactory(); 
    } 
catch(java.security.GeneralSecurityException thr) { 
    throw new IOException("Cannot create server socket factory using ephemeral keystore ("+thr+")",thr); 
    } 
Cuestiones relacionadas