Commit 93a49fe9 authored by Guus der Kinderen's avatar Guus der Kinderen

Merge pull request #526 from guusdk/aberenguel-certificate-issues

Aberenguel certificate issues
parents 8c7a56f4 436da497
package org.jivesoftware.openfire.keystore; package org.jivesoftware.openfire.keystore;
import org.bouncycastle.operator.OperatorCreationException;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.net.DNSUtil; import org.jivesoftware.openfire.net.DNSUtil;
import org.jivesoftware.util.CertificateManager; import org.jivesoftware.util.CertificateManager;
...@@ -99,7 +100,7 @@ public class IdentityStore extends CertificateStore ...@@ -99,7 +100,7 @@ public class IdentityStore extends CertificateStore
return pemCSR; return pemCSR;
} }
catch ( IOException | NoSuchProviderException | SignatureException | InvalidKeyException | KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException e ) catch ( IOException | KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException | OperatorCreationException e )
{ {
throw new CertificateStoreConfigException( "Cannot generate CSR for alias '"+ alias +"'", e ); throw new CertificateStoreConfigException( "Cannot generate CSR for alias '"+ alias +"'", e );
} }
...@@ -194,7 +195,7 @@ public class IdentityStore extends CertificateStore ...@@ -194,7 +195,7 @@ public class IdentityStore extends CertificateStore
final X509Certificate x509Certificate = (X509Certificate) certificate; final X509Certificate x509Certificate = (X509Certificate) certificate;
// First certificate in the chain should correspond with the certificate in the store // First certificate in the chain should correspond with the certificate in the store
if ( !x509Certificate.getSerialNumber().equals( certificates.get( 0 ).getSerialNumber() ) ) if ( !x509Certificate.getPublicKey().equals(certificates.get(0).getPublicKey()) )
{ {
return false; return false;
} }
...@@ -402,8 +403,7 @@ public class IdentityStore extends CertificateStore ...@@ -402,8 +403,7 @@ public class IdentityStore extends CertificateStore
final String name = JiveGlobals.getProperty( "xmpp.domain" ).toLowerCase(); final String name = JiveGlobals.getProperty( "xmpp.domain" ).toLowerCase();
final String alias = name + "_" + algorithm.toLowerCase(); final String alias = name + "_" + algorithm.toLowerCase();
final String distinctName = "cn=" + name; final int validityInDays = 5*365;
final int validityInDays = 60;
Log.info( "Generating a new private key and corresponding self-signed certificate for domain name '{}', using the {} algorithm (sign-algorithm: {} with a key size of {} bits). Certificate will be valid for {} days.", name, algorithm, signAlgorithm, keySize, validityInDays ); Log.info( "Generating a new private key and corresponding self-signed certificate for domain name '{}', using the {} algorithm (sign-algorithm: {} with a key size of {} bits). Certificate will be valid for {} days.", name, algorithm, signAlgorithm, keySize, validityInDays );
// Generate public and private keys // Generate public and private keys
...@@ -412,7 +412,7 @@ public class IdentityStore extends CertificateStore ...@@ -412,7 +412,7 @@ public class IdentityStore extends CertificateStore
final KeyPair keyPair = generateKeyPair( algorithm.toUpperCase(), keySize ); final KeyPair keyPair = generateKeyPair( algorithm.toUpperCase(), keySize );
// Create X509 certificate with keys and specified domain // Create X509 certificate with keys and specified domain
final X509Certificate cert = CertificateManager.createX509V3Certificate( keyPair, validityInDays, distinctName, distinctName, name, signAlgorithm ); final X509Certificate cert = CertificateManager.createX509V3Certificate( keyPair, validityInDays, name, name, name, signAlgorithm );
// Store new certificate and private key in the key store // Store new certificate and private key in the key store
store.setKeyEntry( alias, keyPair.getPrivate(), configuration.getPassword(), new X509Certificate[]{cert} ); store.setKeyEntry( alias, keyPair.getPrivate(), configuration.getPassword(), new X509Certificate[]{cert} );
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
package org.jivesoftware.openfire.session; package org.jivesoftware.openfire.session;
import java.io.IOException; import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
...@@ -36,7 +35,6 @@ import org.jivesoftware.openfire.SessionManager; ...@@ -36,7 +35,6 @@ import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID; import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.keystore.CertificateStoreManager;
import org.jivesoftware.openfire.net.SASLAuthentication; import org.jivesoftware.openfire.net.SASLAuthentication;
import org.jivesoftware.openfire.net.SocketConnection; import org.jivesoftware.openfire.net.SocketConnection;
import org.jivesoftware.openfire.server.ServerDialback; import org.jivesoftware.openfire.server.ServerDialback;
...@@ -371,8 +369,7 @@ public class LocalIncomingServerSession extends LocalServerSession implements In ...@@ -371,8 +369,7 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
usingSelfSigned = true; usingSelfSigned = true;
} else { } else {
try { try {
final KeyStore keyStore = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore( ConnectionType.SOCKET_S2S ).getStore(); usingSelfSigned = CertificateManager.isSelfSignedCertificate((X509Certificate) chain[0]);
usingSelfSigned = CertificateManager.isSelfSignedCertificate(keyStore, (X509Certificate) chain[0]);
} catch (KeyStoreException ex) { } catch (KeyStoreException ex) {
Log.warn("Exception occurred while trying to determine whether local certificate is self-signed. Proceeding as if it is.", ex); Log.warn("Exception occurred while trying to determine whether local certificate is self-signed. Proceeding as if it is.", ex);
usingSelfSigned = true; usingSelfSigned = true;
......
...@@ -20,9 +20,23 @@ ...@@ -20,9 +20,23 @@
package org.jivesoftware.util; package org.jivesoftware.util;
import java.io.*; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.*; import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchProviderException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import java.security.cert.CertPathBuilder; import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathBuilderException;
...@@ -36,42 +50,62 @@ import java.security.cert.CollectionCertStoreParameters; ...@@ -36,42 +50,62 @@ import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXBuilderParameters;
import java.security.cert.X509CertSelector; import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.X509Extensions; import org.bouncycastle.cert.CertException;
import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.jce.PKCS10CertificationRequest; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.openssl.MiscPEMGenerator;
import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder; import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.InputDecryptorProvider; import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException; import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.x509.X509V3CertificateGenerator; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.io.pem.PemObjectGenerator;
import org.bouncycastle.util.io.pem.PemWriter;
import org.jivesoftware.openfire.keystore.CertificateStore; import org.jivesoftware.openfire.keystore.CertificateStore;
import org.jivesoftware.openfire.keystore.CertificateStoreConfigException;
import org.jivesoftware.openfire.keystore.CertificateUtils; import org.jivesoftware.openfire.keystore.CertificateUtils;
import org.jivesoftware.util.cert.CertificateIdentityMapping;
import org.jivesoftware.util.cert.CNCertificateIdentityMapping; import org.jivesoftware.util.cert.CNCertificateIdentityMapping;
import org.jivesoftware.util.cert.CertificateIdentityMapping;
import org.jivesoftware.util.cert.SANCertificateIdentityMapping; import org.jivesoftware.util.cert.SANCertificateIdentityMapping;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -89,11 +123,6 @@ public class CertificateManager { ...@@ -89,11 +123,6 @@ public class CertificateManager {
private static Pattern valuesPattern = Pattern.compile("(?i)(=)([^,]*)"); private static Pattern valuesPattern = Pattern.compile("(?i)(=)([^,]*)");
/**
* The maximum length of lines in certification requests
*/
private static final int CERT_REQ_LINE_LENGTH = 76;
private static List<CertificateEventListener> listeners = new CopyOnWriteArrayList<>(); private static List<CertificateEventListener> listeners = new CopyOnWriteArrayList<>();
private static List<CertificateIdentityMapping> serverCertMapping = new ArrayList<>(); private static List<CertificateIdentityMapping> serverCertMapping = new ArrayList<>();
...@@ -108,7 +137,7 @@ public class CertificateManager { ...@@ -108,7 +137,7 @@ public class CertificateManager {
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String s_provider = st.nextToken(); String s_provider = st.nextToken();
try { try {
Class c_provider = ClassUtils.forName(s_provider); Class<?> c_provider = ClassUtils.forName(s_provider);
CertificateIdentityMapping provider = CertificateIdentityMapping provider =
(CertificateIdentityMapping)(c_provider.newInstance()); (CertificateIdentityMapping)(c_provider.newInstance());
Log.debug("CertificateManager: Loaded server identity mapping " + s_provider); Log.debug("CertificateManager: Loaded server identity mapping " + s_provider);
...@@ -132,7 +161,7 @@ public class CertificateManager { ...@@ -132,7 +161,7 @@ public class CertificateManager {
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String s_provider = st.nextToken(); String s_provider = st.nextToken();
try { try {
Class c_provider = ClassUtils.forName(s_provider); Class<?> c_provider = ClassUtils.forName(s_provider);
CertificateIdentityMapping provider = CertificateIdentityMapping provider =
(CertificateIdentityMapping)(c_provider.newInstance()); (CertificateIdentityMapping)(c_provider.newInstance());
Log.debug("CertificateManager: Loaded client identity mapping " + s_provider); Log.debug("CertificateManager: Loaded client identity mapping " + s_provider);
...@@ -393,28 +422,13 @@ public class CertificateManager { ...@@ -393,28 +422,13 @@ public class CertificateManager {
* @return true if the specified certificate is a self-signed certificate. * @return true if the specified certificate is a self-signed certificate.
* @throws KeyStoreException if an error happens while usign the keystore * @throws KeyStoreException if an error happens while usign the keystore
*/ */
public static boolean isSelfSignedCertificate(KeyStore keyStore, String alias) throws KeyStoreException { public static boolean isSelfSignedCertificate(X509Certificate certificate) throws KeyStoreException {
// Get certificate chain try {
java.security.cert.Certificate[] certificateChain = keyStore.getCertificateChain( alias ); certificate.verify(certificate.getPublicKey());
// Verify that the chain is empty or was signed by himself return true;
return certificateChain == null || certificateChain.length == 1; } catch (GeneralSecurityException e) {
} return false;
/**
* Returns true if the specified certificate is a self-signed certificate. If the certificate
* was not found in the store then a KeyStoreException is returned.
*
* @param keyStore key store that holds the certificate to verify.
* @param certificate the certificate in the key store.
* @return true if the specified certificate is a self-signed certificate.
* @throws KeyStoreException if an error happens while usign the keystore
*/
public static boolean isSelfSignedCertificate(KeyStore keyStore, X509Certificate certificate) throws KeyStoreException {
String alias = keyStore.getCertificateAlias( certificate );
if (alias == null) {
throw new KeyStoreException("Certificate not found in store: " + certificate);
} }
return isSelfSignedCertificate(keyStore, alias);
} }
/** /**
...@@ -427,14 +441,13 @@ public class CertificateManager { ...@@ -427,14 +441,13 @@ public class CertificateManager {
* @return true if the specified certificate is ready to be signed by a Certificate Authority. * @return true if the specified certificate is ready to be signed by a Certificate Authority.
* @throws KeyStoreException if an error happens while usign the keystore * @throws KeyStoreException if an error happens while usign the keystore
*/ */
public static boolean isSigningRequestPending(KeyStore keyStore, String alias) throws KeyStoreException { public static boolean isSigningRequestPending(X509Certificate certificate) throws KeyStoreException {
// Verify that this is a self-signed certificate // Verify that this is a self-signed certificate
if (!isSelfSignedCertificate(keyStore, alias)) { if (!isSelfSignedCertificate(certificate)) {
return false; return false;
} }
// Verify that the issuer information has been entered // Verify that the issuer information has been entered
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(alias); Matcher matcher = valuesPattern.matcher(certificate.getIssuerDN().toString());
Matcher matcher = valuesPattern.matcher( certificate.getIssuerDN().toString() );
return matcher.find() && matcher.find(); return matcher.find() && matcher.find();
} }
...@@ -450,44 +463,26 @@ public class CertificateManager { ...@@ -450,44 +463,26 @@ public class CertificateManager {
* @param privKey the private key of the certificate. * @param privKey the private key of the certificate.
* @return the content of a new singing request for the specified certificate. * @return the content of a new singing request for the specified certificate.
*/ */
public static String createSigningRequest(X509Certificate cert, PrivateKey privKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, IOException public static String createSigningRequest(X509Certificate cert, PrivateKey privKey) throws OperatorCreationException, IOException {
{
StringBuilder sb = new StringBuilder();
String subject = cert.getSubjectDN().getName();
X509Name xname = new X509Name(subject);
PublicKey pubKey = cert.getPublicKey();
String signatureAlgorithm = "DSA".equals(pubKey.getAlgorithm()) ? "SHA1withDSA" : "SHA1WITHRSAENCRYPTION";
PKCS10CertificationRequest csr = JcaPKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder( //
new PKCS10CertificationRequest(signatureAlgorithm, xname, pubKey, null, privKey); cert.getSubjectX500Principal(), //
cert.getPublicKey() //
);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); String signatureAlgorithm = "SHA256WITH" + cert.getPublicKey().getAlgorithm();
DEROutputStream deros = new DEROutputStream(baos);
deros.writeObject(csr.toASN1Primitive());
String sTmp = new String(org.bouncycastle.util.encoders.Base64.encode(baos.toByteArray()));
// Header ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithm).build(privKey);
sb.append("-----BEGIN NEW CERTIFICATE REQUEST-----\n"); PKCS10CertificationRequest csr = csrBuilder.build(signer);
// Add signing request content (base 64 encoded) StringWriter string = new StringWriter();
for (int iCnt = 0; iCnt < sTmp.length(); iCnt += CERT_REQ_LINE_LENGTH) { PemWriter pemWriter = new PemWriter(string);
int iLineLength;
if ((iCnt + CERT_REQ_LINE_LENGTH) > sTmp.length()) { PemObjectGenerator objGen = new MiscPEMGenerator(csr);
iLineLength = sTmp.length() - iCnt; pemWriter.writeObject(objGen);
} else { pemWriter.close();
iLineLength = CERT_REQ_LINE_LENGTH;
}
sb.append(sTmp.substring(iCnt, iCnt + iLineLength)).append("\n");
}
// Footer return string.toString();
sb.append("-----END NEW CERTIFICATE REQUEST-----\n");
return sb.toString();
} }
/** /**
...@@ -508,7 +503,7 @@ public class CertificateManager { ...@@ -508,7 +503,7 @@ public class CertificateManager {
* @return true if the CA reply was successfully processed. * @return true if the CA reply was successfully processed.
* @throws Exception * @throws Exception
*/ */
public static boolean installReply(KeyStore keyStore, KeyStore trustStore, String keyPassword, String alias, InputStream inputStream) throws Exception { public static boolean installReply(KeyStore keyStore, KeyStore trustStore, char[] keyPassword, String alias, InputStream inputStream) throws Exception {
// Check that there is a certificate for the specified alias // Check that there is a certificate for the specified alias
X509Certificate certificate = (X509Certificate) keyStore.getCertificate( alias ); X509Certificate certificate = (X509Certificate) keyStore.getCertificate( alias );
...@@ -517,7 +512,7 @@ public class CertificateManager { ...@@ -517,7 +512,7 @@ public class CertificateManager {
return false; return false;
} }
// Retrieve the private key of the stored certificate // Retrieve the private key of the stored certificate
PrivateKey privKey = (PrivateKey) keyStore.getKey(alias, keyPassword.toCharArray()); PrivateKey privKey = (PrivateKey) keyStore.getKey(alias, keyPassword);
// Load certificates found in the PEM input stream // Load certificates found in the PEM input stream
Collection<X509Certificate> certs = parseCertificates( inputStream ); Collection<X509Certificate> certs = parseCertificates( inputStream );
if (certs.isEmpty()) { if (certs.isEmpty()) {
...@@ -535,7 +530,7 @@ public class CertificateManager { ...@@ -535,7 +530,7 @@ public class CertificateManager {
{ {
return false; return false;
} }
keyStore.setKeyEntry(alias, privKey, keyPassword.toCharArray(), newCerts.toArray(new X509Certificate[newCerts.size()])); keyStore.setKeyEntry(alias, privKey, keyPassword, newCerts.toArray(new X509Certificate[newCerts.size()]));
// Notify listeners that a new certificate has been created // Notify listeners that a new certificate has been created
for (CertificateEventListener listener : listeners) { for (CertificateEventListener listener : listeners) {
...@@ -613,15 +608,15 @@ public class CertificateManager { ...@@ -613,15 +608,15 @@ public class CertificateManager {
return true; return true;
} }
/**
* @deprecated Use {@link #parsePrivateKey(String, String)} instead. public static PrivateKey parsePrivateKey(String pemRepresentation, String passPhrase) throws IOException {
*/
@Deprecated if (pemRepresentation == null || pemRepresentation.trim().isEmpty()) {
public static PrivateKey parsePrivateKey( InputStream pemRepresentation, String passPhrase ) throws IOException throw new IllegalArgumentException("Argument 'pemRepresentation' cannot be null or an empty String.");
{ }
// see http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
final java.util.Scanner s = new java.util.Scanner( pemRepresentation ).useDelimiter("\\A"); ByteArrayInputStream input = new ByteArrayInputStream(pemRepresentation.getBytes(StandardCharsets.UTF_8));
return parsePrivateKey( s.hasNext() ? s.next() : "", passPhrase ); return parsePrivateKey(input, passPhrase);
} }
/** /**
...@@ -633,17 +628,15 @@ public class CertificateManager { ...@@ -633,17 +628,15 @@ public class CertificateManager {
* @param passPhrase optional pass phrase (must be present if the private key is encrypted). * @param passPhrase optional pass phrase (must be present if the private key is encrypted).
* @return a PrivateKey instance (never null) * @return a PrivateKey instance (never null)
*/ */
public static PrivateKey parsePrivateKey( String pemRepresentation, String passPhrase ) throws IOException public static PrivateKey parsePrivateKey(InputStream pemRepresentation, String passPhrase) throws IOException {
{
if ( pemRepresentation == null || pemRepresentation.trim().isEmpty() ) {
throw new IllegalArgumentException( "Argument 'pemRepresentation' cannot be null or an empty String.");
}
if ( passPhrase == null ) { if ( passPhrase == null ) {
passPhrase = ""; passPhrase = "";
} }
try ( Reader reader = new StringReader( pemRepresentation.trim() )) try (Reader reader = new InputStreamReader(pemRepresentation); //
{ PEMParser pemParser = new PEMParser(reader)) {
final Object object = new PEMParser( reader ).readObject();
final Object object = pemParser.readObject();
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider( "BC" ); final JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider( "BC" );
final KeyPair kp; final KeyPair kp;
...@@ -682,15 +675,16 @@ public class CertificateManager { ...@@ -682,15 +675,16 @@ public class CertificateManager {
} }
} }
/** public static Collection<X509Certificate> parseCertificates(String pemRepresentation) throws IOException,
* @deprecated Use {@link #parseCertificates(String)} instead. CertificateException {
*/
@Deprecated // The parser is very picky. We should trim each line of the input string.
public static Collection<X509Certificate> parseCertificates( InputStream pemRepresentation ) throws IOException, CertificateException final String pem = pemRepresentation //
{ .replaceAll("(?m) +$", "") // remove trailing whitespace
// see http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string .replaceAll("(?m)^ +", ""); // remove leading whitespace
final java.util.Scanner s = new java.util.Scanner( pemRepresentation ).useDelimiter("\\A");
return parseCertificates( s.hasNext() ? s.next() : "" ); ByteArrayInputStream input = new ByteArrayInputStream(pem.getBytes(StandardCharsets.UTF_8));
return parseCertificates(input);
} }
/** /**
...@@ -699,22 +693,17 @@ public class CertificateManager { ...@@ -699,22 +693,17 @@ public class CertificateManager {
* @param pemRepresentation a PEM representation of a certificate or certificate chain (cannot be null or empty) * @param pemRepresentation a PEM representation of a certificate or certificate chain (cannot be null or empty)
* @return A collection of certificates (possibly empty, but never null). * @return A collection of certificates (possibly empty, but never null).
*/ */
public static Collection<X509Certificate> parseCertificates( String pemRepresentation ) throws IOException, CertificateException @SuppressWarnings("unchecked")
{ public static Collection<X509Certificate> parseCertificates(InputStream pemRepresentation) throws IOException,
if ( pemRepresentation == null || pemRepresentation.trim().isEmpty() ) { CertificateException {
throw new IllegalArgumentException( "Argument 'pemRepresentation' cannot be null or an empty String.");
}
// The parser is very picky. We should trim each line of the input string. CertificateFactory certificateFactory;
final String pem = pemRepresentation try {
.replaceAll( "(?m) +$", "" ) // remove trailing whitespace certificateFactory = CertificateFactory.getInstance("X509", "BC");
.replaceAll( "(?m)^ +", "" ); // remove leading whitespace } catch (NoSuchProviderException e) {
certificateFactory = CertificateFactory.getInstance("X509");
try ( InputStream inputStream = new ByteArrayInputStream( pem.getBytes() ) )
{
final CertificateFactory certificateFactory = CertificateFactory.getInstance( "X509" );
return (Collection<X509Certificate>) certificateFactory.generateCertificates( inputStream );
} }
return (Collection<X509Certificate>) certificateFactory.generateCertificates(pemRepresentation);
} }
/** /**
...@@ -752,7 +741,7 @@ public class CertificateManager { ...@@ -752,7 +741,7 @@ public class CertificateManager {
throw new Exception("Certificate reply and certificate in keystore are identical"); throw new Exception("Certificate reply and certificate in keystore are identical");
} }
} }
Map<Principal, List<X509Certificate>> knownCerts = new Hashtable<>(); Map<String, List<X509Certificate>> knownCerts = new Hashtable<>();
// TODO Figure out why we add keystore issuers. This implies that we always trust the issuer of our identitity (which probably is right, but shouldn't be required) // TODO Figure out why we add keystore issuers. This implies that we always trust the issuer of our identitity (which probably is right, but shouldn't be required)
if (keyStore.size() > 0) { if (keyStore.size() > 0) {
...@@ -781,7 +770,7 @@ public class CertificateManager { ...@@ -781,7 +770,7 @@ public class CertificateManager {
* @return true if the entire chain of all certificates was successfully built. * @return true if the entire chain of all certificates was successfully built.
*/ */
private static boolean buildChain(X509Certificate certificate, LinkedList<X509Certificate> answer, private static boolean buildChain(X509Certificate certificate, LinkedList<X509Certificate> answer,
Map<Principal, List<X509Certificate>> knownCerts) { Map<String, List<X509Certificate>> knownCerts) {
Principal subject = certificate.getSubjectDN(); Principal subject = certificate.getSubjectDN();
Principal issuer = certificate.getIssuerDN(); Principal issuer = certificate.getIssuerDN();
// Check if the certificate is a root certificate (i.e. was issued by the same Principal that // Check if the certificate is a root certificate (i.e. was issued by the same Principal that
...@@ -791,7 +780,7 @@ public class CertificateManager { ...@@ -791,7 +780,7 @@ public class CertificateManager {
return true; return true;
} }
// Get the list of known certificates of the certificate's issuer // Get the list of known certificates of the certificate's issuer
List<X509Certificate> issuerCerts = knownCerts.get(issuer); List<X509Certificate> issuerCerts = knownCerts.get(issuer.getName());
if (issuerCerts == null || issuerCerts.isEmpty()) { if (issuerCerts == null || issuerCerts.isEmpty()) {
// No certificates were found so building of chain failed // No certificates were found so building of chain failed
return false; return false;
...@@ -822,9 +811,9 @@ public class CertificateManager { ...@@ -822,9 +811,9 @@ public class CertificateManager {
* @return a map with the certificates per issuer. * @return a map with the certificates per issuer.
* @throws Exception * @throws Exception
*/ */
private static Map<Principal, List<X509Certificate>> getCertsByIssuer(KeyStore ks) private static Map<String, List<X509Certificate>> getCertsByIssuer(KeyStore ks)
throws Exception { throws Exception {
Map<Principal, List<X509Certificate>> answer = new HashMap<>(); Map<String, List<X509Certificate>> answer = new HashMap<>();
Enumeration<String> aliases = ks.aliases(); Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) { while (aliases.hasMoreElements()) {
String alias = aliases.nextElement(); String alias = aliases.nextElement();
...@@ -841,7 +830,7 @@ public class CertificateManager { ...@@ -841,7 +830,7 @@ public class CertificateManager {
vec.add(cert); vec.add(cert);
} }
} }
answer.put(subjectDN, vec); answer.put(subjectDN.getName(), vec);
} }
} }
return answer; return answer;
...@@ -971,19 +960,46 @@ public class CertificateManager { ...@@ -971,19 +960,46 @@ public class CertificateManager {
* Creates an X509 version3 certificate. * Creates an X509 version3 certificate.
* *
* @param kp KeyPair that keeps the public and private keys for the new certificate. * @param kp KeyPair that keeps the public and private keys for the new certificate.
* @param months time to live * @param days time to live
* @param issuerDN Issuer string e.g "O=Grid,OU=OGSA,CN=ACME" * @param issuerCommonName Issuer CN string
* @param subjectDN Subject string e.g "O=Grid,OU=OGSA,CN=John Doe" * @param subjectCommonName Subject CN string
* @param domain Domain of the server. * @param domain Domain of the server.
* @param signAlgoritm Signature algorithm. This can be either a name or an OID. * @param signAlgoritm Signature algorithm. This can be either a name or an OID.
* @return X509 V3 Certificate * @return X509 V3 Certificate
* @throws GeneralSecurityException * @throws GeneralSecurityException
* @throws IOException * @throws IOException
*/ */
public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int months, String issuerDN, public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int days, String issuerCommonName,
String subjectDN, String domain, String subjectCommonName, String domain,
String signAlgoritm) String signAlgoritm)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
// subjectDN
X500NameBuilder subjectBuilder = new X500NameBuilder();
subjectBuilder.addRDN(BCStyle.CN, subjectCommonName);
// issuerDN
X500NameBuilder issuerBuilder = new X500NameBuilder();
issuerBuilder.addRDN(BCStyle.CN, issuerCommonName);
return createX509V3Certificate(kp, days, issuerBuilder, subjectBuilder, domain, signAlgoritm);
}
/**
* Creates an X509 version3 certificate.
*
* @param kp KeyPair that keeps the public and private keys for the new certificate.
* @param days time to live
* @param issuerBuilder IssuerDN builder
* @param subjectBuilder SubjectDN builder
* @param domain Domain of the server.
* @param signAlgoritm Signature algorithm. This can be either a name or an OID.
* @return X509 V3 Certificate
* @throws GeneralSecurityException
* @throws IOException
*/
public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int days, X500NameBuilder issuerBuilder,
X500NameBuilder subjectBuilder, String domain, String signAlgoritm) throws GeneralSecurityException, IOException {
PublicKey pubKey = kp.getPublic(); PublicKey pubKey = kp.getPublic();
PrivateKey privKey = kp.getPrivate(); PrivateKey privKey = kp.getPrivate();
...@@ -993,32 +1009,52 @@ public class CertificateManager { ...@@ -993,32 +1009,52 @@ public class CertificateManager {
random.nextBytes(serno); random.nextBytes(serno);
BigInteger serial = (new java.math.BigInteger(serno)).abs(); BigInteger serial = (new java.math.BigInteger(serno)).abs();
X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator(); X500Name issuerDN = issuerBuilder.build();
certGenerator.reset(); X500Name subjectDN = subjectBuilder.build();
certGenerator.setSerialNumber(serial); // builder
certGenerator.setIssuerDN(new X509Name(issuerDN)); JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder( //
certGenerator.setNotBefore(new Date(System.currentTimeMillis())); issuerDN, //
certGenerator.setNotAfter( serial, //
new Date(System.currentTimeMillis() + months * (1000L * 60 * 60 * 24 * 30))); new Date(), //
certGenerator.setSubjectDN(new X509Name(subjectDN)); new Date(System.currentTimeMillis() + days * (1000L * 60 * 60 * 24)), //
certGenerator.setPublicKey(pubKey); subjectDN, //
certGenerator.setSignatureAlgorithm(signAlgoritm); pubKey //
);
// Generate the subject alternative name
boolean critical = subjectDN == null || "".equals(subjectDN.trim()); // add subjectAlternativeName extension
boolean critical = subjectDN.getRDNs().length == 0;
ASN1Sequence othernameSequence = new DERSequence(new ASN1Encodable[]{ ASN1Sequence othernameSequence = new DERSequence(new ASN1Encodable[]{
new DERObjectIdentifier("1.3.6.1.5.5.7.8.5"), new DERTaggedObject(true, 0, new DERUTF8String(domain))}); new ASN1ObjectIdentifier("1.3.6.1.5.5.7.8.5"), new DERTaggedObject(true, 0, new DERUTF8String(domain))});
GeneralName othernameGN = new GeneralName(GeneralName.otherName, othernameSequence); GeneralName othernameGN = new GeneralName(GeneralName.otherName, othernameSequence);
GeneralNames subjectAltNames = new GeneralNames(new GeneralName[]{othernameGN}); GeneralNames subjectAltNames = new GeneralNames(new GeneralName[]{othernameGN});
// Add subject alternative name extension certBuilder.addExtension(Extension.subjectAlternativeName, critical, subjectAltNames);
certGenerator.addExtension(X509Extensions.SubjectAlternativeName, critical, subjectAltNames);
// add keyIdentifiers extensions
JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils();
certBuilder.addExtension(Extension.subjectKeyIdentifier, false, utils.createSubjectKeyIdentifier(pubKey));
certBuilder.addExtension(Extension.authorityKeyIdentifier, false, utils.createAuthorityKeyIdentifier(pubKey));
X509Certificate cert = try {
certGenerator.generateX509Certificate(privKey, "BC", new SecureRandom()); // build the certificate
cert.checkValidity(new Date()); ContentSigner signer = new JcaContentSignerBuilder(signAlgoritm).build(privKey);
cert.verify(pubKey); X509CertificateHolder cert = certBuilder.build(signer);
// verify the validity
if (!cert.isValidOn(new Date())) {
throw new GeneralSecurityException("Certificate validity not valid");
}
return cert; // verify the signature (self-signed)
ContentVerifierProvider verifierProvider = new JcaContentVerifierProviderBuilder().build(pubKey);
if (!cert.isSignatureValid(verifierProvider)) {
throw new GeneralSecurityException("Certificate signature not valid");
}
return new JcaX509CertificateConverter().getCertificate(cert);
} catch (OperatorCreationException | CertException e) {
throw new GeneralSecurityException(e);
}
} }
} }
<%@page import="java.util.Enumeration"%>
<%@page import="org.jivesoftware.openfire.XMPPServer"%>
<%@page import="java.security.PublicKey"%>
<%@page import="java.security.KeyPair"%>
<%@page import="java.security.cert.X509Certificate"%>
<%@page import="java.security.PrivateKey"%>
<%@page import="org.jivesoftware.openfire.keystore.IdentityStore"%>
<%@page import="java.security.KeyStore"%>
<%@page import="org.bouncycastle.asn1.x500.X500Name"%>
<%@page import="org.bouncycastle.asn1.x500.style.BCStyle"%>
<%@page import="org.bouncycastle.asn1.x509.Extension"%>
<%@page import="org.bouncycastle.asn1.x500.X500NameBuilder"%>
<%@page import="org.jivesoftware.util.CertificateManager"%>
<%@ page import="org.jivesoftware.util.ParamUtils" %> <%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.util.StringUtils" %> <%@ page import="org.jivesoftware.util.StringUtils" %>
<%@ page import="java.util.HashMap" %> <%@ page import="java.util.HashMap" %>
...@@ -10,99 +23,101 @@ ...@@ -10,99 +23,101 @@
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" /> <jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out ); %> <% webManager.init(request, response, session, application, out ); %>
<% // Get parameters: <%
String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
// Get parameters:
final boolean save = ParamUtils.getParameter(request, "save") != null; final boolean save = ParamUtils.getParameter(request, "save") != null;
final String name = ParamUtils.getParameter(request, "name"); final String name = domain;
final String organizationalUnit = ParamUtils.getParameter(request, "ou"); final String organizationalUnit = ParamUtils.getParameter(request, "ou");
final String organization = ParamUtils.getParameter(request, "o"); final String organization = ParamUtils.getParameter(request, "o");
final String city = ParamUtils.getParameter(request, "city"); final String city = ParamUtils.getParameter(request, "city");
final String state = ParamUtils.getParameter(request, "state"); final String state = ParamUtils.getParameter(request, "state");
final String countryCode = ParamUtils.getParameter(request, "country"); final String countryCode = ParamUtils.getParameter(request, "country");
final String storePurposeText = ParamUtils.getParameter(request, "connectionType"); final String connectionTypeText = ParamUtils.getParameter( request, "connectionType" );
final Map<String, String> errors = new HashMap<String, String>(); final Map<String, String> errors = new HashMap<String, String>();
ConnectionType connectionType; ConnectionType connectionType = null;
IdentityStore identityStore = null;
try try
{ {
connectionType = ConnectionType.valueOf( storePurposeText ); connectionType = ConnectionType.valueOf( connectionTypeText );
} catch (RuntimeException ex) { identityStore = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore( connectionType );
if ( identityStore == null )
{
errors.put( "identityStore", "Unable to get an instance." );
}
}
catch (RuntimeException ex)
{
errors.put( "connectionType", ex.getMessage() ); errors.put( "connectionType", ex.getMessage() );
connectionType = null;
} }
pageContext.setAttribute( "connectionType", connectionType ); pageContext.setAttribute( "connectionType", connectionType );
// if (save) { if (save) {
//
// // Verify that fields were completed // Verify that fields were completed
// if (name == null) { if (organizationalUnit == null) {
// errors.put("name", ""); errors.put("organizationalUnit", "");
// } }
// if (organizationalUnit == null) { if (organization == null) {
// errors.put("organizationalUnit", ""); errors.put("organization", "");
// } }
// if (organization == null) { if (city == null) {
// errors.put("organization", ""); errors.put("city", "");
// } }
// if (city == null) { if (state == null) {
// errors.put("city", ""); errors.put("state", "");
// } }
// if (state == null) { if (countryCode == null) {
// errors.put("state", ""); errors.put("countryCode", "");
// } }
// if (countryCode == null) { if (errors.size() == 0) {
// errors.put("countryCode", ""); try {
// } X500NameBuilder builder = new X500NameBuilder();
// if (errors.size() == 0) { builder.addRDN(BCStyle.CN, name);
// try { builder.addRDN(BCStyle.OU, organizationalUnit);
// final IdentityStore identityStoreConfig = (IdentityStore) SSLConfig.getInstance().getStoreConfig( connectionType ); builder.addRDN(BCStyle.O, organization);
// builder.addRDN(BCStyle.L, city);
// identityStoreConfig.ensureSelfSignedDomainCertificates( name, organizationalUnit, organization, city, state, countryCode, "rsa", "dsa" ); builder.addRDN(BCStyle.ST, state);
// // Regenerate self-sign certs whose subjectDN matches the issuerDN and set the new issuerDN builder.addRDN(BCStyle.C, countryCode);
// String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
// StringBuilder issuerDN = new StringBuilder(); // Update certs with new issuerDN information
// issuerDN.append("CN=").append(name); KeyStore keyStore = identityStore.getStore();
// issuerDN.append(", OU=").append(organizationalUnit); for (Enumeration<String> certAliases = keyStore.aliases(); certAliases.hasMoreElements();) {
// issuerDN.append(", O=").append(organization);
// issuerDN.append(", L=").append(city); String alias = certAliases.nextElement();
// issuerDN.append(", ST=").append(state); X509Certificate certificate = (X509Certificate) keyStore.getCertificate(alias);
// issuerDN.append(", C=").append(countryCode);
// StringBuilder subjectDN = new StringBuilder(); // Update only Self-signed certs
// subjectDN.append("CN=").append(domain); if (CertificateManager.isSelfSignedCertificate(certificate)) {
// subjectDN.append(", OU=").append(organizationalUnit);
// subjectDN.append(", O=").append(organization); PrivateKey privKey = (PrivateKey) keyStore.getKey(alias, identityStore.getConfiguration().getPassword());
// subjectDN.append(", L=").append(city); PublicKey pubKey = certificate.getPublicKey();
// subjectDN.append(", ST=").append(state);
// subjectDN.append(", C=").append(countryCode); String signAlgoritm = "SHA256WITH" + pubKey.getAlgorithm();
// // Update certs with new issuerDN information int days = 60;
// for (Enumeration<String> certAliases = keyStore.aliases(); certAliases.hasMoreElements();) {
// String alias = certAliases.nextElement(); // Regenerate self-sign certs whose subjectDN matches the issuerDN and set the new issuerDN
// X509Certificate certificate = (X509Certificate) keyStore.getCertificate(alias); X509Certificate newCertificate = CertificateManager.createX509V3Certificate(new KeyPair(pubKey, privKey), days, builder, builder, domain, signAlgoritm);
// // Update only Self-signed certs keyStore.setKeyEntry(alias, privKey, identityStore.getConfiguration().getPassword(), new X509Certificate[] { newCertificate });
// if (CertificateManager.isSelfSignedCertificate(keyStore, alias)) { }
// if (CertificateManager.isDSACertificate(certificate)) { }
// CertificateManager.createDSACert(keyStore, sslConfig.getKeyStorePassword(), alias, // Save keystore
// issuerDN.toString(), subjectDN.toString(), "*." + domain); identityStore.persist();
// } else { // Log the event
// CertificateManager.createRSACert(keyStore, sslConfig.getKeyStorePassword(), alias, webManager.logEvent("generated SSL signing request", null);
// issuerDN.toString(), subjectDN.toString(), "*." + domain); response.sendRedirect("security-keystore.jsp?connectionType="+connectionType);
// } return;
// } }
// } catch (Exception e) {
// // Save keystore e.printStackTrace();
// sslConfig.saveStores(); errors.put("general", "");
// // Log the event }
// webManager.logEvent("generated SSL signing request", null); }
// response.sendRedirect("security-keystore.jsp?connectivityType="+connectivityType); }
// return;
// }
// catch (Exception e) {
// e.printStackTrace();
// errors.put("general", "");
// }
// }
// }
%> %>
<html> <html>
...@@ -110,7 +125,7 @@ ...@@ -110,7 +125,7 @@
<title> <title>
<fmt:message key="ssl.signing-request.title"/> <fmt:message key="ssl.signing-request.title"/>
</title> </title>
<meta name="pageID" content="security-keystore-${connectivityType}"/> <meta name="pageID" content="security-keystore-${connectionType}"/>
</head> </head>
<body> <body>
...@@ -118,9 +133,6 @@ ...@@ -118,9 +133,6 @@
<c:forEach var="err" items="${errors}"> <c:forEach var="err" items="${errors}">
<admin:infobox type="error"> <admin:infobox type="error">
<c:choose> <c:choose>
<c:when test="${err.key eq 'name'}">
<fmt:message key="ssl.signing-request.enter_name" />
</c:when>
<c:when test="${err.key eq 'organizationalUnit'}"> <c:when test="${err.key eq 'organizationalUnit'}">
<fmt:message key="ssl.signing-request.enter_ou" /> <fmt:message key="ssl.signing-request.enter_ou" />
</c:when> </c:when>
...@@ -147,9 +159,9 @@ ...@@ -147,9 +159,9 @@
</c:forEach> </c:forEach>
<!-- BEGIN 'Issuer information form' --> <!-- BEGIN 'Issuer information form' -->
<form action="ssl-signing-request.jsp" method="post"> <form action="security-keystore-signing-request.jsp" method="post">
<input type="hidden" name="save" value="true"> <input type="hidden" name="save" value="true">
<input type="hidden" name="connectivityType" value="${connectivityType}"> <input type="hidden" name="connectionType" value="${connectionType}">
<div class="jive-contentBoxHeader"> <div class="jive-contentBoxHeader">
<fmt:message key="ssl.signing-request.issuer_information"/> <fmt:message key="ssl.signing-request.issuer_information"/>
</div> </div>
...@@ -167,7 +179,7 @@ ...@@ -167,7 +179,7 @@
</td> </td>
<td width="99%"> <td width="99%">
<input type="text" name="name" size="50" maxlength="75" <input type="text" name="name" size="50" maxlength="75"
value="<%= ((name!=null) ? StringUtils.escapeForXML(name) : "") %>" id="namef"> value="<%= ((name!=null) ? StringUtils.escapeForXML(name) : "") %>" id="namef" disabled="disabled">
</td> </td>
</tr> </tr>
<tr> <tr>
......
<%@page import="org.jivesoftware.util.StringUtils"%>
<%@page import="java.util.LinkedHashMap"%>
<%@page import="java.security.PrivateKey"%>
<%@page import="org.jivesoftware.util.CertificateManager"%>
<%@ page errorPage="error.jsp" %> <%@ page errorPage="error.jsp" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %> <%@ page import="org.jivesoftware.openfire.XMPPServer" %>
...@@ -87,27 +91,20 @@ ...@@ -87,27 +91,20 @@
pageContext.setAttribute( "errors", errors ); pageContext.setAttribute( "errors", errors );
/**
if (generate) { if (generate) {
String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain(); String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
try { try {
if (errors.containsKey("ioerror") && keyStore == null) { if (errors.containsKey("ioerror") || !identityStore.containsDomainCertificate("DSA")) {
keyStore = sslConfig.initializeKeyStore(); identityStore.addSelfSignedDomainCertificate("DSA");
}
if (errors.containsKey("ioerror") || !CertificateManager.isDSACertificate(keyStore, domain)) {
CertificateManager
.createDSACert(keyStore, sslConfig.getKeyStorePassword(), domain + "_dsa", "cn=" + domain, "cn=" + domain, "*." + domain);
} }
if (errors.containsKey("ioerror") || !CertificateManager.isRSACertificate(keyStore, domain)) { if (errors.containsKey("ioerror") || !identityStore.containsDomainCertificate("RSA")) {
CertificateManager identityStore.addSelfSignedDomainCertificate("RSA");
.createRSACert(keyStore, sslConfig.getKeyStorePassword(), domain + "_rsa", "cn=" + domain, "cn=" + domain, "*." + domain);
} }
// Save new certificates into the key store // Save new certificates into the key store
sslConfig.saveStores(); identityStore.persist();
// Log the event // Log the event
webManager.logEvent("generated SSL self-signed certs", null); webManager.logEvent("generated SSL self-signed certs", null);
response.sendRedirect("security-keystore.jsp?connectivityType="+connectivityType); response.sendRedirect("security-keystore.jsp?connectionType="+connectionType);
return; return;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
...@@ -119,12 +116,11 @@ ...@@ -119,12 +116,11 @@
String reply = ParamUtils.getParameter(request, "reply"); String reply = ParamUtils.getParameter(request, "reply");
if (alias != null && reply != null && reply.trim().length() > 0) { if (alias != null && reply != null && reply.trim().length() > 0) {
try { try {
CertificateManager.installReply( keyStore, s2sTrustStore, identityStore.installCSRReply(alias, reply);
sslConfig.getKeyStorePassword(), alias, new ByteArrayInputStream( reply.getBytes() ) ); identityStore.persist();
sslConfig.saveStores();
// Log the event // Log the event
webManager.logEvent( "imported SSL certificate with alias " + alias, null ); webManager.logEvent( "imported SSL certificate with alias " + alias, null );
response.sendRedirect("security-keystore.jsp?connectivityType="+connectivityType); response.sendRedirect("security-keystore.jsp?connectionType="+connectionType);
return; return;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
...@@ -132,10 +128,12 @@ ...@@ -132,10 +128,12 @@
} }
} }
} }
*/
final boolean restartNeeded = ( (AdminConsolePlugin) XMPPServer.getInstance().getPluginManager().getPlugin( "admin" ) ).isRestartNeeded(); final boolean restartNeeded = ( (AdminConsolePlugin) XMPPServer.getInstance().getPluginManager().getPlugin( "admin" ) ).isRestartNeeded();
pageContext.setAttribute( "restartNeeded", restartNeeded ); pageContext.setAttribute( "restartNeeded", restartNeeded );
boolean offerUpdateIssuer = false;
Map<String, String> signingRequests = new LinkedHashMap<String, String>();
%> %>
<html> <html>
...@@ -240,38 +238,19 @@ ...@@ -240,38 +238,19 @@
<c:set var="alias" value="${certificateEntry.key}"/> <c:set var="alias" value="${certificateEntry.key}"/>
<c:set var="identities" value="${admin:serverIdentities(certificateEntry.value)}"/> <c:set var="identities" value="${admin:serverIdentities(certificateEntry.value)}"/>
<% <%
// TODO restore this functionality String rowAlias = (String) pageContext.getAttribute("alias");
// int i = 0; X509Certificate certificate = (X509Certificate) pageContext.getAttribute("certificate");
// boolean offerUpdateIssuer = false;
// Map<String, String> signingRequests = new LinkedHashMap<String, String>(); boolean isSelfSigned = CertificateManager.isSelfSignedCertificate(certificate);
// if (keyStore != null && keyStore.aliases().hasMoreElements()) { boolean isSigningPending = CertificateManager.isSigningRequestPending(certificate);
// for (Enumeration aliases = keyStore.aliases(); aliases.hasMoreElements(); ) {
// i++; offerUpdateIssuer = offerUpdateIssuer || isSelfSigned || isSigningPending;
// String a = (String) aliases.nextElement();
// X509Certificate c = (X509Certificate) keyStore.getCertificate(a); if (isSigningPending) {
// StringBuffer identities = new StringBuffer(); // Generate new signing request for certificate
// for (String identity : CertificateManager.getServerIdentities(c)) { signingRequests.put(rowAlias, identityStore.generateCSR(rowAlias));
// identities.append(identity).append(", "); }
// }
// if (identities.length() > 0) {
// identities.setLength(identities.length() - 2);
// }
// // Self-signed certs are certs generated by Openfire whose IssueDN equals SubjectDN
// boolean isSelfSigned = CertificateManager.isSelfSignedCertificate(keyStore, a);
// // Signing Request pending = not self signed certs whose chain has only 1 cert (the same cert)
// boolean isSigningPending = CertificateManager.isSigningRequestPending(keyStore, a);
//
// offerUpdateIssuer = offerUpdateIssuer || isSelfSigned || isSigningPending;
// if (isSigningPending) {
// // Generate new signing request for certificate
// PrivateKey privKey = (PrivateKey) keyStore.getKey(a, sslConfig.getKeyStorePassword().toCharArray());
// if (privKey != null) {
// signingRequests.put(a, CertificateManager.createSigningRequest(c, privKey));
// }
// }
// pageContext.setAttribute("identities", identities);
// pageContext.setAttribute("alias", a);
// pageContext.setAttribute("certificate", c);
%> %>
<tr valign="top"> <tr valign="top">
<td> <td>
...@@ -300,30 +279,28 @@ ...@@ -300,30 +279,28 @@
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
</td> </td>
<%--<% if (isSelfSigned && !isSigningPending) { %>--%> <% if (isSelfSigned && !isSigningPending) { %>
<%--<td width="1%"><img src="images/certificate_warning-16x16.png" width="16" height="16" border="0"--%> <td width="1%"><img src="images/certificate_warning-16x16.png" width="16" height="16" border="0"
<%--alt="<fmt:message key="ssl.certificates.keystore.self-signed.info"/>"--%> alt="<fmt:message key="ssl.certificates.keystore.self-signed.info"/>"
<%--title="<fmt:message key="ssl.certificates.keystore.self-signed.info"/>"></td>--%> title="<fmt:message key="ssl.certificates.keystore.self-signed.info"/>"></td>
<%--<td width="1%" nowrap>--%> <td width="1%" nowrap>
<%--<fmt:message key="ssl.certificates.self-signed"/>--%> <fmt:message key="ssl.certificates.self-signed"/>
<%--</td>--%> </td>
<%--<% } else if (isSigningPending) { %>--%> <% } else if (isSigningPending) { %>
<%--<td width="1%"><img src="images/certificate_warning-16x16.png" width="16" height="16" border="0"--%> <td width="1%"><img src="images/certificate_warning-16x16.png" width="16" height="16" border="0"
<%--alt="<fmt:message key="ssl.certificates.keystore.signing-pending.info"/>"--%> alt="<fmt:message key="ssl.certificates.keystore.signing-pending.info"/>"
<%--title="<fmt:message key="ssl.certificates.keystore.signing-pending.info"/>"></td>--%> title="<fmt:message key="ssl.certificates.keystore.signing-pending.info"/>"></td>
<%--<td width="1%" nowrap>--%> <td width="1%" nowrap>
<%--<fmt:message key="ssl.certificates.signing-pending"/>--%> <fmt:message key="ssl.certificates.signing-pending"/>
<%--</td>--%> </td>
<%--<% } else { %>--%> <% } else { %>
<%--<td width="1%"><img src="images/certificate_ok-16x16.png" width="16" height="16" border="0"--%> <td width="1%"><img src="images/certificate_ok-16x16.png" width="16" height="16" border="0"
<%--alt="<fmt:message key="ssl.certificates.keystore.ca-signed.info"/>"--%> alt="<fmt:message key="ssl.certificates.keystore.ca-signed.info"/>"
<%--title="<fmt:message key="ssl.certificates.keystore.ca-signed.info"/>"></td>--%> title="<fmt:message key="ssl.certificates.keystore.ca-signed.info"/>"></td>
<%--<td width="1%" nowrap>--%> <td width="1%" nowrap>
<%--<fmt:message key="ssl.certificates.ca-signed"/>--%> <fmt:message key="ssl.certificates.ca-signed"/>
<%--</td>--%> </td>
<%--<% } %>--%> <% } %>
<td width="1%" nowrap><%-- Restore functionality above --%></td>
<td width="1%" nowrap><%-- Restore functionality above --%></td>
<td width="2%"> <td width="2%">
<c:out value="${certificate.publicKey.algorithm}"/> <c:out value="${certificate.publicKey.algorithm}"/>
</td> </td>
...@@ -334,85 +311,82 @@ ...@@ -334,85 +311,82 @@
><img src="images/delete-16x16.gif" width="16" height="16" border="0" alt=""></a> ><img src="images/delete-16x16.gif" width="16" height="16" border="0" alt=""></a>
</td> </td>
</tr> </tr>
<% if (isSigningPending) { %>
<form action="security-keystore.jsp?connectionType=${connectionType}" method="post">
<input type="hidden" name="importReply" value="true">
<input type="hidden" name="alias" value="${alias}">
<tr>
<td colspan="5">
<span class="jive-description">
<fmt:message key="ssl.certificates.truststore.ca-reply"/>
</span>
<textarea name="reply" rows="8" style="width:100%;font-size:8pt;" wrap="virtual"></textarea>
</td>
<td valign="bottom">
<input type="submit" name="install" value="<fmt:message key="global.save"/>">
</td>
</tr>
</form>
<% } %>
</c:forEach> </c:forEach>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
<%-- FIXME restore functionality below. --%>
<%--<% if (isSigningPending) { %>--%>
<%--<form action="security-keystore.jsp" method="post">--%>
<%--<input type="hidden" name="importReply" value="true">--%>
<%--<input type="hidden" name="alias" value="${alias}">--%>
<%--<input type="hidden" name="connectivityType" value="${connecticvityType}">--%>
<%--<tr id="pk<%=i%>">--%>
<%--<td colspan="5">--%>
<%--<span class="jive-description">--%>
<%--<fmt:message key="ssl.certificates.truststore.ca-reply"/>--%>
<%--</span>--%>
<%--<textarea name="reply" cols="40" rows="3" style="width:100%;font-size:8pt;" wrap="virtual"></textarea>--%>
<%--</td>--%>
<%--<td valign="bottom">--%>
<%--<input type="submit" name="install" value="<fmt:message key="global.save"/>">--%>
<%--</td>--%>
<%--</tr>--%>
<%--</form>--%>
</tbody> </tbody>
</table> </table>
<!-- END 'Installed Certificates' --> <!-- END 'Installed Certificates' -->
<!-- BEGIN 'Signing request' --> <!-- BEGIN 'Signing request' -->
<%-- FIXME restore functionality below. --%>
<% if (offerUpdateIssuer || !signingRequests.isEmpty()) { %>
<%--<% if (offerUpdateIssuer || !signingRequests.isEmpty()) { %>--%> <br>
<%--<br>--%>
<div class="jive-contentBoxHeader">
<%--<div class="jive-contentBoxHeader">--%> <fmt:message key="ssl.signing-request.title"/>
<%--<fmt:message key="ssl.signing-request.title"/>--%> </div>
<%--</div>--%> <div class="jive-contentBox">
<%--<div class="jive-contentBox">--%> <% if (offerUpdateIssuer) { %>
<%--<% if (offerUpdateIssuer) { %>--%> <p>
<%--<p>--%> <fmt:message key="ssl.signing-request.offer-issuer-information">
<%--<fmt:message key="ssl.signing-request.offer-issuer-information">--%> <fmt:param value="<a href='security-keystore-signing-request.jsp?connectionType=${connectionType}'>"/>
<%--<fmt:param value="<a href='ssl-signing-request.jsp?connectivityType=${connectivityType}'>"/>--%> <fmt:param value="</a>"/>
<%--<fmt:param value="</a>"/>--%> </fmt:message>
<%--</fmt:message>--%> </p>
<%--</p>--%> <% } %>
<%--<% } %>--%> <% if (!signingRequests.isEmpty()) { %>
<%--<% if (!signingRequests.isEmpty()) { %>--%> <p>
<%--<p>--%> <fmt:message key="ssl.signing-request.requests_info"/>
<%--<fmt:message key="ssl.signing-request.requests_info"/>--%> </p>
<%--</p>--%> <table cellpadding="3" cellspacing="2" border="0">
<%--<table cellpadding="3" cellspacing="2" border="0">--%> <thead>
<%--<thead>--%> <tr>
<%--<tr>--%> <th>
<%--<th>--%> <fmt:message key="ssl.signing-request.alias"/>
<%--<fmt:message key="ssl.signing-request.alias"/>--%> </th>
<%--</th>--%> <th>
<%--<th>--%> <fmt:message key="ssl.signing-request.signing-request"/>
<%--<fmt:message key="ssl.signing-request.signing-request"/>--%> </th>
<%--</th>--%> </tr>
<%--</tr>--%> </thead>
<%--</thead>--%> <tbody>
<%--<tbody>--%> <% for (Map.Entry<String, String> entry : signingRequests.entrySet()) { %>
<%--<% for (Map.Entry<String, String> entry : signingRequests.entrySet()) { %>--%> <tr>
<%--<tr>--%> <td valign="top">
<%--<td valign="top">--%> <%= entry.getKey() %>
<%--<%= entry.getKey() %>--%> </td>
<%--</td>--%> <td style="font-family: monospace;">
<%--<td style="font-family: monospace;">--%> <%= StringUtils.escapeHTMLTags(entry.getValue()) %>
<%--<%= StringUtils.escapeHTMLTags(entry.getValue()) %>--%> </td>
<%--</td>--%> </tr>
<%--</tr>--%> <% } %>
<%--<% } %>--%> </tbody>
<%--</tbody>--%> </table>
<%--</table>--%> <% } %>
<%--<% } %>--%> </div>
<%--</div>--%> <% } %>
<%--<% } %>--%> <!-- END 'Signing request' -->
<%--<!-- END 'Signing request' -->--%> <form action="/security-certificate-store-management.jsp">
<%--<form action="/security-certificate-store-management.jsp">--%> <input type="submit" name="done" value="<fmt:message key="global.done" />">
<%--<input type="submit" name="done" value="<fmt:message key="global.done" />">--%> </form>
<%--</form>--%>
</body> </body>
</html> </html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment