public synchronized void addSelfSignedDomainCertificate() throws CertificateStoreConfigException
    {
        String algorithm = JiveGlobals.getProperty( "cert.algorithm", "RSA" );

        final int keySize;
        final String signAlgorithm;
        switch (algorithm.toUpperCase()) {
            case "RSA" -> {
                keySize = JiveGlobals.getIntProperty("cert.rsa.keysize", 2048);
                signAlgorithm = JiveGlobals.getProperty("cert.rsa.algorithm", "SHA256WITHRSAENCRYPTION");
            }
            case "DSA" -> {
                keySize = JiveGlobals.getIntProperty("cert.dsa.keysize", 1024);
                signAlgorithm = JiveGlobals.getProperty("cert.dsa.algorithm", "SHA256withDSA");
            }
            default ->
                throw new IllegalArgumentException("Unsupported algorithm '" + algorithm + "'. Use 'RSA' or 'DSA'.");
        }

        final String name = XMPPServerInfo.XMPP_DOMAIN.getValue().toLowerCase();
        final String alias = name + "_" + algorithm.toLowerCase();
        final int validityInDays = JiveGlobals.getIntProperty( "cert.validity-days", 5*365 );
        Set<String> sanDnsNames = CertificateManager.determineSubjectAlternateNameDnsNameValues();

        // OF-1605: Check if a wildcard entry is to be used to represent/replace any subdomains of the XMPP domain name.
        final boolean useWildcard = JiveGlobals.getBooleanProperty( "cert.wildcard", true );
        if ( useWildcard )
        {
            final String wildcard = "*." + XMPPServer.getInstance().getServerInfo().getXMPPDomain();

            // Remove any names that match the wildcard.
            sanDnsNames = sanDnsNames.stream()
                .filter( sanDnsName -> !DNSUtil.isNameCoveredByPattern( sanDnsName, wildcard )  )
                .collect( Collectors.toSet() );

            // Add the domain and wildcard entries.
            sanDnsNames.add( XMPPServer.getInstance().getServerInfo().getXMPPDomain() );
            sanDnsNames.add( wildcard );
        }

        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
        try
        {
            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, sanDnsNames );

            // Store new certificate and private key in the key store
            store.setKeyEntry( alias, keyPair.getPrivate(), configuration.getPassword(), new X509Certificate[]{cert} );

            // Persist the changes in the store to disk.
            persist();
        }
        catch ( CertificateStoreConfigException | IOException | GeneralSecurityException ex )
        {
            reload(); // reset state of the store.
            throw new CertificateStoreConfigException( "Unable to generate new self-signed " + algorithm + " certificate.", ex );
        }

        // TODO Notify listeners that a new certificate has been created
    }
Populates the key store with a self-signed certificate for the domain of this XMPP service.

@throws CertificateStoreConfigException if a self-signed certificate could not be created
xmppserver/src/main/java/org/jivesoftware/openfire/keystore/IdentityStore.java