[Webfunds-commits] java/webfunds/sox SimpleIssuer.java SmartIssuer.java

Ian Grigg iang@cypherpunks.ai
Sun, 24 Sep 2000 19:49:19 -0400 (AST)


iang        00/09/24 19:49:19

  Modified:    webfunds/sox SimpleIssuer.java SmartIssuer.java
  Log:
  Worked through the startup sequence in order to reduce the number
  of spurious requests that go out, after seeing what a slow link
  did to current version of SOX.
  1.  documented the PKI approach in the certs requests.
  2.  wrapped each request in a method so that proper fall-back
      could be organised.
  3.  (big change) made SimpleIssuer persistant so that it kept
      hold of its time estimates and its unchanging certs even
      though it was experiencing failures.
  4.  changed SmartIssuer to restart SimpleIssuers in cycles,
      rather than reinstantiate them.
  5.  significantly widened the watermarks on time checks.  Only
      payments currently depend on these, and they really don't
      care if they are widened much.

Revision  Changes    Path
1.18      +115 -54   java/webfunds/sox/SimpleIssuer.java

Index: SimpleIssuer.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/SimpleIssuer.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- SimpleIssuer.java	2000/09/05 22:30:18	1.17
+++ SimpleIssuer.java	2000/09/24 23:49:18	1.18
@@ -1,5 +1,5 @@
 /*
- * $Id: SimpleIssuer.java,v 1.17 2000/09/05 22:30:18 gelderen Exp $
+ * $Id: SimpleIssuer.java,v 1.18 2000/09/24 23:49:18 iang Exp $
  *
  * Copyright (c) Systemics Ltd 1995-1999 on behalf of
  * the WebFunds Development Team.  All Rights Reserved.
@@ -46,28 +46,38 @@
     protected BasicAgent basicAgent;
 
     /**
-     * The primary certificate for the issuer.
-     * Not used?
+     *  The PKI is evolving...
+     *
+     *  The [operator] certificate is the high level key used by
+     *  the operator to sign and authenticate different servers
+     *  in his administrative domain.  It is infrequently used,
+     *  the [server] keys are delegated with the task of day-to-day
+     *  authentication of comms keys.
+     *
+     *  The [server] key is the key that each physical server has
+     *  in order to sign ephemeral (temporary, session) comms keys.
+     *  The client can expected the [server] key to be around for
+     *  many days, even months.  It is signed by the [operator] key.
+     *
+     *  Each session will request a comms key, which is made by the
+     *  lower-level key exchange protocol.  This comms key will be
+     *  authenticated by being signed by the [server] key.
+     *  The client can expect the comms key to be valid for at least
+     *  one request, and hopefully more, up to many hours worth.
      */
-    protected Certificate issuerCert = null;
+    protected Certificate signer = null;
 
-    /**
-     * The communications certificate (key) for the issuer.
-     */
+    /** The [server] certificate for this physical server.  */
+    protected Certificate serverCert = null;
+    /** The communications certificate (key) for this current session.  */
     protected PublicKey commsKey = null;
 
-    /**
-     * The operator's certificate, as found in the contract.
-     * This should be used to check that the server key returned
-     * from the SOX Server is signed.
-     * The PKI is evolving...
-     */
-    protected Certificate signer = null;
-
     protected int reqNo = 0;
 
 
 
+/////////  Instantiation  //////////////////////////////////////////
+
     /**
      * Create a new SimpleIssuer object
      * The SimpleIssuer object will normally be cached by the caller,
@@ -110,7 +120,9 @@
     public void getReady()
         throws SOXIssuerException, SOXLaterException
     {
-        checkSync();
+        // checkSync(); now on demand, not pre-emptive
+        if (isDead())
+            timesync();    // will set Alive if it works
     }
 
 
@@ -124,6 +136,9 @@
     }
 
 
+
+/////////  Keys and Certs  //////////////////////////////////////////
+
     /**
      * Fetch the current communications certificate for this issuer.
      * The certificate signatures are verified before assigning.
@@ -161,44 +176,19 @@
          */
         if( !commsCert.getType().equals("X.509") )
         {
-            Certificate serverCert;
-            try {
-                logmsg("Requesting serverCert...");
-                serverCert = basicAgent.getServerKey();
-                logmsg("Got a serverCert!" + serverCert);
-            } catch (SOXLaterException ex) {
-                setDead(ex.getMessage()); // URL is wrong or server is down
-                throw ex;
-            } catch (SOXPacketException ex) {
-                setDead(ex.getMessage());
-                throw new SOXIssuerException(ex.getNumber(),
-                                             "SOXPE 2: " + ex.getMessage());
-            } catch (SOXIssuerException ex) {
-                setDead(ex.getMessage());      // BA thinks info is wrong
-                throw ex ;
-            }
-
-            PublicKey signerKey = Crypto.getPublicKeyFromCert(signer);
-            logmsg("Verifying ServerCert is signed by Server CA certificate");
-            if (!Crypto.verifyCertificate(serverCert, signerKey)) {
-
-byte[] b = signerKey.getEncoded();
-PGPArmoury ok = new PGPArmoury(b, PGPArmoury.TYPE_PUBLIC_KEY);
-b = Crypto.getPublicKeyFromCert(serverCert).getEncoded();
-PGPArmoury sk = new PGPArmoury(b, PGPArmoury.TYPE_PUBLIC_KEY);
-logmsg(
-                    "serverCert (first) not signed by operator Cert (2nd)\n\n"+
-                    sk + "\n\n\n" + ok + "\n\n");
-
-                throw new SOXIssuerException(SOXException.SERVER_CERT,
-                    "serverCert not signed by operator Cert");
-            }
+            fetchServerCert();
 
             PublicKey serverKey = Crypto.getPublicKeyFromCert(serverCert);
             logmsg("Verifying CommsCert is signed by serverCert");
-            if (!Crypto.verifyCertificate(commsCert, serverKey)) {
-                throw new SOXIssuerException(SOXException.COMMS_CERT,
-                    "commsCert not signed by serverCert");
+            if (!Crypto.verifyCertificate(commsCert, serverKey))
+            {
+                String e = "commsCert not signed by serverCert";
+
+                serverCert = null;       // must have rolled over?
+                // fetchServerCert();    // do a retry on the ServerCert?
+                setDead(e);              // no, do a high level retry
+
+                throw new SOXIssuerException(SOXException.COMMS_CERT, e);
             }
             
             logmsg("Using comms key (valid signature by the issuer)");
@@ -209,6 +199,71 @@
     }
 
     /**
+     *  Fetch the current [server] certificate for this issuer.
+     *  
+     *  There is one [server] cert for each physical server (i.e.,
+     *  the server defined by this object.
+     *
+     *  The one [operator] key is used across the entire virtual server
+     *  (of many entry points, as described by the URLs in the
+     *  SOX Server File).
+     *
+     *  The certificate signatures are verified before assigning.
+     *
+     *  This won't do anything if [server] is already set.  If a
+     *  signature failure has occurred then set the key to null first.
+     */
+    protected void fetchServerCert()
+        throws SOXIssuerException, SOXLaterException
+    {
+        if (serverCert != null)
+            return;
+
+        logmsg("Requesting the SOX Server [server] certificate");
+
+        Certificate cert = null;
+        try {
+            cert = basicAgent.getServerKey();
+            logmsg("Got a cert!" + serverCert);
+        } catch (SOXLaterException ex) {
+            setDead(ex.getMessage());      // URL is wrong or server is down
+            throw ex ;
+        } catch (SOXPacketException ex) {  // what was this for?
+            setDead(ex.getMessage());
+            throw new SOXIssuerException(ex.getNumber(),
+                                         "SOXPE 2: " + ex.getMessage());
+        } catch (SOXIssuerException ex) {
+            setDead(ex.getMessage());      // BA thinks info is wrong
+            throw ex ;
+        }
+
+        PublicKey signerKey = Crypto.getPublicKeyFromCert(signer);
+        logmsg("Verifying ServerCert is signed by Server CA certificate");
+
+        if (!Crypto.verifyCertificate(cert, signerKey))
+        {
+            String e = "serverCert not signed by operator Cert";
+
+            byte[] b = signerKey.getEncoded();
+            PGPArmoury ok = new PGPArmoury(b, PGPArmoury.TYPE_PUBLIC_KEY);
+            b = Crypto.getPublicKeyFromCert(cert).getEncoded();
+            PGPArmoury sk = new PGPArmoury(b, PGPArmoury.TYPE_PUBLIC_KEY);
+            logmsg("serverCert (first) not signed by operator Cert (2nd)\n\n"+
+                   sk + "\n\n\n" + ok + "\n\n");
+
+            setDead(e);
+            throw new SOXIssuerException(SOXException.SERVER_CERT, e);
+        }
+
+        // Careful not to set this before validating the signature
+        serverCert = cert;
+    }
+
+
+
+/////////  Requests  //////////////////////////////////////////
+
+    /**
      * Issue a request.
      * Checks first to see if timesync is recent.
      * @except SOXIssuerException if this Issuer is dead, try another
@@ -216,7 +271,8 @@
     public byte[] request(Request request)
           throws SOXIssuerException, SOXLaterException
     {
-        checkSync();
+        // checkSync();  no, on demand, not pre-emptive
+
         return internalRequest(request);
     }
 
@@ -292,6 +348,8 @@
         EncryptedReply reply;
         reply = basicAgent.encryptedRequest(encReq);
 
+        setAlive();
+
         timeLastRequest = System.currentTimeMillis() - tim;
         logmsg(timeLastRequest + "ms only !");
         byte[] kkk = reply.decrypt(key);
@@ -301,6 +359,7 @@
 
 
 
+/////////  Time Syncronisation  //////////////////////////////////////////
     
     // if a fatal exception is found, set me as Dead, force user to re-invoke
     protected boolean      isDead       = false;
@@ -308,6 +367,7 @@
     public boolean         isDead()             { return isDead ; }
     public void            setDead()            { isDead = true ; }
     public void            setDead(String s)    { isDead = true; reason = s; }
+    public void            setAlive()           { isDead = false ; }
     public String          getDead()            { return reason; }
 
     /**
@@ -361,7 +421,7 @@
 
         TimeSyncReply reply;
         try {
-            reply = new TimeSyncReply(packet);
+            reply = new TimeSyncReply(tsr, packet);
         } catch (SOXPacketException ex) {
             setDead(ex.getMessage());
             throw new SOXIssuerException(ex.getNumber(),
@@ -401,12 +461,13 @@
         long timeNow = System.currentTimeMillis();
         if (timeNow - lastsync > 24 * HOUR)
             timesync();
-        else if (deviation > SECOND)
+        else if (deviation > 10 * SECOND)
             timesync();
     }
 
 
 
+/////////  Misc / Debug  //////////////////////////////////////////
 
     public String toString()
     {



1.15      +59 -26    java/webfunds/sox/SmartIssuer.java

Index: SmartIssuer.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/SmartIssuer.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- SmartIssuer.java	2000/09/05 18:21:53	1.14
+++ SmartIssuer.java	2000/09/24 23:49:18	1.15
@@ -1,5 +1,5 @@
 /*
- * $Id: SmartIssuer.java,v 1.14 2000/09/05 18:21:53 iang Exp $
+ * $Id: SmartIssuer.java,v 1.15 2000/09/24 23:49:18 iang Exp $
  *
  * Copyright (c) Systemics Ltd 1995-1999 on behalf of
  * the WebFunds Development Team.  All Rights Reserved.
@@ -20,11 +20,13 @@
 import webfunds.utils.RawURLException;
 
 /**
- * Make out like an Issuer.
- * Hold a bunch of URLs, invoke issuers on them on demand,
- * and switch whenever a problem is detected.
+ *  Pretend to be a single SOX Server "Issuer", but actually manage through
+ *  a list of equivalent entry points into the same virtual server.
+ *  Hold a bunch of URLs, invoke objects on them on demand, and
+ *  switch whenever a problem is detected.
  *
- * @version 1.3
+ *  Name needs to change away from Issuer which is more oriented to money
+ *  issuance than SOX Service.
  */
 public class SmartIssuer
     extends Debug  implements Issuer, IssuerFinder
@@ -33,7 +35,7 @@
     protected Vector       others;
     protected int          which;
     protected int          size;
-    protected Certificate     cert;
+    protected Certificate  cert;
 
     /**
      * Create a new Issuer object
@@ -42,14 +44,19 @@
      * This call is passive, call getReady() to cause action.
      *
      * @param name our name for the issuer
-     * @param signer the certificate which signs this issuers certificate
+     * @param signer the [operator] certificate which signs the
+     *               server's [server] certificate
      * @param agent the comms agent that sends requests at the transport layer
      */
-    public SmartIssuer(String[] rawUrls, Certificate serverCert, PrintWriter bug)
+    public SmartIssuer(String[] rawUrls, Certificate operCert, PrintWriter bug)
         throws SOXIssuerException
     {
         debug(bug, "        I  ");
 
+        which = 0;
+        this.cert = operCert;
+        others = null;
+
         if (rawUrls.length == 0)
             throw new SOXIssuerException("no servers listed");
 
@@ -58,11 +65,9 @@
         if (size == 0)
             throw new SOXIssuerException("all URLs are malformed!");
 
-        which = 0;
-        this.cert = serverCert;
-        others = null;
+        startSimpleServers(urls);
 
-        logmsg("SmartIssuer(" + size + " urls, serverCert, bug);");
+        logmsg("SmartIssuer(" + size + " urls, operCert, bug);");
     }
 
     /**
@@ -103,7 +108,28 @@
     public Issuer getIssuer(ItemId id) { id = null; return (Issuer)this ; }
 
     protected SimpleIssuer current  = null;
+    protected SimpleIssuer[] servers = null;
+
+    /**
+     * Do the things necessary for being ready for a request.
+     * On return, current is set to a hopefully valid Issuer.
+     */
+    public void startSimpleServers(Vector urls)
+    {
+        int siz = urls.size();
+        servers = new SimpleIssuer[siz];
+        for (int i = 0; i < siz; i++)
+        {
+            URL url = (URL)urls.elementAt(which % siz);
+            logmsg("new Simple at " + url);
 
+            HttpAgent http = new HttpAgent(url, true, getDebug());
+            SimpleIssuer simp = new SimpleIssuer(""+i, cert, http, getDebug());
+
+            servers[i] = simp;
+        }
+    }
+
     /**
      * Do the things necessary for being ready for a request.
      * On return, current is set to a hopefully valid Issuer.
@@ -133,26 +159,22 @@
         int failures = 0;
         int laters   = 0;
 
-        int guard = which + urls.size();     // record where we stop
+        int guard = which + servers.length;     // record where we stop
 
         while (which++ < guard)
         {
-            url = (URL)urls.elementAt(which % urls.size());
-            logmsg("new Simple at " + url);
-
-            http = new HttpAgent(url, true, getDebug());
-            simp = new SimpleIssuer(""+which, cert, http, getDebug());
+            simp = servers[which % servers.length];
 
-            logmsg(which + ": " + url);
+            logmsg(which + ": " + simp);
             try {
                 simp.getReady();
             } catch (SOXLaterException ex) {
                 laters++;
-                logmsg(url + " : later?");
+                logmsg(simp + " : later?");
                 continue ;
             } catch (SOXIssuerException ex) {
                 failures++;
-                logmsg(url + " : dead!  " + ex);
+                logmsg(simp + " : dead!  " + ex);
                 continue ;
             }
 
@@ -160,7 +182,7 @@
             if (!simp.isDead())               // found a good one
             {
                 current = simp;
-                checkTimes();
+                // checkTimes();
                 logmsg("times " + timediff + " / " + deviation);
                 return ;
             }
@@ -191,12 +213,14 @@
     public byte[] request(Request req)
         throws SOXLaterException, SOXIssuerException
     {
-        int guard = which + 2 * urls.size();     // record where we stop
+        int guard = which + 2 * servers.length;     // record where we stop
         int failures = 0;
         int laters   = 0;
         while (which < guard)
         {
-            getReady();
+            if (current.isDead())
+                getReady();
+
             byte[] b;
             try {
                 b = current.request(req);
@@ -207,7 +231,7 @@
                 failures++;
                 continue ;
             }
-            checkTimes();
+            // checkTimes();
             return b ;
         }
 
@@ -308,11 +332,20 @@
     protected long timediff = 0;
     protected long deviation = 24 * SimpleIssuer.HOUR;
 
-    public long getTimeDifference() { return timediff ; }
+    public long getTimeDifference() { checkTimes(); return timediff ; }
     public long getTimeDeviation()  { return deviation ; }
 
     protected void checkTimes()
     {
+        if (!current.isDead())
+        {
+            try {
+                current.checkSync();
+            } catch (SOXException ex) {
+                logmsg("checkTimes: (ignoring) current throws " + ex);
+                return ;
+            }
+        }
         timediff = current.getTimeDifference();
         deviation = current.getTimeDeviation();
     }