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>