package org.fnppl.opensdx.security; /* * Copyright (C) 2010-2015 * fine people e.V. <opensdx@fnppl.org> * Henning Thieß <ht@fnppl.org> * * http://fnppl.org */ /* * Software license * * As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied. * * This file is part of openSDX * openSDX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * openSDX is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * and GNU General Public License along with openSDX. * If not, see <http://www.gnu.org/licenses/>. * */ /* * Documentation license * * As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied. * * This file is part of openSDX. * Permission is granted to copy, distribute and/or modify this document * under the terms of the GNU Free Documentation License, Version 1.3 * or any later version published by the Free Software Foundation; * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. * A copy of the license is included in the section entitled "GNU * Free Documentation License" resp. in the file called "FDL.txt". * */ import java.io.*; import java.math.BigInteger; import java.net.*; import java.util.*; import org.fnppl.opensdx.http.HTTPClient; import org.fnppl.opensdx.http.HTTPClientRequest; import org.fnppl.opensdx.http.HTTPClientResponse; import org.fnppl.opensdx.security.*; import org.fnppl.opensdx.tsaserver.*; import org.fnppl.opensdx.xml.*; public class KeyClient extends HTTPClient { public static int OSDX_KEYSERVER_DEFAULT_PORT = 8889; public final static String ERROR_WRONG_RESPONE_FORMAT = "ERROR: Wrong format in keyserver's response."; private String prepath; private KeyVerificator keyverificator = null; public KeyClient(String host, int port, String prepath, KeyVerificator keyverificator) { super(host, port); this.prepath = prepath; this.keyverificator = keyverificator; if (DEBUG) log = System.out; } public KeyClient(KeyServerIdentity keyserver, KeyVerificator keyverificator) { super(keyserver.getHost(), keyserver.getPort()); this.prepath = keyserver.getPrepath(); this.keyverificator = keyverificator; if (DEBUG) log = System.out; } public void setKeyVerificator(KeyVerificator keyverificator) { this.keyverificator = keyverificator; } // 1. Ich, als fremder user, möchte beim keyserver (z.B. keys.fnppl.org) den/die (MASTER) pubkey(s) zu der identity thiess@finetunes.net suchen können public Vector<String> requestMasterPubKeys(final String idemail) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestMasterPubKeys(host, prepath, idemail); HTTPClientResponse resp = send(req); writeLog(req, resp, "MASTERPUBKEY"); OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.MASTERPUBKEYS_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Vector<String> ret = new Vector<String>(); Element er = content.getChild("related_keys"); if (er!=null) { Vector<Element> keyids = er.getChildren("keyid"); for (Element k : keyids) { ret.add(k.getText()); } } return ret; } else { message = result.errorMessage; return null; } } public MasterKey requestMasterPubKey(final String keyid) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestMasterPubKey(host, prepath, keyid); HTTPClientResponse resp = send(req); writeLog(req, resp, "SUBKEYS MASTERPUBKEY"); OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.MASTERPUBKEY_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Element key = content.getChild("pubkey"); OSDXKey pubkey = OSDXKey.fromPubKeyElement(key); pubkey.addDataSourceStep(new DataSourceStep(host, System.currentTimeMillis())); if (pubkey instanceof MasterKey) return (MasterKey)pubkey; message = "resulted key is not a MASTER key"; return null; } else { message = result.errorMessage; return null; } } // public Vector<OSDXKey> requestPubKeys(final String idemail) throws Exception { // OSDXKeyServerClientRequest req = OSDXKeyServerClientRequest.getRequestPubKeys(host, idemail); // OSDXKeyServerClientResponse resp = send(req); // // Element e = resp.doc.getRootElement(); // if (!e.getName().equals("pubkeys")) { // throw new RuntimeException("ERROR: Wrong format in keyserver's response"); // } // Vector<OSDXKey> ret = new Vector<OSDXKey>(); // Vector<Element> pks = e.getChildren("keypair"); // for (Element pk : pks) { // OSDXKey key = OSDXKey.fromElement(pk); // ret.add(key); // } // return ret; // } public KeyServerIdentity requestKeyServerIdentity() throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestKeyServerIdentity(host, prepath); HTTPClientResponse resp = send(req); writeLog(req, resp, "KEYSERVER IDENTITY"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignaturesWithoutKeyVerification(); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.KEYSERVER_SETTINGS_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } try { KeyServerIdentity id = KeyServerIdentity.fromElement(content); return id; } catch (Exception ex) { message = "error in keyserver response"; return null; } } else { message = result.errorMessage; return null; } } //2. Ich, als fremder user, möchte beim keyserver die weiteren identities (identity-details) zu einem pubkey bekommen können public Vector<Identity> requestIdentities(String keyid, OSDXKey signingKey) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestIdentities(host, prepath, keyid, signingKey); HTTPClientResponse resp = send(req); writeLog(req, resp, "IDENTITIES"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.IDENTITIES_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Vector<Identity> ret = new Vector<Identity>(); Vector<Element> eid = content.getChildren("identity"); for (Element id : eid) { ret.add(Identity.fromElement(id)); } return ret; } else { message = result.errorMessage; return null; } } public Identity requestCurrentIdentity(String keyid, OSDXKey signingKey) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestIdentities(host, prepath, keyid, signingKey); HTTPClientResponse resp = send(req); writeLog(req, resp, "IDENTITY"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.IDENTITIES_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Vector<Element> eid = content.getChildren("identity"); if (eid.size()>0) { return (Identity.fromElement(eid.get(0))); } return null; } else { message = result.errorMessage; return null; } } //3. Ich, als fremder user, möchte beim keyserver den aktuellen (beim keyserver bekannten) status zu einem pubkey bekommen können (valid/revoked/etc.) public KeyStatus requestKeyStatus(String keyid) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestKeyStatus(host, prepath, keyid); HTTPClientResponse resp = send(req); writeLog(req, resp, "KEYSTATUS"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.KEYSTATUS_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Element eks = content.getChild("keystatus"); if (eks != null) { KeyStatus ks = KeyStatus.fromElement(eks); return ks; } return null; } else { message = result.errorMessage; return null; } } //4. Ich, als fremder user, möchte beim keyserver die keylogs eines (beliebigen) pubkeys bekommen können public Vector<KeyLog> requestKeyLogs(String keyid, OSDXKey sign) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestKeyLogs(host, prepath, keyid, sign); HTTPClientResponse resp = send(req); writeLog(req, resp, "KeyLogs"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.KEYLOGS_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Vector<Element> ekls = content.getChildren("keylog"); Vector<KeyLog> vkl = new Vector<KeyLog>(); for (Element ekl : ekls) { KeyLog kl = KeyLog.fromElement(ekl); vkl.add(kl); } return vkl; } else { message = result.errorMessage; return null; } } //5. Ich, als fremder user, möchte beim keyserver die weiteren pubkeys zu einem parent-pubkey (MASTER) bekommen können public Vector<String> requestSubKeys(String masterkeyid) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestSubkeys(host, prepath, masterkeyid); HTTPClientResponse resp = send(req); writeLog(req, resp, "SubKeys"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.SUBKEYS_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Vector<String> ret = new Vector<String>(); Vector<Element> keyids = content.getChildren("keyid"); for (Element k : keyids) { ret.add(k.getText()); } return ret; } else { message = result.errorMessage; return null; } } public OSDXKey requestPublicKey(String keyid) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildRequestPublicKey(host, prepath, keyid); HTTPClientResponse resp = send(req); writeLog(req, resp, "PublicKey"); if (resp==null || resp.status == null) { message = ERROR_NO_RESPONSE; return null; } OSDXMessage msg = OSDXMessage.fromElement(resp.doc.getRootElement()); Result result = msg.verifySignatures(keyverificator); if (result.succeeded) { Element content = msg.getContent(); if (!content.getName().equals(KeyClientMessageFactory.PUBLICKEY_RESPONSE)) { message = ERROR_WRONG_RESPONE_FORMAT; return null; } Element key = content.getChild("pubkey"); OSDXKey pubkey = OSDXKey.fromPubKeyElement(key); pubkey.addDataSourceStep(new DataSourceStep(host, System.currentTimeMillis())); return pubkey; } else { message = result.errorMessage; return null; } } // 1. Ich, als user, möchte auf dem keyserver meinen MASTER-pubkey ablegen können // includes 2. Ich, als user, möchte, daß der keyserver meinen MASTER-pubkey per email-verifikation (der haupt-identity) akzeptiert (sonst ist der status pending oder so -> erst, wenn die email mit irgendeinem token-link drin aktiviert wurde, wird der pubkey akzeptiert) public boolean putMasterKey(MasterKey masterkey, Identity id) throws Exception { try { HTTPClientRequest req = KeyClientMessageFactory.buildPutRequestMasterKey(host, prepath, masterkey, id); HTTPClientResponse resp = send(req); writeLog(req, resp, "PUT MasterKey"); return checkResponse(resp); } catch (Exception ex) { ex.printStackTrace(); message = ex.getMessage(); } return false; } //3. Ich, als user, möchte auf dem keyserver meinen REVOKE-key für meinen master-key abspeichern können (der sollte sogar nicht sichtbar für irgendwen sonst sein!!!) public boolean putRevokeKey(RevokeKey revokekey, MasterKey relatedMasterKey) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildPutRequestRevokeKey(host, prepath, revokekey, relatedMasterKey); HTTPClientResponse resp = send(req); writeLog(req, resp, "PUT RevokeKey"); return checkResponse(resp); } public boolean putRevokeMasterKeyRequest(RevokeKey revokekey, MasterKey relatedMasterKey, String message) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildPutRequestRevokeMasterKey(host, prepath, revokekey, relatedMasterKey, message); HTTPClientResponse resp = send(req); writeLog(req, resp, "PUT Revoke-MasterKey"); return checkResponse(resp); } public boolean putSubKey(SubKey subkey, MasterKey relatedMasterKey) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildPutRequestSubKey(host, prepath, subkey, relatedMasterKey); HTTPClientResponse resp = send(req); writeLog(req, resp, "PUT SubKey"); return checkResponse(resp); } public boolean putRevokeSubKeyRequest(SubKey subkey, MasterKey relatedMasterKey, String message) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.buildPutRequestRevokeSubKey(host, prepath, subkey, relatedMasterKey, message); HTTPClientResponse resp = send(req); writeLog(req, resp, "Revoke SubKey"); return checkResponse(resp); } // 5. Ich, als user, möchte meine keylogs auf dem server ablegen können (ein löschen von keylogs ist NICHT möglich - für einen aktuellen status ist die "kette ist chronologisch abzuarbeiten") public boolean putKeyLogAction(KeyLogAction keylogAction, OSDXKey signingKey) throws Exception { Vector<KeyLogAction> keylogActions = new Vector<KeyLogAction>(); keylogActions.add(keylogAction); return putKeyLogActions(keylogActions, signingKey); } public boolean putKeyLogActions(Vector<KeyLogAction> keylogActions, OSDXKey signingKey) throws Exception { HTTPClientRequest req = KeyClientMessageFactory.getPutRequestKeyLogs(host, prepath, keylogActions, signingKey); HTTPClientResponse resp = send(req); writeLog(req, resp, "PUT KeyLogs"); return checkResponse(resp); } // 4. Ich, als user, möchte eigentlich, daß alle meine Aktionen auf meinem MASTER-key - bzw. allen meiner keys durch einen entsprechenden signature-proof des entsprechenden private-keys validierbar sind // 6. Ich, als user, möchte alle kommunikation vom/zum keyserver mit einem vom keyserver definierten root-MASTER-key approveden key signiert wissen // 7. Ich, als user, möchte diese keyserver-root-keys vordefiniert in meiner openSDX-suite finden, aber auch simpelst selbst nachrüsten können public static void main(String[] args) throws Exception { // OSDXKeyServerClient c = new OSDXKeyServerClient("localhost", 8889); // Vector<PublicKey> keys = c.requestMasterPubKeys("test@fnppl.org"); // for (PublicKey k : keys) { // System.out.println("public key: "+k.getKeyID()); // } // Vector<Identity> ids = c.requestIdentities("7610FF13E234ED7694333FF67F312E0DEA45AC99"); // for (Identity id : ids) { // System.out.println("identity email: "+id.getEmail()); // } // Vector<KeyLog> keylogs = c.requestKeyLogs("85D9EB452CA5CD270CA9EC73724ACDAC9E6A6281@LOCAL"); // System.out.println("received "+keylogs.size()+" keylogs"); // Vector<PublicKey> keys = c.requestSubKeys("85D9EB452CA5CD270CA9EC73724ACDAC9E6A6281@LOCAL"); // for (PublicKey k : keys) { // System.out.println("public sub key: "+k.getKeyID()); // } // AsymmetricKeyPair kp = AsymmetricKeyPair.generateAsymmetricKeyPair(); // OSDXKey key = OSDXKey.fromKeyPair(kp); // Identity id = Identity.newEmptyIdentity(); // id.setEmail("test@fnppl.org"); // boolean ok = c.putMasterKey(key.getPubKey(), id); // System.out.println("put master key: "+(ok?"OK":"FAILED")); // String[] status = c.requestKeyStatus("C930CEEF52E4D6808A4253AC2C0EF5F6E578C603"); // System.out.println("key status: "+status[0]+" from date: "+status[1]); // boolean ok2 = c.putRevokeKey(key.getPubKey(), key); // System.out.println("put revoke key: "+(ok2?"OK":"FAILED")); } }