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
final String name = JiveGlobals.getProperty( "xmpp.domain" ).toLowerCase();
final String alias = name + "_" + algorithm.toLowerCase();
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 );
// Generate public and private keys
......@@ -464,7 +466,7 @@ public class IdentityStore extends CertificateStore
final KeyPair keyPair = generateKeyPair( algorithm.toUpperCase(), keySize );
// 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.setKeyEntry( alias, keyPair.getPrivate(), configuration.getPassword(), new X509Certificate[]{cert} );
......
......@@ -47,6 +47,10 @@ import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.io.pem.PemObjectGenerator;
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.CertificateUtils;
import org.jivesoftware.util.cert.CNCertificateIdentityMapping;
......@@ -443,6 +447,13 @@ public class CertificateManager {
String subjectCommonName, String domain,
String signAlgoritm)
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
X500NameBuilder subjectBuilder = new X500NameBuilder();
......@@ -452,7 +463,7 @@ public class CertificateManager {
X500NameBuilder issuerBuilder = new X500NameBuilder();
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 {
* @throws IOException
*/
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();
PrivateKey privKey = kp.getPrivate();
......@@ -492,18 +509,11 @@ public class CertificateManager {
pubKey //
);
// add subjectAlternativeName extension
boolean critical = subjectDN.getRDNs().length == 0;
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);
// add subjectAlternativeName extension that includes all relevant names.
final GeneralNames subjectAlternativeNames = getSubjectAlternativeNames( sanDnsNames, sanXmppAddrs );
GeneralNames subjectAltNames = GeneralNames.getInstance( new DERSequence( othernameGN ) );
certBuilder.addExtension(Extension.subjectAlternativeName, critical, subjectAltNames);
final boolean critical = subjectDN.getRDNs().length == 0;
certBuilder.addExtension(Extension.subjectAlternativeName, critical, subjectAlternativeNames);
// add keyIdentifiers extensions
JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils();
......@@ -532,4 +542,80 @@ public class CertificateManager {
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 @@
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ 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="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
......@@ -114,7 +116,9 @@
int days = 60;
// 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 });
}
}
......
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