Commit 6a0b9f59 authored by Guus der Kinderen's avatar Guus der Kinderen

OF-1495: Add server identities to Subject Alternative Name extension of cert

parent 4b98b442
...@@ -456,6 +456,8 @@ public class IdentityStore extends CertificateStore ...@@ -456,6 +456,8 @@ 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 int validityInDays = 5*365; final int validityInDays = 5*365;
final Set<String> sanDnsNames = CertificateManager.determineSubjectAlternateNameDnsNameValues();
final Set<String> sanXmppAddrs = CertificateManager.determineSubjectAlternateNameXmppAddrValues();
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
...@@ -464,7 +466,7 @@ public class IdentityStore extends CertificateStore ...@@ -464,7 +466,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, name, name, name, signAlgorithm ); final X509Certificate cert = CertificateManager.createX509V3Certificate( keyPair, validityInDays, name, name, name, signAlgorithm, sanDnsNames, sanXmppAddrs );
// 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} );
......
...@@ -47,6 +47,10 @@ import org.bouncycastle.pkcs.PKCSException; ...@@ -47,6 +47,10 @@ import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.io.pem.PemObjectGenerator; import org.bouncycastle.util.io.pem.PemObjectGenerator;
import org.bouncycastle.util.io.pem.PemWriter; import org.bouncycastle.util.io.pem.PemWriter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.disco.DiscoItem;
import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider;
import org.jivesoftware.openfire.keystore.CertificateStore; import org.jivesoftware.openfire.keystore.CertificateStore;
import org.jivesoftware.openfire.keystore.CertificateUtils; import org.jivesoftware.openfire.keystore.CertificateUtils;
import org.jivesoftware.util.cert.CNCertificateIdentityMapping; import org.jivesoftware.util.cert.CNCertificateIdentityMapping;
...@@ -443,6 +447,13 @@ public class CertificateManager { ...@@ -443,6 +447,13 @@ public class CertificateManager {
String subjectCommonName, String domain, String subjectCommonName, String domain,
String signAlgoritm) String signAlgoritm)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
return createX509V3Certificate( kp, days, issuerCommonName, subjectCommonName, domain, signAlgoritm, null, null );
}
public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int days, String issuerCommonName,
String subjectCommonName, String domain,
String signAlgoritm, Set<String> sanDnsNames, Set<String> sanXmppAddrs)
throws GeneralSecurityException, IOException {
// subjectDN // subjectDN
X500NameBuilder subjectBuilder = new X500NameBuilder(); X500NameBuilder subjectBuilder = new X500NameBuilder();
...@@ -452,7 +463,7 @@ public class CertificateManager { ...@@ -452,7 +463,7 @@ public class CertificateManager {
X500NameBuilder issuerBuilder = new X500NameBuilder(); X500NameBuilder issuerBuilder = new X500NameBuilder();
issuerBuilder.addRDN(BCStyle.CN, issuerCommonName); issuerBuilder.addRDN(BCStyle.CN, issuerCommonName);
return createX509V3Certificate(kp, days, issuerBuilder, subjectBuilder, domain, signAlgoritm); return createX509V3Certificate(kp, days, issuerBuilder, subjectBuilder, domain, signAlgoritm, sanDnsNames, sanXmppAddrs);
} }
/** /**
...@@ -469,7 +480,13 @@ public class CertificateManager { ...@@ -469,7 +480,13 @@ public class CertificateManager {
* @throws IOException * @throws IOException
*/ */
public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int days, X500NameBuilder issuerBuilder, public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int days, X500NameBuilder issuerBuilder,
X500NameBuilder subjectBuilder, String domain, String signAlgoritm) throws GeneralSecurityException, IOException { X500NameBuilder subjectBuilder, String domain, String signAlgoritm ) throws GeneralSecurityException, IOException
{
return createX509V3Certificate( kp, days, issuerBuilder, subjectBuilder, domain, signAlgoritm, null, null );
}
public static synchronized X509Certificate createX509V3Certificate(KeyPair kp, int days, X500NameBuilder issuerBuilder,
X500NameBuilder subjectBuilder, String domain, String signAlgoritm, Set<String> sanDnsNames, Set<String> sanXmppAddrs ) throws GeneralSecurityException, IOException {
PublicKey pubKey = kp.getPublic(); PublicKey pubKey = kp.getPublic();
PrivateKey privKey = kp.getPrivate(); PrivateKey privKey = kp.getPrivate();
...@@ -492,18 +509,11 @@ public class CertificateManager { ...@@ -492,18 +509,11 @@ public class CertificateManager {
pubKey // pubKey //
); );
// add subjectAlternativeName extension // add subjectAlternativeName extension that includes all relevant names.
boolean critical = subjectDN.getRDNs().length == 0; final GeneralNames subjectAlternativeNames = getSubjectAlternativeNames( sanDnsNames, sanXmppAddrs );
ASN1Sequence othernameSequence = new DERSequence(
new ASN1Encodable[] {
new ASN1ObjectIdentifier("1.3.6.1.5.5.7.8.5"),
new DERTaggedObject( true, GeneralName.otherName, new DERUTF8String( domain ) )
}
);
DERTaggedObject othernameGN = new DERTaggedObject(false, GeneralName.otherName, othernameSequence);
GeneralNames subjectAltNames = GeneralNames.getInstance( new DERSequence( othernameGN ) ); final boolean critical = subjectDN.getRDNs().length == 0;
certBuilder.addExtension(Extension.subjectAlternativeName, critical, subjectAltNames); certBuilder.addExtension(Extension.subjectAlternativeName, critical, subjectAlternativeNames);
// add keyIdentifiers extensions // add keyIdentifiers extensions
JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils(); JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils();
...@@ -532,4 +542,80 @@ public class CertificateManager { ...@@ -532,4 +542,80 @@ public class CertificateManager {
throw new GeneralSecurityException(e); throw new GeneralSecurityException(e);
} }
} }
protected static GeneralNames getSubjectAlternativeNames( Set<String> sanDnsNames, Set<String> sanXmppAddrs )
{
final ASN1EncodableVector subjectAlternativeNames = new ASN1EncodableVector();
if ( sanDnsNames != null )
{
for ( final String dnsNameValue : sanDnsNames )
{
subjectAlternativeNames.add(
new GeneralName( GeneralName.dNSName, dnsNameValue )
);
}
}
if ( sanXmppAddrs != null )
{
for ( final String xmppAddrValue : sanXmppAddrs )
{
subjectAlternativeNames.add(
new DERTaggedObject( false,
GeneralName.otherName,
new DERSequence(
new ASN1Encodable[] {
new ASN1ObjectIdentifier( "1.3.6.1.5.5.7.8.5" ),
new DERTaggedObject( true, GeneralName.otherName, new DERUTF8String( xmppAddrValue ) )
}
)
)
);
}
}
return GeneralNames.getInstance(
new DERSequence( subjectAlternativeNames )
);
}
/**
* Finds all values that aught to be added as a Subject Alternate Name of the dnsName type to a certificate that
* identifies this XMPP server.
*
* @return A set of names, possibly empty, never null.
*/
public static Set<String> determineSubjectAlternateNameDnsNameValues()
{
final HashSet<String> result = new HashSet<>();
// The fully qualified domain name of the server
result.add( XMPPServer.getInstance().getServerInfo().getHostname() );
return result;
}
/**
* Finds all values that aught to be added as a Subject Alternate Name of the dnsName type to a certificate that
* identifies this XMPP server.
*
* @return A set of names, possibly empty, never null.
*/
public static Set<String> determineSubjectAlternateNameXmppAddrValues()
{
final HashSet<String> result = new HashSet<>();
// Add the XMPP domain name itself.
result.add( XMPPServer.getInstance().getServerInfo().getXMPPDomain() );
if ( XMPPServer.getInstance().getIQDiscoItemsHandler() != null ) // When we're not in setup any longer...
{
// Add the name of each of the domain level item nodes as reported by service discovery.
for ( final DiscoItem item : XMPPServer.getInstance().getIQDiscoItemsHandler().getServerItems() )
{
result.add( item.getJID().toBareJID() );
}
}
return result;
}
} }
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
<%@ page import="java.util.HashMap" %> <%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %> <%@ page import="java.util.Map" %>
<%@ page import="org.jivesoftware.openfire.spi.ConnectionType" %> <%@ page import="org.jivesoftware.openfire.spi.ConnectionType" %>
<%@ page import="org.jivesoftware.openfire.keystore.CertificateUtils" %>
<%@ page import="java.util.Set" %>
<%@ taglib uri="admin" prefix="admin" %> <%@ taglib uri="admin" prefix="admin" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
...@@ -114,7 +116,9 @@ ...@@ -114,7 +116,9 @@
int days = 60; int days = 60;
// Regenerate self-sign certs whose subjectDN matches the issuerDN and set the new issuerDN // Regenerate self-sign certs whose subjectDN matches the issuerDN and set the new issuerDN
X509Certificate newCertificate = CertificateManager.createX509V3Certificate(new KeyPair(pubKey, privKey), days, builder, builder, domain, signAlgoritm); final Set<String> sanDnsNames = CertificateManager.determineSubjectAlternateNameDnsNameValues();
final Set<String> sanXmppAddrs = CertificateManager.determineSubjectAlternateNameXmppAddrValues();
X509Certificate newCertificate = CertificateManager.createX509V3Certificate(new KeyPair(pubKey, privKey), days, builder, builder, domain, signAlgoritm, sanDnsNames, sanXmppAddrs);
keyStore.setKeyEntry(alias, privKey, identityStore.getConfiguration().getPassword(), new X509Certificate[] { newCertificate }); keyStore.setKeyEntry(alias, privKey, identityStore.getConfiguration().getPassword(), new X509Certificate[] { newCertificate });
} }
} }
......
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