BigBastis Blog

Java: SubjectDN eines X509Zertifikates zu OpenSSL kompatibel machen

Introduction

user

Sebastian Gross

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.


LATEST POSTS

Handling too long scrollspy menus 10th June, 2015

Java: Create ZIP archive 23rd March, 2015

Java

Java: SubjectDN eines X509Zertifikates zu OpenSSL kompatibel machen

Posted on .

Java stellt uns zum angenehmen Arbeiten mit X509-Zertifikaten die Klasse java.security.cert.X509Certificate zur Verfügung. Hier können wir uns sehr einfach über die methode .getSubjectDN().getName() den Distinguished Name des Zertifikats besorgen.

Wenn man in der Javawelt bleibt ist das auch alles ok und funktioniert Problemlos. Will man aber andere Programme wie zum Beispiel OpenSSL anbinden, bekommt man hier ein Problem, denn OpenSSL liefert einen anderen SubjectDN String als unsere Java Klasse.

Wobei mit anders meine ich, dass die Reihenfolge der ausgegebenen Parameter anders ist, hier ein Beispiel:

Ausgabe von OpenSSL (über die X509_NAME_oneline Methode):

/C=DE/ST=NRW/L=Bielefeld/O=ORG/OU=AB1/CN=130.122.146.121

Wogegen die Java-Klasse folgenden String liefert (.getSubjectDN().getName()) :

CN=130.122.146.121, OU=AB1, O=ORG, L=Bielefeld, ST=NRW, C=DE

Die Reihenfolge scheint genau umgekehrt zu sein und auch die Trenner sind anders, und wenn man den String nun als Auth-String benutzen will bekommt man ein Problem.

Leider bietet uns Java hier keine Möglichkeit den String anders zu sortieren, man kann zwar über die Methode getSubjectX500Principal.getName(String format) einen RFC als Parameter mitgeben, welcher die Sortierung etwas anpasst, aber teilweise noch komischere Ergebnisse liefert.

Hier bleibt einem nun leider nichts anderes übrig, als selbst einzugreifen und die Sortierung selbst vorzunehmen. Dazu habe ich eine kleine Klasse geschrieben die das für euch erledigt. Diese hat zwei Methoden, eine die einen OpenSSL Kompatiblen String ausgibt und eine bei der ihr die Reihenfolge der Parameter selbst bestimmen könnt:

 

/**
 * Teilt die Informationen aus dem X509Certificate.SubjectDN in die
 * einzelnen Bestandteile auf und macht diese einzeln verfügbar
 * @author sebastian gross blog.bigbasti.com
 */
public class CertificateDataSeperator {

    private String _C = "";
    private String _ST = "";
    private String _L = "";
    private String _O = "";
    private String _OU = "";
    private String _CN = "";
    private String _EMAILADRESS = "";

    /**
     * Erstellt eine neue instanz
     * @param cert Das Zwetifikat aus dem die Daten gelesen werden sollen
     * @param seperator Die Zeichenfolge ander die parameter
     *        getrennt werden sollen, bei Java ist Standard ", "
     */
    public CertificateDataSeperator(X509Certificate cert, String seperator){
        String [] subjectDNData;

        subjectDNData = cert.getSubjectDN().getName().split(seperator);

        seperateData(subjectDNData);
    }

    /**
     * Duchläuft das Array und ordnet die Informationen
     * @param data Array mit dem SubjectDN String
     */
    private void seperateData(String [] data){
        for(String s : data){
            if((s.toUpperCase()).startsWith("C=")){
                _C = s;
            }else if((s.toUpperCase()).startsWith("ST=")){
                _ST = s;
            }else if((s.toUpperCase()).startsWith("L=")){
                _L = s;
            }else if((s.toUpperCase()).startsWith("O=")){
                _O = s;
            }else if((s.toUpperCase()).startsWith("OU=")){
                _OU = s;
            }else if((s.toUpperCase()).startsWith("CN=")){
                _CN = s;
            }else if((s.toUpperCase()).startsWith("EMAILADRESS=")){
                _EMAILADRESS = s;
            }
        }
    }

    /**
     * Generiert einen angepassten SubjectDN String
     * @param params Die gewünschten Werte in der gewünschten Reihenfolge als Array
     * @param seperator Die Zeichenfolge, die zum Trennen der Parameter genutzt werden soll
     * @return Einen angepassten SubjectDN String
     */
    public String getNewDNString(String [] params, String seperator){
        StringBuilder sb = new StringBuilder();

        for(String s : params){
            if((s.toUpperCase()).equals("C")){
                sb.append(_C);
            }else if((s.toUpperCase()).equals("ST")){
                sb.append(_ST);
            }else if((s.toUpperCase()).equals("L")){
                sb.append(_L);
            }else if((s.toUpperCase()).equals("O")){
                sb.append(_O);
            }else if((s.toUpperCase()).equals("OU")){
                sb.append(_OU);
            }else if((s.toUpperCase()).equals("CN")){
                sb.append(_CN);
            }else if((s.toUpperCase()).equals("EMAILADRESS")){
                sb.append(_EMAILADRESS);
            }

            if(!s.equals(params[params.length-1])){
                sb.append(seperator);
            }
        }

        return sb.toString();
    }

    /**
     * Erzeugt einen DN String in dem Format, wie ihn auch die
     * X509_NAME_oneline Methode von OpenSSL generiert, dies ist
     * auch das Format, welches von dem Exim Email Server genutzt wird.
     * Das Forman ist wiefolgt: /C=$/ST=$/L=$/O=$/OU=$/CN=$
     * @return OpenSSL
     */
    public String getOpenSSLCompatibleDNString(){
        StringBuilder sb = new StringBuilder();

        sb.append("/").append(_C).append("/").append(_ST).append("/").append(_L).append("/")
          .append(_O).append("/").append(_OU).append("/").append(_CN);

        //EMAILADRESS Ist ein optionales Feld und könnte nicht gesetzt sein
        if(_EMAILADRESS != null){
            sb.append("/").append(_EMAILADRESS);
        }

        return sb.toString();
    }

    public String getC() {
        return _C;
    }

    public String getCN() {
        return _CN;
    }

    public String getEMAILADRESS() {
        return _EMAILADRESS;
    }

    public String getL() {
        return _L;
    }

    public String getO() {
        return _O;
    }

    public String getOU() {
        return _OU;
    }

    public String getST() {
        return _ST;
    }
}

Mit dieser kleinen Klasse ist es sehr einfach einen OpenSSL kompatiblen SubjectDN zu erhalten:

X509Certificate myCert = session.getClientCertificate();
CertificateDataSeperator sep = new CertificateDataSeperator(myCert, ", ");
String dn = sep.getOpenSSLCompatibleDNString();

Wenn man selbst die Reihenfolge der parameter bestimmen will kann man das z.B. so machen:

X509Certificate myCert = session.getClientCertificate();
String [] myParams = new String[]{"O", "CN", "L"};
CertificateDataSeperator sep = new CertificateDataSeperator(myCert, ", ");
String dn = sep.getNewDNString(myParams, "|");

Nun soll erst O, dann CN und zum Schluss L ausgegeben, jeweils von einem | (pipe) getrennt.

Das Ganze lässt sich natürlich je nach verwendeten optionalen SSL Parametern noch beliebig erweitern, und ist eine einfache und schnelle Methode um den SubjectDN neu zu sortieren.

profile

Sebastian Gross

http://www.bigbasti.com

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.

There are no comments.

Kommentar verfassen

View Comments (0) ...
Navigation