Any comments? It's a fair chunk of code but it would avoid the need to include 
sun.* private classes which currently prevent the node from being built on 
GCJ, while still having the ability to create SSL certificates for encrypted 
HTTP/FCP/etc.
-------------- next part --------------
Index: D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateSubjectName.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateSubjectName.java   
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateSubjectName.java   
(revision 0)
@@ -0,0 +1,24 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.cert;
+
+/**
+ * SubjectName is the same as issuer name for self signed certificate
+ */
+public class CertificateSubjectName extends CertificateIssuerName {
+
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateAlgorithmId.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateAlgorithmId.java   
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateAlgorithmId.java   
(revision 0)
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import freenet.crypt.der.DerOutputStream;
+import freenet.crypt.der.DerValue;
+
+public class CertificateAlgorithmId {
+    /**
+     * Encode the certificate algorithm id in DER form to the stream.
+     *
+     * @param out the OutputStream to marshal the contents to.
+     * @exception IOException on errors.
+     */
+    public static void encode(OutputStream out) throws IOException {
+       int[] components = {1, 2, 840, 10040, 4, 3}; // SHA1withDSA
+       DerOutputStream bytes = new DerOutputStream();
+       DerOutputStream tmp = new DerOutputStream();
+       bytes.putOID(components);
+       // rfc3370 3.1: When the id-dsa-with-sha1 algorithm identifier 
+        // is used, the AlgorithmIdentifier parameters field MUST be absent.
+           bytes.putNull();
+           tmp.write(DerValue.tag_Sequence, bytes);
+       out.write(tmp.toByteArray());
+    }
+    
+
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateVersion.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateVersion.java       
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateVersion.java       
(revision 0)
@@ -0,0 +1,43 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.cert;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import freenet.crypt.der.DerOutputStream;
+import freenet.crypt.der.DerValue;
+
+public class CertificateVersion {
+    /**
+     * Encode the certificate version in DER form to the stream.
+     *
+     * @param out the OutputStream to marshal the contents to.
+     * @exception IOException on errors.
+     */
+    public static void encode(OutputStream out) throws IOException {
+        DerOutputStream tmp = new DerOutputStream();
+        tmp.putInteger(BigInteger.valueOf(2)); // V3
+
+        DerOutputStream seq = new DerOutputStream();
+        seq.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0), 
tmp);
+
+        out.write(seq.toByteArray());
+    }
+
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateValidity.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateValidity.java      
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateValidity.java      
(revision 0)
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.cert;
+
+import java.io.IOException;
+import java.util.Date;
+
+import freenet.crypt.der.DerOutputStream;
+import freenet.crypt.der.DerValue;
+
+public class CertificateValidity {
+
+    private static final long YR_2050 = 2524636800000L;
+    
+    /**
+     * Encode the validity in DER form to the stream.
+     *
+     * @param out the OutputStream to marshal the contents to.
+     * @exception IOException on errors.
+     */
+    public static void encode(DerOutputStream out, long validity) throws 
IOException {
+           Date notBefore = new Date();
+           Date notAfter = new Date (notBefore.getTime() + validity);
+        DerOutputStream tmp = new DerOutputStream();
+
+        if (notBefore.getTime() < YR_2050) {
+               tmp.putUTCTime(notBefore);
+        } else
+               tmp.putGeneralizedTime(notBefore);
+
+        if (notAfter.getTime() < YR_2050) {
+               tmp.putUTCTime(notAfter);
+        } else {
+               tmp.putGeneralizedTime(notAfter);
+        }
+        out.write(DerValue.tag_Sequence, tmp);
+    }
+}
Index: D:/Project/Freenet 
0.7/src/freenet/crypt/cert/CertificateSerialNumber.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateSerialNumber.java  
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateSerialNumber.java  
(revision 0)
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Date;
+
+import freenet.crypt.der.DerOutputStream;
+
+public class CertificateSerialNumber {
+    /**
+     * Encode the certificate serial number in DER form to the stream.
+     *
+     * @param out the OutputStream to marshal the contents to.
+     * @exception IOException on errors.
+     */
+    public static void encode(OutputStream out) throws IOException {
+       Date date = new Date();
+       DerOutputStream tmp = new DerOutputStream();
+        tmp.putInteger(BigInteger.valueOf(date.getTime()/1000));
+
+        out.write(tmp.toByteArray());
+    }
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateIssuerName.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateIssuerName.java    
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/cert/CertificateIssuerName.java    
(revision 0)
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.cert;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import freenet.crypt.der.DerOutputStream;
+import freenet.crypt.der.DerValue;
+
+public class CertificateIssuerName {
+    /**
+     * Encode the issuer name in DER form to the stream.
+     *
+     * @param out the OutputStream to marshal the contents to.
+     * @exception IOException on errors.
+     */
+    public static void encode(DerOutputStream out) throws IOException {
+       DerOutputStream tmpRDNs = new DerOutputStream();
+       DerOutputStream tmpATAV;
+       DerOutputStream tmp;
+       // Country
+        // Get default locale
+        int[] countryOID = {2, 5, 4, 6};
+       Locale locale = Locale.getDefault();
+       tmp = new DerOutputStream();
+        tmp.putOID(countryOID);
+       tmp.putUTF8String(locale.getCountry());
+       tmpATAV = new DerOutputStream();
+       tmpATAV.write(DerValue.tag_Sequence, tmp);
+        tmpRDNs.write(DerValue.tag_Set, tmpATAV);
+       // OrgName
+        int[] orgName = {2, 5, 4, 10};
+       tmp = new DerOutputStream();
+        tmp.putOID(orgName);
+       tmp.putUTF8String("Freenet");
+       tmpATAV = new DerOutputStream();
+       tmpATAV.write(DerValue.tag_Sequence, tmp);
+        tmpRDNs.write(DerValue.tag_Set, tmpATAV);
+       // OrgUnitName
+        int[] orgUnitName = {2, 5, 4, 11};
+       tmp = new DerOutputStream();
+        tmp.putOID(orgUnitName);
+       tmp.putUTF8String("Freenet");
+       tmpATAV = new DerOutputStream();
+       tmpATAV.write(DerValue.tag_Sequence, tmp);
+        tmpRDNs.write(DerValue.tag_Set, tmpATAV);
+       // CommonName
+        int[] commonName = {2, 5, 4, 3};
+       tmp = new DerOutputStream();
+        tmp.putOID(commonName);
+       tmp.putUTF8String("Freenet");
+       tmpATAV = new DerOutputStream();
+       tmpATAV.write(DerValue.tag_Sequence, tmp);
+        tmpRDNs.write(DerValue.tag_Set, tmpATAV);
+       
+       out.write(DerValue.tag_Sequence, tmpRDNs);
+    }
+
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/der/DerOutputStream.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/der/DerOutputStream.java   
(revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/der/DerOutputStream.java   
(revision 0)
@@ -0,0 +1,259 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.der;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class DerOutputStream extends ByteArrayOutputStream {
+    /**
+     * Construct an DER output stream.
+     *
+     * @param size how large a buffer to preallocate.
+     */
+    public DerOutputStream(int size) {
+       super(size);
+    }
+
+    /**
+     * Construct an DER output stream.
+     */
+    public DerOutputStream() {
+       
+    }
+
+    /*
+     * Notice it needs to emit in big-endian form, so it buffers the output
+     * until it's ready.(Minimum length encoding is a DER requirement.)
+     */
+    private static void putComponent (DerOutputStream out, int val) throws 
IOException {
+               int     i;
+        // TODO: val must be <128*128*128*128 here, otherwise, 4 bytes is not
+        // enough to hold it. Will address this later.
+               byte    buf [] = new byte [4] ;
+       
+               for (i = 0; i < 4; i++) {
+                   buf[i] = (byte)(val & 0x07f);
+                   val >>>= 7;
+                   if (val == 0)
+                       break;
+               }
+               for ( ; i > 0; --i) {
+                   out.write(buf [i] | 0x080);
+               }
+               out.write (buf [0]);
+    }
+
+    /**
+     * Put a DER bit string on the output stream. The bit
+     * string must be byte-aligned.
+     *
+     * @param bits the bit string, MSB first
+     */
+    public void putBitString(byte[] bits) throws IOException {
+        write(DerValue.tag_BitString);
+        putLength(bits.length + 1);
+        write(0);               // all of last octet is used
+        write(bits);
+    }
+
+    /**
+     * Put  integer on the DER output stream.
+     *
+     * @param i the integer in the form of a BigInteger.
+     */
+    public void putInteger(BigInteger i) throws IOException {
+       write(DerValue.tag_Integer);
+       byte[] buf = i.toByteArray(); // least number  of bytes
+        putLength(buf.length);
+        write(buf, 0, buf.length);
+    }
+
+    /**
+     * Put the encoding of the length in the stream.
+     *   
+     * @params len the length of the attribute.
+     * @exception IOException on writing errors.
+     */  
+    public void putLength(int len) throws IOException {
+               if (len < 128) {
+                   write((byte)len);
+       
+               } else if (len < (1 << 8)) {
+                   write((byte)0x081);
+                   write((byte)len);
+       
+               } else if (len < (1 << 16)) {
+                   write((byte)0x082);
+                   write((byte)(len >> 8));
+                   write((byte)len);
+       
+               } else if (len < (1 << 24)) {
+                   write((byte)0x083);
+                   write((byte)(len >> 16));
+                   write((byte)(len >> 8));
+                   write((byte)len);
+       
+               } else {
+                   write((byte)0x084);
+                   write((byte)(len >> 24));
+                   write((byte)(len >> 16));
+                   write((byte)(len >> 8));
+                   write((byte)len);
+               }
+    }
+
+    /**
+     * Put a DER "null" value on the output stream.  These are
+     * often used to indicate optional values which have been omitted.
+     */
+    public void putNull() throws IOException {
+               write(DerValue.tag_Null);
+               putLength(0);
+    }
+
+    /**
+     * Marshals an object identifier (OID) on the output stream.
+     * Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct.
+     */
+    public void putOID(int[] components) throws IOException {
+       DerOutputStream tmpOID = new DerOutputStream ();
+       int i;
+        // According to ISO X.660, when the 1st component is 0 or 1, the 2nd 
+        // component is restricted to be less than or equal to 39, thus make
+        // it small enough to be encoded into one single byte.
+        if (components[0] < 2) {
+               tmpOID.write((components [0] * 40) + components[1]);
+        } else {
+            putComponent(tmpOID, (components[0] * 40) + components[1]);
+        }
+       for (i = 2; i < components.length; i++) {
+           putComponent(tmpOID, components[i]);
+       }
+       write(DerValue.tag_ObjectId, tmpOID);
+    }
+
+    /**
+     * Put the tag of the attribute in the stream.
+     *   
+     * @params class the tag class type, one of UNIVERSAL, CONTEXT, 
APPLICATION or PRIVATE
+     * @params form if true, the value is constructed, otherwise it is 
primitive.
+     * @params val the tag value
+     */  
+    public void putTag(byte tagClass, boolean form, byte val) {
+        byte tag = (byte)(tagClass | val);
+        if (form) {
+            tag |= (byte)0x20;
+        }
+        write(tag);
+    }
+
+    /**
+     * Put a DER UTC time/date value.
+     *
+     * <P>YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time
+     * and with seconds (even if seconds=0) as per RFC 3280.
+     */
+    public void putUTCTime(Date d) throws IOException {
+        putTime(d, DerValue.tag_UtcTime);
+    }
+
+    /**
+     * Put a DER Generalized Time/date value.
+     *
+     * <P>YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time
+     * and with seconds (even if seconds=0) as per RFC 3280.
+     */
+    public void putGeneralizedTime(Date d) throws IOException {
+        putTime(d, DerValue.tag_GeneralizedTime);
+    }
+
+    /**
+     * Private helper routine for marshalling a DER UTC/Generalized
+     * time/date value. If the tag specified is not that for UTC Time
+     * then it defaults to Generalized Time.
+     * @param d the date to be marshalled
+     * @param tag the tag for UTC Time or Generalized Time
+     */
+    private void putTime(Date d, byte tag) throws IOException {
+        /*
+         * Format the date.
+         */
+        TimeZone tz = TimeZone.getTimeZone("GMT");
+        String pattern = null;
+        if (tag == DerValue.tag_UtcTime) {
+            pattern = "yyMMddHHmmss'Z'";
+        } else {
+            tag = DerValue.tag_GeneralizedTime;
+            pattern = "yyyyMMddHHmmss'Z'";
+        }
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        sdf.setTimeZone(tz);
+        byte[] time = (sdf.format(d)).getBytes("ISO-8859-1");
+        /*
+         * Write the formatted date.
+         */
+        write(tag);
+        putLength(time.length);
+        write(time);
+    }
+
+    /**
+     * Put a string as a DER encoded UTF8String.
+     */
+    public void putUTF8String(String s) throws IOException {
+        byte[] data = s.getBytes("UTF8");
+        write(DerValue.tag_UTF8String);
+        putLength(data.length);
+        write(data);
+    }
+
+    /**
+     * Writes tagged, pre-marshaled data.  This calcuates and encodes
+     * the length, so that the output data is the standard triple of
+     * { tag, length, data } used by all DER values.
+     *
+     * @param tag the DER value tag for the data, such as
+     *         <em>DerValue.tag_Sequence</em>
+     * @param buf buffered data, which must be DER-encoded 
+     */
+    public void write(byte tag, byte[] buf) throws IOException {
+               write(tag);
+               putLength(buf.length);
+               write(buf, 0, buf.length);
+    }
+
+    /**
+     * Writes tagged data using buffer-to-buffer copy.  As above,
+     * this writes a standard DER record.  This is often used when
+     * efficiently encapsulating values in sequences.
+     *
+     * @param tag the DER value tag for the data, such as
+     *         <em>DerValue.tag_Sequence</em>
+     * @param out buffered data
+     */
+    public void write(byte tag, DerOutputStream out) throws IOException {
+               write(tag);
+               putLength(out.count);
+               write(out.buf, 0, out.count);
+    }
+
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/der/DerValue.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/der/DerValue.java  (revision 0)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/der/DerValue.java  (revision 0)
@@ -0,0 +1,115 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.crypt.der;
+
+public class DerValue {
+    /** The tag class types */
+    public static final byte TAG_UNIVERSAL = (byte)0x000;
+    public static final byte TAG_APPLICATION = (byte)0x040;
+    public static final byte TAG_CONTEXT = (byte)0x080;
+    public static final byte TAG_PRIVATE = (byte)0x0c0;
+
+    /** Tag value indicating an ASN.1 "BOOLEAN" value. */
+    public final static byte   tag_Boolean = 0x01;
+
+    /** Tag value indicating an ASN.1 "INTEGER" value. */
+    public final static byte   tag_Integer = 0x02;
+
+    /** Tag value indicating an ASN.1 "BIT STRING" value. */
+    public final static byte   tag_BitString = 0x03;
+
+    /** Tag value indicating an ASN.1 "OCTET STRING" value. */
+    public final static byte   tag_OctetString = 0x04;
+
+    /** Tag value indicating an ASN.1 "NULL" value. */
+    public final static byte   tag_Null = 0x05;
+
+    /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */
+    public final static byte   tag_ObjectId = 0x06;
+
+    /** Tag value including an ASN.1 "ENUMERATED" value */
+    public final static byte   tag_Enumerated = 0x0A;
+
+    /** Tag value indicating an ASN.1 "UTF8String" value. */
+    public final static byte    tag_UTF8String = 0x0C;
+
+    /** Tag value including a "printable" string */
+    public final static byte   tag_PrintableString = 0x13;
+
+    /** Tag value including a "teletype" string */
+    public final static byte   tag_T61String = 0x14;
+
+    /** Tag value including an ASCII string */
+    public final static byte   tag_IA5String = 0x16;
+
+    /** Tag value indicating an ASN.1 "UTCTime" value. */
+    public final static byte   tag_UtcTime = 0x17;
+
+    /** Tag value indicating an ASN.1 "GeneralizedTime" value. */
+    public final static byte   tag_GeneralizedTime = 0x18;
+
+    /** Tag value indicating an ASN.1 "GenerallString" value. */
+    public final static byte    tag_GeneralString = 0x1B;
+
+    /** Tag value indicating an ASN.1 "UniversalString" value. */
+    public final static byte    tag_UniversalString = 0x1C;
+
+    /** Tag value indicating an ASN.1 "BMPString" value. */
+    public final static byte    tag_BMPString = 0x1E;
+
+    // CONSTRUCTED seq/set
+
+    /** 
+     * Tag value indicating an ASN.1
+     * "SEQUENCE" (zero to N elements, order is significant). 
+     */
+    public final static byte   tag_Sequence = 0x30;
+
+    /**
+     * Tag value indicating an ASN.1
+     * "SEQUENCE OF" (one to N elements, order is significant).
+     */
+    public final static byte   tag_SequenceOf = 0x30;
+
+    /** 
+     * Tag value indicating an ASN.1
+     * "SET" (zero to N members, order does not matter).
+     */
+    public final static byte   tag_Set = 0x31;
+
+    /** 
+     * Tag value indicating an ASN.1
+     * "SET OF" (one to N members, order does not matter).
+     */
+    public final static byte   tag_SetOf = 0x31;
+
+    /**
+     * Create the tag of the attribute.
+     *
+     * @params class the tag class type, one of UNIVERSAL, CONTEXT, 
APPLICATION or PRIVATE
+     * @params form if true, the value is constructed, otherwise it is 
primitive.
+     * @params val the tag value
+     */
+    public static byte createTag(byte tagClass, boolean form, byte val) {
+        byte tag = (byte)(tagClass | val);
+        if (form) {
+            tag |= (byte)0x20;
+        }
+        return (tag);
+    }
+
+}
Index: D:/Project/Freenet 0.7/src/freenet/crypt/SSL.java
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/crypt/SSL.java   (revision 17168)
+++ D:/Project/Freenet 0.7/src/freenet/crypt/SSL.java   (working copy)
@@ -16,39 +16,61 @@

 package freenet.crypt;

+import java.io.ByteArrayInputStream;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.ServerSocket;
+import java.security.InvalidKeyException;
 import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
 import java.security.KeyStore;
-import java.security.PrivateKey;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
 import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
 import javax.net.ServerSocketFactory;
 import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.SSLContext;

 import freenet.config.InvalidConfigValueException;
 import freenet.config.SubConfig;
+import freenet.crypt.cert.CertificateAlgorithmId;
+import freenet.crypt.cert.CertificateIssuerName;
+import freenet.crypt.cert.CertificateSerialNumber;
+import freenet.crypt.cert.CertificateSubjectName;
+import freenet.crypt.cert.CertificateValidity;
+import freenet.crypt.cert.CertificateVersion;
+import freenet.crypt.der.DerOutputStream;
+import freenet.crypt.der.DerValue;
 import freenet.support.Logger;
 import freenet.support.api.BooleanCallback;
 import freenet.support.api.StringCallback;

-import sun.security.x509.X500Name;
-import sun.security.x509.CertAndKeyGen;
-
 public class SSL {

+       private static final long ONE_YEAR = 31536000000L;
+
        private static boolean enable;
        private static KeyStore keystore;
+       private static KeyStore truststore;
        private static ServerSocketFactory ssf;
        private static String keyStore;
+       private static String trustStore;
        private static String keyStorePass;
+       private static String trustStorePass;
        private static String keyPass;
        private static String version;
-
+       
        private SSL() {

        }
@@ -81,15 +103,20 @@
                                                if(enable) {
                                                        try {
                                                                loadKeyStore();
+                                                               
loadTrustStore();
                                                        createSSLContext();
                                                        } catch (Exception e) {
+                                                               
e.printStackTrace(System.out);
                                                                enable = false;
-                                                               
e.printStackTrace(System.out);
+                                                               ssf = null;
+                                                               keyStore = null;
+                                                               trustStore = 
null;
                                                        throw new 
InvalidConfigValueException("Cannot enabled ssl, config error");
                                                        }
                                                } else {
                                                        ssf = null;
                                                        keyStore = null;
+                                                       trustStore = null;
                                                }
                                        }
                                }
@@ -106,12 +133,19 @@
                                        if (!newKeyStore.equals(get())) {
                                                String oldKeyStore = keyStore;
                                                keyStore = newKeyStore;
-                                               try {
-                                                       loadKeyStore();
-                                               } catch (Exception e) {
-                                                       keyStore = oldKeyStore;
-                                                       
e.printStackTrace(System.out);
-                                               throw new 
InvalidConfigValueException("Cannot change keystore file");
+                                               if(enable) {
+                                                       try {
+                                                               loadKeyStore();
+                                                       } catch (Exception e) {
+                                                               
e.printStackTrace(System.out);
+                                                               keyStore = 
oldKeyStore;
+                                                               try {
+                                                                       
loadKeyStore();
+                                                               } catch 
(Exception e1) {
+                                                                       // 
ignore
+                                                               }
+                                                       throw new 
InvalidConfigValueException("Cannot change keystore file");
+                                                       }
                                                }
                                        }
                                }
@@ -128,13 +162,15 @@
                                        if (!newKeyStorePass.equals(get())) {
                                                String oldKeyStorePass = 
keyStorePass;
                                                keyStorePass = newKeyStorePass;
-                                       try {
-                                               storeKeyStore();
-                                       } catch (Exception e) {
-                                               keyStorePass = oldKeyStorePass;
-                                                       
e.printStackTrace(System.out);
-                                               throw new 
InvalidConfigValueException("Cannot change keystore password");
-                                       }
+                                               if(enable) {
+                                                       try {
+                                                       storeKeyStore();
+                                               } catch (Exception e) {
+                                                       
e.printStackTrace(System.out);
+                                                       keyStorePass = 
oldKeyStorePass;
+                                                       throw new 
InvalidConfigValueException("Cannot change keystore password");
+                                               }
+                                               }
                                        }
                                }
                        }
@@ -150,15 +186,17 @@
                                        if (!newKeyPass.equals(get())) {
                                                String oldKeyPass = keyPass;
                                                keyPass = newKeyPass;
-                                               try {
-                                                       Certificate[] chain = 
keystore.getCertificateChain("freenet");
-                                                       Key privKey = 
keystore.getKey("freenet", oldKeyPass.toCharArray());
-                                               keystore.setKeyEntry("freenet", 
privKey, keyPass.toCharArray(), chain);
-                                               createSSLContext();
-                                               } catch (Exception e) {
-                                                       keyPass = oldKeyPass;
-                                                       
e.printStackTrace(System.out);
-                                               throw new 
InvalidConfigValueException("Cannot change private key password");
+                                               if(enable) {
+                                                       try {
+                                                               Certificate[] 
chain = keystore.getCertificateChain("freenet");
+                                                               Key privKey = 
keystore.getKey("freenet", oldKeyPass.toCharArray());
+                                                       
keystore.setKeyEntry("freenet", privKey, keyPass.toCharArray(), chain);
+                                                       createSSLContext();
+                                                       } catch (Exception e) {
+                                                               
e.printStackTrace(System.out);
+                                                               keyPass = 
oldKeyPass;
+                                                               throw new 
InvalidConfigValueException("Cannot change private key password");
+                                                       }
                                                }
                                        }
                                }
@@ -175,32 +213,105 @@
                                        if (!newVersion.equals(get())) {
                                                String oldVersion = version;
                                                version = newVersion;
-                                               try {
-                                                       createSSLContext();
-                                               } catch (Exception e) {
-                                                       version = oldVersion;
-                                                       
e.printStackTrace(System.out);
-                                               throw new 
InvalidConfigValueException("Cannot change ssl version, wrong value");
+                                               if(enable) {
+                                                       try {
+                                                               
createSSLContext();
+                                                       } catch (Exception e) {
+                                                               
e.printStackTrace(System.out);
+                                                               version = 
oldVersion;
+                                                               try {
+                                                                       
createSSLContext();
+                                                               } catch 
(Exception e1) {
+                                                                       // 
ignore
+                                                               }
+                                                       throw new 
InvalidConfigValueException("Cannot change ssl version, wrong value");
+                                                       }
                                                }
                                        }
                                }
                        }
                );

+               sslConfig.register("sslTrustStore", "datastore/trusts", 
configItemOrder++, true, true, "SSL.trustStore", "SSL.trustStoreLong",
+                       new StringCallback() {
+                               public String get() {
+                                       return trustStore;
+                               }
+                               
+                               public void set(String newTrustStore) throws 
InvalidConfigValueException {
+                                       if (!newTrustStore.equals(get())) {
+                                               String oldTrustStore = 
trustStore;
+                                               trustStore = newTrustStore;
+                                               if(enable) {
+                                                       try {
+                                                               
loadTrustStore();
+                                                       } catch (Exception e) {
+                                                               
e.printStackTrace(System.out);
+                                                               trustStore = 
oldTrustStore;
+                                                               try {
+                                                                       
loadTrustStore();
+                                                               } catch 
(Exception e1) {
+                                                                       // 
ignore
+                                                               }
+                                                       throw new 
InvalidConfigValueException("Cannot change truststore file");
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               );
+
+               sslConfig.register("sslTrustStorePass", "freenet", 
configItemOrder++, true, true, "SSL.trustStorePass", "SSL.trustStorePassLong",
+                       new StringCallback() {
+                               public String get() {
+                                       return trustStorePass;
+                               }
+                               
+                               public void set(String newTrustStorePass) 
throws InvalidConfigValueException {
+                                       if (!newTrustStorePass.equals(get())) {
+                                               String oldTrustStorePass = 
trustStorePass;
+                                               trustStorePass = 
newTrustStorePass;
+                                       if(enable) {
+                                                       try {
+                                                       storeTrustStore();
+                                               } catch (Exception e) {
+                                                               
e.printStackTrace(System.out);
+                                                       trustStorePass = 
oldTrustStorePass;
+                                                       throw new 
InvalidConfigValueException("Cannot change truststore password");
+                                               }
+                                       }
+                                       }
+                               }
+                       }
+               );
+
                enable = sslConfig.getBoolean("sslEnable");
                keyStore = sslConfig.getString("sslKeyStore");
+               trustStore = sslConfig.getString("sslTrustStore");
                keyStorePass = sslConfig.getString("sslKeyStorePass");
+               trustStorePass = sslConfig.getString("sslTrustStorePass");
                keyPass = sslConfig.getString("sslKeyPass");
                version = sslConfig.getString("sslVersion");
-
+               
                try {
-                       keystore = KeyStore.getInstance("PKCS12");
+                       try {
+                               keystore = KeyStore.getInstance("PKCS12");
+                               truststore = KeyStore.getInstance("PKCS12");
+                       } catch (KeyStoreException e) {
+                               // if PKCS12 is not supported (GCJ)
+                               keystore = 
KeyStore.getInstance(KeyStore.getDefaultType());
+                               truststore = 
KeyStore.getInstance(KeyStore.getDefaultType());
+                       }
                        loadKeyStore();
-               createSSLContext();
+                       loadTrustStore();
+                       createSSLContext();
                } catch (Exception e) {
-                       Logger.error(SSL.class, "Cannot load keystore, ssl is 
disable", e);
+                       enable = false;
+                       ssf = null;
+                       keyStore = null;
+                       trustStore = null;
+                       Logger.error(SSL.class, "SSL initialization fail, ssl 
is disable", e);
                }
-
        }

        /**
@@ -214,7 +325,72 @@
                return ssf.createServerSocket();
        }

-       private static void loadKeyStore() throws Exception {
+       /**
+        * Get trust store, use by authToadlet in future
+        * @return Trust store
+        */
+       public static KeyStore getTrustStore() {
+               return truststore;
+       }
+       
+       /**
+        * Generate DSA key pair, use by authToadlet in future
+        * @return Key pair
+        * @throws Exception
+        */
+       public static KeyPair generateKeyPair() throws NoSuchAlgorithmException 
{
+               // 1024 bits DSA
+               KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
+               keyGen.initialize(1024, new SecureRandom());
+               return keyGen.generateKeyPair();
+       }
+       
+       /**
+        * Generate freenet's certificate, use by authToadlet in future for 
create client certificate
+        * @param pair Key pair
+        * @return Freenet's certificate
+        * @throws CertificateException
+        * @throws InvalidKeyException
+        * @throws IOException
+        * @throws NoSuchAlgorithmException
+        * @throws SignatureException
+        */
+       public static Certificate generateCertificate(KeyPair pair) throws 
CertificateException, InvalidKeyException, IOException, 
NoSuchAlgorithmException, SignatureException {
+               // Public key
+               PublicKey publicKey = pair.getPublic();
+               // Initialize signature
+               Signature sig = Signature.getInstance("SHA1withDSA");
+               sig.initSign(pair.getPrivate());
+               // Create DER certificate
+               DerOutputStream cert = new DerOutputStream();
+               // Raw certificate
+               DerOutputStream rawCert = new DerOutputStream();
+               DerOutputStream tmp = new DerOutputStream();
+               // version number (Version 3)
+               CertificateVersion.encode(tmp);
+               // Encode serial number, issuer signing algorithm, issuer name 
and validity
+               CertificateSerialNumber.encode(tmp);
+               CertificateAlgorithmId.encode(tmp);
+               CertificateIssuerName.encode(tmp);
+               CertificateValidity.encode(tmp, ONE_YEAR);
+               CertificateSubjectName.encode(tmp);
+               // Public key
+               tmp.write(publicKey.getEncoded());
+               // Wrap the data, encoding of the "raw" cert is now complete.
+               rawCert.write(DerValue.tag_Sequence, tmp);
+               byte[] rawCertByte = rawCert.toByteArray();
+               // AlgId
+               CertificateAlgorithmId.encode(rawCert);
+               // Signature
+               sig.update(rawCertByte, 0, rawCertByte.length);
+               byte[] signature = sig.sign();
+               rawCert.putBitString(signature);
+               cert.write(DerValue.tag_Sequence, rawCert);
+               CertificateFactory cf = CertificateFactory.getInstance("X.509");
+               return cf.generateCertificate(new 
ByteArrayInputStream(cert.toByteArray()));
+       }
+
+       private static void loadKeyStore() throws CertificateException, 
InvalidKeyException, IOException, KeyStoreException, NoSuchAlgorithmException, 
SignatureException   {
                if(enable) {
                        // A keystore is where keys and certificates are kept
                        // Both the keystore and individual private keys should 
be password protected
@@ -224,46 +400,62 @@
                        } catch (FileNotFoundException fnfe) {
                                //If keystore not exist, create keystore and 
server certificat
                                keystore.load(null, keyStorePass.toCharArray());
-                               CertAndKeyGen keypair = new 
CertAndKeyGen("DSA", "SHA1WithDSA");
-                               X500Name x500Name = new X500Name (
-                                               "Freenet",
-                                               "Freenet",
-                                               "Freenet",
-                                               "",
-                                               "",
-                                               ""
-                                       );
-                               keypair.generate(1024);
-                               PrivateKey privKey = keypair.getPrivateKey();
-                               X509Certificate[] chain = new 
X509Certificate[1];
-                               chain[0] = keypair.getSelfCertificate(x500Name, 
(long)365*24*60*60);
-                       keystore.setKeyEntry("freenet", privKey, 
keyPass.toCharArray(), chain);
-                       storeKeyStore();
-                       createSSLContext();
+                               KeyPair pair = generateKeyPair();
+                               Certificate cert = generateCertificate(pair);
+                               Certificate[] chain = new Certificate[1];
+                               chain[0] = cert;
+                       keystore.setKeyEntry("freenet", pair.getPrivate(), 
keyPass.toCharArray(), chain);
+                       storeKeyStore();
                        }
                }
        }

-       private static void storeKeyStore() throws Exception {
+       private static void loadTrustStore() throws CertificateException, 
IOException, KeyStoreException, NoSuchAlgorithmException {
                if(enable) {
+                       // A truststore is where trust certificates are kept
+                       // the truststore should be password protected
+                       try {
+                               FileInputStream fis = new 
FileInputStream(trustStore);
+                               truststore.load(fis, 
trustStorePass.toCharArray());
+                       } catch (FileNotFoundException fnfe) {
+                               //If truststore not exist, create truststore
+                               truststore.load(null, 
trustStorePass.toCharArray());
+                       storeTrustStore();
+                       }
+               }
+       }
+
+       private static void storeKeyStore() throws CertificateException, 
FileNotFoundException, IOException, KeyStoreException, NoSuchAlgorithmException 
{
+               if(enable) {
                        FileOutputStream fos = new FileOutputStream(keyStore);
                        keystore.store(fos, keyStorePass.toCharArray());
                        fos.close();
                }
        }
-       
+
+       private static void storeTrustStore() throws CertificateException, 
FileNotFoundException, IOException, KeyStoreException, NoSuchAlgorithmException 
{
+               if(enable) {
+                       FileOutputStream fos = new FileOutputStream(trustStore);
+                       truststore.store(fos, trustStorePass.toCharArray());
+                       fos.close();
+               }
+       }
+
        private static void createSSLContext() throws Exception {
                if(enable) {
                        // A KeyManagerFactory is used to create key managers
-                       KeyManagerFactory kmf = 
KeyManagerFactory.getInstance("SunX509");
+                       KeyManagerFactory kmf = 
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+                       TrustManagerFactory tmf = 
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                        // Initialize the KeyManagerFactory to work with our 
keystore
                        kmf.init(keystore, keyPass.toCharArray());
+                       tmf.init(truststore);
                        // An SSLContext is an environment for implementing JSSE
                        // It is used to create a ServerSocketFactory
                        SSLContext sslc = SSLContext.getInstance(version);
                        // Initialize the SSLContext to work with our key 
managers
-                       sslc.init(kmf.getKeyManagers(), null, null);
+                       sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), 
null);
                        ssf = sslc.getServerSocketFactory();
                }
        }
+
 }
Index: D:/Project/Freenet 0.7/src/freenet/l10n/freenet.l10n.en.properties
===================================================================
--- D:/Project/Freenet 0.7/src/freenet/l10n/freenet.l10n.en.properties  
(revision 17168)
+++ D:/Project/Freenet 0.7/src/freenet/l10n/freenet.l10n.en.properties  
(working copy)
@@ -936,8 +936,12 @@
 SSL.keyStorePassLong=Password for access of key store file
 SSL.keyPass=Password of private key access
 SSL.keyPassLong=Password of private key access
+SSL.trustStore=Name and path of trust store file
+SSL.trustStoreLong=Name and path of trust store file
+SSL.trustStorePass=Password for access of trust store file
+SSL.trustStorePassLong=Password for access of trust store file
 SSL.version=Version of SSL
-SSL.versionLong=Version of SSL, SSLv3 or TLSv1 (default SSLv3)
+SSL.versionLong=Version of SSL, SSLv3 or TLSv1 (default SSLv3, TLSv1 not 
supported by gcj)
 StaticToadlet.pathInvalidChars=The given URI contains disallowed characters.
 StaticToadlet.pathNotFound=The path you specified doesn't exist.
 StaticToadlet.pathNotFoundTitle=Path Not Found
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: 
<https://emu.freenetproject.org/pipermail/devl/attachments/20080125/da4913a3/attachment.pgp>

Reply via email to