public static String createSigningRequest(X509Certificate cert, PrivateKey privKey) throws OperatorCreationException, IOException, CertificateParsingException
    {
        JcaPKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder( //
                cert.getSubjectX500Principal(), //
                cert.getPublicKey() //
                );

        // Add SubjectAlternativeNames (SANs)
        final ASN1EncodableVector subjectAlternativeNames = new ASN1EncodableVector();

        final Collection<List<?>> certSans = cert.getSubjectAlternativeNames();
        if ( certSans != null )
        {
            for ( final List<?> certSan : certSans )
            {
                final int nameType = (Integer) certSan.get( 0 );
                final Object value = certSan.get( 1 ); // this is either a string, or a byte-array that represents the ASN.1 DER encoded form.
                switch ( nameType )
                {
                    case 0:
                        // OtherName: search for "id-on-xmppAddr" or 'sRVName' or 'userPrincipalName'
                        try ( final ASN1InputStream decoder = new ASN1InputStream( (byte[]) value ) )
                        {
                            // By specification, OtherName instances must always be an ASN.1 Sequence.
                            final ASN1Primitive object = decoder.readObject();
                            final ASN1Sequence otherNameSeq = (ASN1Sequence) object;

                            // By specification, an OtherName instance consists of:
                            // - the type-id (which is an Object Identifier), followed by:
                            // - a tagged value, of which the tag number is 0 (zero) and the value is defined by the type-id.
                            final ASN1ObjectIdentifier typeId = (ASN1ObjectIdentifier) otherNameSeq.getObjectAt( 0 );
                            final ASN1TaggedObject taggedValue = (ASN1TaggedObject) otherNameSeq.getObjectAt( 1 );

                            final int tagNo = taggedValue.getTagNo();
                            if ( tagNo != 0 )
                            {
                                throw new IllegalArgumentException( "subjectAltName 'otherName' sequence's second object is expected to be a tagged value of which the tag number is 0. The tag number that was detected: " + tagNo );
                            }
                            subjectAlternativeNames.add(
                                new DERTaggedObject( false,
                                                     GeneralName.otherName,
                                                     new DERSequence(
                                                         new ASN1Encodable[] {
                                                             typeId,
                                                             taggedValue
                                                         }
                                                     )
                                )
                            );
                        }
                        catch ( Exception e )
                        {
                            Log.warn( "Unable to parse certificate SAN 'otherName' value", e );
                        }
                        break;
                    case 2:
                        // DNS
                        subjectAlternativeNames.add( new GeneralName( GeneralName.dNSName, (String) value ) );
                        break;
                    case 6:
                        // URI
                        subjectAlternativeNames.add( new GeneralName( GeneralName.uniformResourceIdentifier, (String) value ) );
                        break;
                    default:
                        // Not applicable to XMPP, so silently ignore them
                        break;
                }

            }
        }

        final GeneralNames subjectAltNames = GeneralNames.getInstance(
            new DERSequence( subjectAlternativeNames )
        );

        final ExtensionsGenerator extGen = new ExtensionsGenerator();
        extGen.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
        csrBuilder.addAttribute( PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());

        String signatureAlgorithm = "SHA256WITH" + cert.getPublicKey().getAlgorithm();

        ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithm).build(privKey);
        PKCS10CertificationRequest csr = csrBuilder.build(signer);

        StringWriter string = new StringWriter();
        PemWriter pemWriter = new PemWriter(string);

        PemObjectGenerator objGen = new MiscPEMGenerator(csr);
        pemWriter.writeObject(objGen);
        pemWriter.close();

        return string.toString();
    }
Creates and returns the content of a new singing request for the specified certificate. Signing
requests are required by Certificate Authorities as part of their signing process. The signing request
contains information about the certificate issuer, subject DN, subject alternative names and public key.
Private keys are not included. After the Certificate Authority verified and signed the certificate a new
certificate is going to be returned.

@param cert the certificate to create a signing request.
@param privKey the private key of the certificate.
@return the content of a new singing request for the specified certificate.
@throws OperatorCreationException if there was a problem creating the CSR
@throws IOException if there was a problem creating the CSR
@throws CertificateParsingException if there was a problem creating the CSR
xmppserver/src/main/java/org/jivesoftware/util/CertificateManager.java