1    // Copyright (C) 2003 Adam Megacz <adam@xwt.org> all rights reserved.
2    //
3    // You may modify, copy, and redistribute this code under the terms of
4    // the GNU Library Public License version 2.1, with the exception of
5    // the portion of clause 6a after the semicolon (aka the "obnoxious
6    // relink clause")
7    
8    package org.xwt.util;
9    
10   import org.bouncycastle.crypto.AsymmetricBlockCipher;
11   import org.bouncycastle.crypto.Digest;
12   import org.bouncycastle.crypto.CipherParameters;
13   import org.bouncycastle.crypto.InvalidCipherTextException;
14   import org.bouncycastle.crypto.params.RSAKeyParameters;
15   import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
16   import org.bouncycastle.crypto.params.KeyParameter;
17   import org.bouncycastle.crypto.digests.SHA1Digest;
18   import org.bouncycastle.crypto.digests.MD5Digest;
19   import org.bouncycastle.crypto.digests.MD2Digest;
20   import org.bouncycastle.crypto.engines.RSAEngine;
21   import org.bouncycastle.crypto.engines.RC4Engine;
22   import org.bouncycastle.util.encoders.Base64;
23   import org.bouncycastle.asn1.DERInputStream;
24   import org.bouncycastle.asn1.DEROutputStream;
25   import org.bouncycastle.asn1.DERSequence;
26   import org.bouncycastle.asn1.DERObject;
27   import org.bouncycastle.asn1.DEROctetString;
28   import org.bouncycastle.asn1.BERInputStream;
29   import org.bouncycastle.asn1.x509.X509CertificateStructure;
30   import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
31   import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
32   import org.bouncycastle.asn1.x509.TBSCertificateStructure;
33   import org.bouncycastle.asn1.x509.X509Name;
34   import org.bouncycastle.asn1.x509.X509Extensions;
35   import org.bouncycastle.asn1.x509.X509Extension;
36   import org.bouncycastle.asn1.x509.BasicConstraints;
37   import org.xwt.util.Log;
38   import java.net.*;
39   import java.io.*;
40   import java.util.*;
41   import java.math.*;
42   import java.text.*;
43   
44   /**
45   
46      TinySSL: a tiny SSL implementation in Java, built on the
47               bouncycastle.org lightweight crypto library.
48   
49      This class implements an SSLv3 client-side socket, with the
50      SSL_RSA_EXPORT_WITH_RC4_40_MD5 and SSL_RSA_WITH_RC4_128_MD5 cipher
51      suites, as well as certificate chain verification against a
52      collection of 93 built-in Trusted Root CA public keys (the same 93
53      included with Microsoft Internet Explorer 5.5 SP2).
54   
55      As of 07-Dec-01, the zipped bytecode for this class is 43k, and the
56      subset of bouncycastle it requires is 82k.
57   
58      This class should work correctly on any Java 1.1 compliant
59      platform. The java.security.* classes are not used.
60   
61      The main design goal for this class was the smallest possible body
62      of code capable of connecting to 99% of all active HTTPS
63      servers. Although this class is useful in many other situations
64      (IMAPS, Secure SMTP, etc), the author will refuse all feature
65      requests and submitted patches which go beyond this scope.
66   
67      Because of the limited goals of this class, certain abstractions
68      have been avoided, and certain parameters have been
69      hard-coded. "Magic numbers" are often used instead of "static final
70      int"'s, although they are usually accompanied by a descriptive
71      comment. Numeric offsets into byte arrays are also favored over
72      DataInputStream(ByteArrayInputStream(foo))'s.
73   
74      Much thanks and credit go to the BouncyCastle team for producing
75      such a first-class library, and for helping me out on the
76      dev-crypto mailing list while I was writing this.
77   
78      Revision History:
79   
80      1.0  07-Dec-01  Initial Release
81   
82      1.01 15-Mar-02  Added PKCS1 class to avoid dependancy on java.security.SecureRandom
83   
84      1.02 27-Mar-02  Fixed a bug which would hang the connection when more than one
85                      Handshake message appeared in the same TLS Record
86   
87      1.03 10-Aug-02  Fixed a vulnerability outlined at
88                      http://online.securityfocus.com/archive/1/286290
89   
90      1.04 12-Dec-03  Renamed to org.xwt.SSL, fixed race condition
91   
92   */
93   
94   public class SSL extends Socket {
95   
96       // Simple Test //////////////////////////////////////////////
97   
98       public static void main(String[] args) {
99           Log.on = true;
100          try {
101              Socket s = new SSL("www.paypal.com", 443);
102              PrintWriter pw = new PrintWriter(s.getOutputStream());
103              BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
104              pw.println("GET / HTTP/1.0");
105              pw.println("");
106              pw.flush();
107              
108              while(true) {
109                  String s2 = br.readLine();
110                  if (s2 == null) return;
111                  Log.info(SSL.class, s2);
112              }
113              
114          } catch (Exception e) {
115              e.printStackTrace();
116          }
117      }
118  
119      // Static Data //////////////////////////////////////////////
120  
121      public static class SSLException extends IOException { public SSLException(String s) { super(s); } }
122      static SubjectPublicKeyInfo[] trusted_CA_public_keys;
123      static String[] trusted_CA_public_key_identifiers;
124      public static byte[] pad1 = new byte[48];
125      public static byte[] pad2 = new byte[48];
126      public static byte[] pad1_sha = new byte[40];
127      public static byte[] pad2_sha = new byte[40];
128      static byte[] randpool;
129      static long randcnt = 0;
130  
131      // Cipher State //////////////////////////////////////////////
132  
133      public byte[] server_random = new byte[32];
134      public byte[] client_random = new byte[32];
135      public byte[] client_write_MAC_secret = new byte[16];        
136      public byte[] server_write_MAC_secret = new byte[16];        
137      public byte[] client_write_key = null;
138      public byte[] server_write_key = null;
139      public byte[] master_secret = null;
140  
141      /** the bytes of the ServerKeyExchangeMessage, null if none recieved */
142      public byte[] serverKeyExchange = null;
143  
144      /** true iff the server asked for a certificate */
145      public boolean cert_requested = false;
146  
147      public X509CertificateStructure server_cert = null;
148  
149      public SSLOutputStream os = null;
150      public SSLInputStream is = null;
151  
152      String hostname;
153  
154      /** if true, we don't mind if the server's cert isn't signed by a CA. USE WITH CAUTION! */
155      boolean ignoreUntrustedCert = false;
156  
157      /** the concatenation of all the bytes of all handshake messages sent or recieved */
158      public byte[] handshakes = new byte[] { };
159  
160      /** true iff we're using SSL_RSA_EXPORT_WITH_RC4_40_MD5 */
161      boolean export = false;
162  
163      public InputStream getInputStream() throws IOException { return is != null ? is : super.getInputStream(); }
164      public OutputStream getOutputStream() throws IOException { return os != null ? os : super.getOutputStream(); }
165  
166      public SSL(String host, int port) throws IOException { this(host, port, true, false); }
167      public SSL(String host, int port, boolean negotiateImmediately) throws IOException { this(host, port, negotiateImmediately, false); }
168      public SSL(String host, int port, boolean negotiateImmediately, boolean ignoreUntrustedCert) throws IOException {
169          super(host, port);
170          if (!initializationFinished) {
171              synchronized(SSL.class) {
172                  while (!initializationFinished)
173                      try { SSL.class.wait(); } catch (Exception e) { }
174              }
175          }
176          hostname = host;
177          this.ignoreUntrustedCert = ignoreUntrustedCert;
178          if (negotiateImmediately) negotiate();
179      }
180  
181      /** negotiates the SSL connection */
182      public void negotiate() throws IOException {
183          os = new SSLOutputStream(super.getOutputStream());
184          is = new SSLInputStream(super.getInputStream());
185          os.writeClientHello();
186          is.readServerHandshakes();
187          os.sendClientHandshakes();
188          is.readServerFinished();
189      }
190  
191      class SSLInputStream extends InputStream {
192          
193          /** the underlying inputstream */
194          DataInputStream raw;
195  
196          /** the server's sequence number */
197          public int seq_num = 0;
198  
199          /** the decryption engine */
200          public RC4Engine rc4 = null;
201          
202          /** pending bytes -- decrypted, but not yet fed to consumer */
203          byte[] pend = null;
204          int pendstart = 0;
205          int pendlen = 0;
206  
207          public void mark() { }
208          public void reset() { }
209          public boolean markSupported() { return false; }
210          public long skip(long l) throws IOException { for(long i=0; i<l; i++) read(); return l; }
211          public SSLInputStream(InputStream raw) { this.raw = new DataInputStream(raw); }
212          public int available() throws IOException { return pendlen; }
213  
214          public int read() throws IOException {
215              byte[] singlebyte = new byte[1];
216              int numread = read(singlebyte);
217              if (numread != 1) return -1;
218              return (int)singlebyte[0];
219          }
220         
221          public int read(byte[] b, int off, int len) throws IOException {
222              if (pendlen == 0) {
223                  pend = readRecord();
224                  if (pend == null) return -1;
225                  pendstart = 0;
226                  pendlen = pend.length;
227              }
228              int ret = Math.min(len, pendlen);
229              System.arraycopy(pend, pendstart, b, off, ret);
230              pendlen -= ret;
231              pendstart += ret;
232              return ret;
233          }
234  
235          /** reads and decrypts exactly one record; blocks if unavailable */        
236          public byte[] readRecord() throws IOException {
237  
238              // we only catch EOFException here, because anywhere else
239              // would be "unusual", and we *want* and EOFException in
240              // those cases
241              byte type;
242              try { type = raw.readByte();
243              } catch (EOFException e) {
244                  if (Log.on) Log.info(this, "got EOFException reading packet type");
245                  return null;
246              }
247  
248              byte ver_major = raw.readByte();
249              byte ver_minor = raw.readByte();
250              short len = raw.readShort();
251              if (Log.on) Log.info(this, "got record of type " + type + ", SSLv" + ver_major + "." + ver_minor + ", length=" + len);
252  
253              byte[] ret = new byte[len];
254              raw.readFully(ret);
255              
256              // simply ignore ChangeCipherSpec messages -- we change as soon as we send ours
257              if (type == 20) {
258                  if (Log.on) Log.info(this, "got ChangeCipherSpec; ignoring");
259                  seq_num = 0;
260                  return readRecord();
261              }
262  
263              byte[] decrypted_payload;
264  
265              // if crypto hasn't been enabled yet; skip crypt and hash
266              if (rc4 == null) decrypted_payload = ret;
267              else {
268                  // decrypt the payload
269                  decrypted_payload = new byte[len - 16];
270                  rc4.processBytes(ret, 0, len - 16, decrypted_payload, 0);
271                  
272                  // check the MAC
273                  byte[] MAC = new byte[16];
274                  rc4.processBytes(ret, len - 16, 16, MAC, 0);
275                  byte[] ourMAC = computeMAC(type, decrypted_payload, 0, decrypted_payload.length, server_write_MAC_secret, seq_num++);
276                  for(int i=0; i<MAC.length; i++)
277                      if (MAC[i] != ourMAC[i])
278                          throw new SSLException("MAC mismatch on byte " + i + ": got " + MAC[i] + ", expecting " + ourMAC[i]);
279              }
280  
281              if (type == 21) {
282                  if (decrypted_payload[1] > 1) {
283                      throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
284                  } else if (decrypted_payload[1] == 0) {
285                      if (Log.on) Log.info(this, "server requested connection closure; returning null");
286                      return null;
287                  } else {
288                      if (Log.on) Log.info(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
289                      return readRecord();
290                  }
291  
292              } else if (type == 22) {
293                  if (Log.on) Log.info(this, "read a handshake");
294  
295              } else if (type != 23) {
296                  if (Log.on) Log.info(this, "unexpected record type: " + type + "; skipping");
297                  return readRecord();
298  
299              }
300                  
301              if (Log.on) Log.info(this, "  returning " + decrypted_payload.length + " byte record payload");
302              return decrypted_payload;
303          }
304  
305          private byte[] readHandshake() throws IOException {
306              // acquire a handshake message
307              byte type = (byte)read();
308              int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff);
309              byte[] rec = new byte[len + 4];
310              rec[0] = type;
311              rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff);
312              rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff);
313              rec[3] = (byte)((len & 0x000000ff) & 0xff);
314              if (len > 0) read(rec, 4, len);
315              return rec;
316          }
317  
318          /** This reads the ServerHello, Certificate, and ServerHelloDone handshake messages */
319          public void readServerHandshakes() throws IOException {
320              for(;;) {
321  
322                  byte[] rec = readHandshake();
323                  handshakes = concat(new byte[][] { handshakes, rec });
324                  DataInputStream stream = new DataInputStream(new ByteArrayInputStream(rec, 4, rec.length - 4));
325  
326                  switch(rec[0]) {
327                  case 2: // ServerHello
328                      if (Log.on) Log.info(this, "got ServerHello");
329                      byte ver_major = rec[4];
330                      byte ver_minor = rec[5];
331                      System.arraycopy(rec, 6, server_random, 0, server_random.length);
332                      short cipher_high = rec[6 + server_random.length + rec[6 + server_random.length] + 1];
333                      short cipher_low = rec[6 + server_random.length + rec[6 + server_random.length] + 2];
334  
335                      if (cipher_low == 0x04 || cipher_high != 0x00) {
336                          export = false;
337                          if (Log.on) Log.info(this, "using SSL_RSA_WITH_RC4_128_MD5");
338  
339                      } else if (cipher_low == 0x03 || cipher_high != 0x00) {
340                          export = true;
341                          if (Log.on) Log.info(this, "using SSL_RSA_EXPORT_WITH_RC4_40_MD5");
342  
343                      } else throw new SSLException("server asked for cipher " + ((cipher_high << 8) | cipher_low) +
344                                                  " but we only do SSL_RSA_WITH_RC4_128_MD5 (0x0004) and " +
345                                                  "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)");
346  
347                      byte compressionMethod = rec[6 + server_random.length + rec[6 + server_random.length] + 3];
348                      if (compressionMethod != 0x0) throw new SSLException("server asked for compression method " + compressionMethod +
349                                                                           " but we don't support compression");
350                      break;
351                      
352                  case 11: // Server's certificate(s)
353                      if (Log.on) Log.info(this, "got Server Certificate(s)");
354                      int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff);
355                      int numcerts = 0;
356                      X509CertificateStructure last_cert = null;
357                      X509CertificateStructure this_cert = null;
358  
359                      for(int i=0; i<numcertbytes;) {
360                          int certlen = ((rec[7 + i] & 0xff) << 16) | ((rec[7 + i + 1] & 0xff) << 8) | (rec[7 + i + 2] & 0xff);
361                          try {
362                              DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(rec, 7 + i + 3, certlen));
363                              this_cert = new X509CertificateStructure((DERSequence)dIn.readObject());
364                          } catch (Exception e) {
365                              SSLException t = new SSLException("error decoding server certificate: " + e);
366                              t.fillInStackTrace();
367                              throw t;
368                          }
369  
370                          if (server_cert == null) {
371                              server_cert = this_cert;
372                              TBSCertificateStructure tbs = server_cert.getTBSCertificate();
373                              X509Name subject = tbs.getSubject();
374  
375                              // gross hack to extract the Common Name so we can compare it to the server hostname
376                              String CN = tbs.getSubject().toString() + " ";
377                              boolean good = false;
378                              for(int j=0; j<CN.length() - 3; j++)
379                                  if (CN.substring(j, j+3).equals("CN=")) {
380                                      good = true;
381                                      CN = CN.substring(j+3, CN.indexOf(' ', j+3));
382                                      break;
383                                  }
384  
385                              if (!good) throw new SSLException("server certificate does not seem to have a CN: " + CN);
386                              if (!ignoreUntrustedCert && !CN.equalsIgnoreCase(hostname))
387                                  throw new SSLException("connecting to host " + hostname + " but server certificate was issued for " + CN);
388  
389                              SimpleDateFormat dateF = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss-z");
390  
391                              // the following idiocy is a result of the brokenness of the GNU Classpath's SimpleDateFormat
392                              String s = tbs.getStartDate().getTime();
393                              s = s.substring(0, 4) + "-" + s.substring(4, 6) + "-" + s.substring(6, 8) + "-" +
394                                  s.substring(8, 10) + "-" + s.substring(10, 12) + "-" +
395                                  s.substring(12, 14) + "-" + s.substring(14);
396  
397                              Date startDate = dateF.parse(s, new ParsePosition(0));
398  
399                              s = tbs.getEndDate().getTime();
400                              s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
401                                  s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
402                              Date endDate = dateF.parse(s, new ParsePosition(0));
403  
404                              Date now = new Date();
405                              if (!ignoreUntrustedCert && now.after(endDate))
406                                  throw new SSLException("server certificate expired on " + endDate);
407                              if (!ignoreUntrustedCert && now.before(startDate))
408                                  throw new SSLException("server certificate will not be valid until " + startDate);
409  
410                              Log.info(this, "server cert (name, validity dates) checks out okay");
411                              
412                          } else {
413  
414                              // don't check the top cert since some very old root certs lack a BasicConstraints field.
415                              if (certlen + 3 + i < numcertbytes) {
416                                  // defend against Mike Benham's attack
417                                  X509Extension basicConstraints = this_cert.getTBSCertificate().getExtensions().getExtension(X509Extensions.BasicConstraints);
418                                  if (basicConstraints == null) throw new SSLException("certificate did not contain a basic constraints block");
419                                  DERInputStream dis = new DERInputStream(new ByteArrayInputStream(basicConstraints.getValue().getOctets()));
420                                  BasicConstraints bc = new BasicConstraints((DERSequence)dis.readObject());
421                                  if (!bc.isCA()) throw new SSLException("non-CA certificate used for signing");
422                              }
423  
424                              if (!isSignedBy(last_cert, this_cert.getSubjectPublicKeyInfo()))
425                                  throw new SSLException("the server sent a broken chain of certificates");
426                          }
427  
428                          last_cert = this_cert;
429                          i += certlen + 3;
430                          numcerts++;
431                      }
432                      if (Log.on) Log.info(this, "  Certificate (" + numcerts + " certificates)");
433  
434                      if (ignoreUntrustedCert) break;
435  
436                      boolean good = false;
437  
438                      // pass 1 -- only check CA's whose subject is a partial match
439                      String subject = this_cert.getSubject().toString();
440                      for(int i=0; i<trusted_CA_public_keys.length; i++) {
441                          if (subject.indexOf(trusted_CA_public_key_identifiers[i]) != -1 && isSignedBy(this_cert, trusted_CA_public_keys[i])) {
442                              if (Log.on) Log.info(this, "pass 1: server cert was signed by trusted CA " + i);
443                              good = true;
444                              break;
445                          }
446                      }
447  
448                      // pass 2 -- try all certs
449                      if (!good)
450                          for(int i=0; i<trusted_CA_public_keys.length; i++) {
451                              if (isSignedBy(this_cert, trusted_CA_public_keys[i])) {
452                                  if (Log.on) Log.info(this, "pass 2: server cert was signed by trusted CA " + i);
453                                  good = true;
454                                  break;
455                              }
456                          }
457  
458                      if (!good) throw new SSLException("server cert was not signed by a trusted CA");
459                      break;
460  
461                  case 12: 
462                      if (Log.on) Log.info(this, "got ServerKeyExchange");
463                      serverKeyExchange = rec;
464                      break;
465  
466                  case 13:
467                      if (Log.on) Log.info(this, "got Request for Client Certificates");
468                      cert_requested = true;
469                      break;
470                      
471                  case 14: if (Log.on) Log.info(this, "  ServerHelloDone"); return;
472                  default: throw new SSLException("unknown handshake of type " + rec[0]);
473                  }
474              }
475          }
476       
477          public void readServerFinished() throws IOException {
478              
479              byte[] rec = readHandshake();
480              if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
481  
482              byte[] expectedFinished = concat(new byte[][] {
483                  md5(new byte[][] { master_secret, pad2,
484                                     md5(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
485                                                        master_secret, pad1 }) }),
486                  sha(new byte[][] { master_secret, pad2_sha,
487                                     sha(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
488                                                        master_secret, pad1_sha } ) } ) } );
489  
490              for(int i=0; i<expectedFinished.length; i++)
491                  if (expectedFinished[i] != rec[i + 4])
492                      throw new SSLException("server Finished message mismatch!");
493  
494              if (Log.on) Log.info(this, "server finished message checked out okay!");
495          }
496     
497      }
498      
499      class SSLOutputStream extends OutputStream {
500          
501          /** the underlying outputstream */
502          DataOutputStream raw;
503          
504          /** the sequence number for sending */
505          public long seq_num = 0;
506  
507          /** the encryption engine for sending */
508          RC4Engine rc4 = null;
509          
510          public SSLOutputStream(OutputStream raw) { this.raw = new DataOutputStream(raw); }
511          public void flush() throws IOException { raw.flush(); }
512          public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); }
513          public void write(byte[] b, int off, int len) throws IOException { write(b, off, len, (byte)23); }
514          public void close() throws IOException {
515              write(new byte[] { 0x1, 0x0 }, 0, 2, (byte)21);
516              raw.close();
517          }
518          
519          /** writes a single SSL Record */
520          public void write(byte[] payload, int off, int len, byte type) throws IOException {
521  
522              // largest permissible frame is 2^14 octets
523              if (len > 1 << 14) {
524                  write(payload, off, 1 << 14, type);
525                  write(payload, off + 1 << 14, len - 1 << 14, type);
526                  return;
527              }
528  
529              raw.writeByte(type);
530              raw.writeShort(0x0300);
531  
532              if (rc4 == null) {
533                  raw.writeShort(len);
534                  raw.write(payload, off, len);
535  
536              } else {
537                  byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num);
538                  byte[] encryptedPayload = new byte[MAC.length + len];
539                  rc4.processBytes(payload, off, len, encryptedPayload, 0);
540                  rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len);
541                  raw.writeShort(encryptedPayload.length);
542                  raw.write(encryptedPayload);
543  
544              }
545  
546              seq_num++;
547          }
548  
549          /** tacks a handshake header onto payload before sending it */        
550          public void writeHandshake(int type, byte[] payload) throws IOException {
551              byte[] real_payload = new byte[payload.length + 4];
552              System.arraycopy(payload, 0, real_payload, 4, payload.length);
553              real_payload[0] = (byte)(type & 0xFF);
554              intToBytes(payload.length, real_payload, 1, 3);
555              handshakes = concat(new byte[][] { handshakes, real_payload });
556              write(real_payload, 0, real_payload.length, (byte)22);
557          }
558  
559          public void sendClientHandshakes() throws IOException {
560              
561              if (Log.on) Log.info(this, "shaking hands");
562              if (cert_requested) {
563                  if (Log.on) Log.info(this, "telling the server we have no certificates");
564                  writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 });
565              }
566              
567              // generate the premaster secret
568              byte[] pre_master_secret = new byte[48];
569              pre_master_secret[0] = 0x03;                            // first two bytes of premaster secret are our version number
570              pre_master_secret[1] = 0x00;
571              getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2);
572  
573              // encrypt and send the pre_master_secret            
574              try {
575                  byte[] encrypted_pre_master_secret;
576  
577                  SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo();
578                  RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
579                  BigInteger modulus = rsa_pks.getModulus();
580                  BigInteger exponent = rsa_pks.getPublicExponent();
581  
582                  if (serverKeyExchange != null) {
583  
584                      AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
585                      rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
586  
587                      int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff);
588                      byte[] b_modulus = new byte[modulus_size];
589                      System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size);
590                      modulus = new BigInteger(1, b_modulus);
591  
592                      int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff);
593                      byte[] b_exponent = new byte[exponent_size];
594                      System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size);
595                      exponent = new BigInteger(1, b_exponent);
596  
597                      byte[] server_params = new byte[modulus_size + exponent_size + 4];
598                      System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length);
599  
600                      byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ),
601                                                                       sha(new byte[][] { client_random, server_random, server_params } ) } );
602  
603                      byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length,
604                                                                  serverKeyExchange.length - 6 - server_params.length);
605  
606                      for(int i=0; i<expectedSignature.length; i++)
607                          if (expectedSignature[i] != recievedSignature[i])
608                              throw new SSLException("ServerKeyExchange message had invalid signature " + i);
609  
610                      if (Log.on) Log.info(this, "ServerKeyExchange successfully processed");
611                  }
612  
613                  AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
614                  rsa.init(true, new RSAKeyParameters(false, modulus, exponent));
615  
616                  encrypted_pre_master_secret = rsa.processBlock(pre_master_secret, 0, pre_master_secret.length);
617                  writeHandshake(16, encrypted_pre_master_secret);
618  
619              } catch (Exception e) {
620                  SSLException t = new SSLException("exception encrypting premaster secret");
621                  t.fillInStackTrace();
622                  throw t;
623              }
624              
625              // ChangeCipherSpec
626              if (Log.on) Log.info(this, "Handshake complete; sending ChangeCipherSpec");
627              write(new byte[] { 0x01 }, 0, 1, (byte)20);
628              seq_num = 0;
629  
630              // compute master_secret
631              master_secret = concat(new byte[][] {
632                  md5(new byte[][] { pre_master_secret,
633                                     sha(new byte[][] { new byte[] { 0x41 }, pre_master_secret, client_random, server_random })}),
634                  md5(new byte[][] { pre_master_secret,
635                                     sha(new byte[][] { new byte[] { 0x42, 0x42 }, pre_master_secret, client_random, server_random })}),
636                  md5(new byte[][] { pre_master_secret,
637                                     sha(new byte[][] { new byte[] { 0x43, 0x43, 0x43 }, pre_master_secret, client_random, server_random })})
638                  } );
639              
640              // construct the key material
641              byte[] key_material = new byte[] { };
642              for(int i=0; key_material.length < 72; i++) {
643                  byte[] crap = new byte[i + 1];
644                  for(int j=0; j<crap.length; j++) crap[j] = (byte)(((byte)0x41) + ((byte)i));
645                  key_material = concat(new byte[][] { key_material,
646                                                     md5(new byte[][] { master_secret,
647                                                                        sha(new byte[][] { crap, master_secret, server_random, client_random }) }) });
648              }
649  
650              client_write_key = new byte[export ? 5 : 16];
651              server_write_key = new byte[export ? 5 : 16];
652  
653              System.arraycopy(key_material, 0,  client_write_MAC_secret, 0, 16);
654              System.arraycopy(key_material, 16, server_write_MAC_secret, 0, 16);
655              System.arraycopy(key_material, 32, client_write_key, 0, export ? 5 : 16);
656              System.arraycopy(key_material, export ? 37 : 48, server_write_key, 0, export ? 5 : 16);
657              
658              if (export) {
659                  // see SSLv3 spec, 6.2.2 for explanation
660                  byte[] client_untrimmed = md5(new byte[][] { concat(new byte[][] { client_write_key, client_random, server_random } ) });
661                  byte[] server_untrimmed = md5(new byte[][] { concat(new byte[][] { server_write_key, server_random, client_random } ) });
662                  client_write_key = new byte[16];
663                  server_write_key = new byte[16];
664                  System.arraycopy(client_untrimmed, 0, client_write_key, 0, 16);
665                  System.arraycopy(server_untrimmed, 0, server_write_key, 0, 16);
666              }
667  
668              rc4 = new RC4Engine();
669              rc4.init(true, new KeyParameter(client_write_key));
670              is.rc4 = new RC4Engine();
671              is.rc4.init(false, new KeyParameter(server_write_key));
672              
673              // send Finished
674              writeHandshake(20, concat(new byte[][] { 
675                  md5(new byte[][] { master_secret, pad2, 
676                                     md5(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
677                                                        master_secret, pad1 }) }),
678                  sha(new byte[][] { master_secret, pad2_sha,
679                                     sha(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
680                                                        master_secret, pad1_sha } ) })
681              }));
682              raw.flush();
683              if (Log.on) Log.info(this, "wrote Finished message");
684  
685          }
686          
687          public void writeClientHello() throws IOException {
688              
689              if (Log.on) Log.info(this, "sending ClientHello");
690              int unixtime = (int)(System.currentTimeMillis() / (long)1000);
691              
692              byte[] out = new byte[] {
693                  0x03, 0x00,                     // client version (SSLv3.0)
694                  
695                  // space for random bytes
696                  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
697                  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
698                  0x0, 0x0, 0x0, 0x0,
699                  
700                  0x0,                            // empty vector for sessionid
701                  0x0, 0x4, 0x0, 0x4, 0x0, 0x3,   // we support two ciphersuites: SSL_RSA_WITH_RC4_128_MD5 and SSL_RSA_EXPORT_WITH_RC4_40_MD5
702                  0x1, 0x0                        // we only support one compression method: none
703              };
704              
705              // don't need to use secure random here since it's sent in the clear
706              Random rand = new Random(System.currentTimeMillis());
707              rand.nextBytes(client_random);
708              intToBytes(unixtime, client_random, 0, 4);
709              System.arraycopy(client_random, 0, out, 2, client_random.length);
710              
711              writeHandshake(1, out);
712              flush();
713          }
714      }
715  
716      // Static Helpers ////////////////////////////////////////////////////////////////////
717  
718      /** copy the least significant num bytes of val into byte array b, startint at offset */
719      public static void intToBytes(long val, byte[] b, int offset, int num) {
720          for(int i=0; i<num; i++)
721              b[offset + num - i - 1] = (byte)((val & (0xFFL << (i * 8))) >> (i * 8));
722      }
723  
724      /** fills b with random bytes */
725      public static synchronized void getRandomBytes(byte[] b, int offset, int len) {
726          MD5Digest md5 = new MD5Digest();
727          byte[] b2 = new byte[16];
728          while(len > 0) {
729              md5.reset();
730              md5.update(randpool, 0, randpool.length);
731              intToBytes(randcnt++, b2, 0, 8);
732              md5.update(b2, 0, 8);
733              md5.doFinal(b2, 0);
734              int n = len < 16 ? len : 16;
735              System.arraycopy(b2, 0, b, offset, n);
736              len -= n;
737              offset += n;
738          }
739      }
740  
741      public static byte[] computeMAC(byte type, byte[] payload, int off, int len, byte[] MAC_secret, long seq_num) {
742          byte[] MAC = new byte[16];
743          MD5Digest md5 = new MD5Digest();
744          md5.update(MAC_secret, 0, MAC_secret.length);
745          md5.update(pad1, 0, pad1.length);
746  
747          byte[] b = new byte[11];
748          intToBytes(seq_num, b, 0, 8);
749          b[8] = type;
750          intToBytes(len, b, 9, 2);
751          md5.update(b, 0, b.length);
752  
753          md5.update(payload, off, len);
754          md5.doFinal(MAC, 0);
755          md5.reset();
756          md5.update(MAC_secret, 0, MAC_secret.length);
757          md5.update(pad2, 0, pad2.length);
758          md5.update(MAC, 0, MAC.length);
759          md5.doFinal(MAC, 0);
760  
761          return MAC;
762      }
763  
764      public static byte[] concat(byte[][] inputs) {
765          int total = 0;
766          for(int i=0; i<inputs.length; i++) total += inputs[i].length;
767          byte[] ret = new byte[total];
768          int pos = 0;
769          for(int i=0; i<inputs.length; i++) {
770              System.arraycopy(inputs[i], 0, ret, pos, inputs[i].length);
771              pos += inputs[i].length;
772          }
773          return ret;
774      }
775      
776      SHA1Digest master_sha1 = new SHA1Digest();
777      public byte[] sha(byte[][] inputs) {
778          master_sha1.reset();
779          for(int i=0; i<inputs.length; i++) master_sha1.update(inputs[i], 0, inputs[i].length);
780          byte[] ret = new byte[master_sha1.getDigestSize()];
781          master_sha1.doFinal(ret, 0);
782          return ret;
783      }
784      
785      MD5Digest master_md5 = new MD5Digest();
786      public byte[] md5(byte[][] inputs) {
787          master_md5.reset();
788          for(int i=0; i<inputs.length; i++) master_md5.update(inputs[i], 0, inputs[i].length);
789          byte[] ret = new byte[master_md5.getDigestSize()];
790          master_md5.doFinal(ret, 0);
791          return ret;
792      }
793  
794      // FEATURE: improve error reporting in here
795      /** returns true iff certificate "signee" is signed by public key "signer" */
796      public static boolean isSignedBy(X509CertificateStructure signee, SubjectPublicKeyInfo signer) throws SSLException {
797  
798          Digest hash = null;
799  
800          String signature_algorithm_oid = signee.getSignatureAlgorithm().getObjectId().getId();
801          if (signature_algorithm_oid.equals("1.2.840.113549.1.1.4")) hash = new MD5Digest();
802          else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.2")) hash = new MD2Digest();
803          else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.5")) hash = new SHA1Digest();
804          else throw new SSLException("unsupported signing algorithm: " + signature_algorithm_oid);
805  
806          try {
807              // decrypt the signature using the signer's public key
808              byte[] ED = signee.getSignature().getBytes();
809              SubjectPublicKeyInfo pki = signer;
810              RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
811              BigInteger modulus = rsa_pks.getModulus();
812              BigInteger exponent = rsa_pks.getPublicExponent();
813              AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
814              rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
815              
816              // Decode the embedded octet string
817              byte[] D = rsa.processBlock(ED, 0, ED.length);
818              BERInputStream beris = new BERInputStream(new ByteArrayInputStream(D));
819              DERObject derob = beris.readObject();
820              DERSequence dercs = (DERSequence)derob;
821              DEROctetString deros = (DEROctetString)dercs.getObjectAt(1);
822              byte[] MD = deros.getOctets();
823              
824              // generate our own hash
825              ByteArrayOutputStream baos = new ByteArrayOutputStream();
826              DEROutputStream dos = new DEROutputStream(baos);
827              dos.writeObject(signee.getTBSCertificate());
828              dos.flush();
829              byte[] b = baos.toByteArray();
830              hash.update(b, 0, b.length);
831              byte[] md_out = new byte[MD.length];
832              hash.doFinal(md_out, 0);
833              
834              // compare our hash to the signed hash
835              for(int j=0; j<MD.length; j++) if (md_out[j] != MD[j]) return false;
836              return true;
837  
838          } catch (Exception e) {
839              return false;
840  
841          }
842      }
843  
844      // Embedded Trusted Public Keys //////////////////////////////////////////////
845  
846      /** base64-encoded sequence of DER-encoded PKCS7 certs for all the "trusted root CA's" included with IE5.5 */
847      static String[] base64_encoded_trusted_CA_public_keys = new String[] {
848  
849          "CN=ABA.ECOM Root CA",
850          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdMR4HlVQwcITMsFQgDiDYNGPe" +
851          "STurYG0w1ZvT7BzkNnAYohqO+8zNCizLBVllOEZgUA2kRJgNhUCqUlhpTtY1b/cGyjoRnS" +
852          "eL5oKkReL8/MGF5HvDqxRj0e8LksNF+MfEwIKZ1AVes8fYPetfD3ioMOoUy0OqWzX1oil+" +
853          "wZm8EFaP3mt6mRlCzkeEgkGiUZOuuVnDkKis9CsvAc1V/7a+1oVns5LHI4sO6TqdN7dzzr" +
854          "cQOpOEoWbIkqytozE3nCVYztnLvyy1sQ+C5hNcYpTCrQKmPRZVm0+M359ACEtldChZ0yqP" +
855          "kqVPv/eEG8vXEo9LuQvP+WNATjRZ6hRihAgQIDAQAB",
856  
857          "O=ViaCode",
858          "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCws2enlrV2g+kWA9kaoHbVdOecBdJRP9" +
859          "tPGaGoOU7LJH1hxB5qIK4Pgd7quDn9Gx9rNkDtTSEl8qPZoVHYbMAblvjUQpTUp84bj9NU" +
860          "JqKE7zKFr0o/8TI2rz3mOifrA8IlfvRhK62KGkvmmzZo1C/l0oiU3Baq2sIVTGzD4RmRyQ" +
861          "IBAw==",
862  
863          "CN=Xcert EZ by DST",
864          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVQY3rS/963odKrti3yPwtR1Gt" +
865          "WEubZi/Inv5JdhkvsduOFaRzSengYi+9PqOMu4iwf3GqAXdwdaMBzUKTgg1ydA2FCTQ7/S" +
866          "GKIpdgVyqmu2aZireR4cZfVqi/zFFqqictpg7U5uGSV6Ch0w41CbQjxE66GwIB7bAn7+PR" +
867          "+/0ACK20B2philFadXtlLCAReYd4+KgcYatGoq5q+p1gCsz9gVSXzbG6H+gfqH+dOQwQLA" +
868          "+dBC6ZFoJV/Gv4c56ZUAYCi/gyzA51621zYW52CHdujnJ7IlDYt65aod5VnNzgsOb8bInO" +
869          "MQ2YU507eb+sa6fHTSXXVWq3SkolG/UnzucQIDAQAB",
870  
871          "CN=Certiposte Classe A Personne",
872          "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQAox3xaJSN48rMAR0Biy2+MQlCfnl" +
873          "7UXA5lC1hWlSvjRtBhNuAtRpuCy5Hu0pV8mpKvBAp+pp/g17HDRfmYQRs5redW19m2f867" +
874          "OS4sO8+2cwODzhNdMmpjottb+Esz6FBsy6gX7J6TuWwGSyYLdx6e+eWMiTfS0bv9qYwrLJ" +
875          "wQMdhLjM23cX44LCnjF7JP6FK245I80v3hAtphEHTSGvPI0dFmB1/EhGNpva5s3GUjHLf7" +
876          "98YTLoN+P6nlCyBtAQo34lzait4icOkN4HQ9xOtxm2Eq4g0Ui0xGN0wm0mjWVsNXqqJgN6" +
877          "9fnaCzgILmQypMgAAJUNmoanNtA/5ec5LlAgMBAAE=",
878  
879          "CN=Certiposte Serveur",
880          "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQA+p3gzOJHiylaV0ZFGsiPcpVZ/D8" +
881          "eXuOKekS4oFi6O80e2XIPE8Ob+ZxqTZH1ACdgdaADs1BHu2GOJAyPphF/HVQ5K4nK7KcFV" +
882          "ZHao45LN9/ZuQlYYUjOJ+YAUqBlRfsd3v3qoMcB9F25DTtVmyQU+S+Ll4lUbdKpRHarMmB" +
883          "F3pOvbKg4nx9XNSOzcfk5J50HNmQvRS14YGw06CpstmznHQAzQdgd8fI9+XHKOh9W+8qa5" +
884          "3r/dnxJ5R3zFyZdARgCS0xNak0+dfthfTMFdSEnZLZg8/MynhyHwPo5yfVk4NhYaDEi+of" +
885          "LVPqgWDCBZz84PM4M9rav1/93X/WkIiADvAgMBAAE=",
886  
887          "OU=Certisign - Autoridade Certificadora - AC2",
888          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5MMyl65DWVpRnM4mDbUa+cJeTF04KJ3" +
889          "DOycXyxdIt0RGcdzJsdNOSb/rp1bhhmqpMEz41OvDuCTbZ0Zcxx16sQUm/SG1OIFPJe2qj" +
890          "ljFrsm6ozy9yTAatMs9aCPN9EJyqu7pz+fPwuCRvqGW2Iv4FWxBVRMIDHa3RIswIbfuMyw" +
891          "IDAQAB",
892  
893          "OU=Certisign - Autoridade Certificadora - AC4",
894          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsg9TMg5A/X+y+wenQx1hGWR/xk0qyFx" +
895          "MLzymZqwRFM+PRXr68jiV3Yt2bkpsxCkBFedXys91suUD9mH9Aoi3pspO9S9XB3unR+nH3" +
896          "P0G89BSvzWvIOUqdYGW0hNBqQeljrptp6rlGHNsYCDtiTN5B156GfxNyEdTc6t5gpbvdGw" +
897          "IDAQAB",
898  
899          "OU=Certisign Autoridade Certificadora AC1S",
900          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwwJXro8VB+JtvcWOOkRFX+QPHaJoanG" +
901          "Hwww8Ml2KIfiYBNX398W9PF5WqfvK7vO/idnNhlTZRgz6E6D+6VzY3lBNskmQflA3rVC9R" +
902          "WuUoXvCShufkbSF6XzcL51u9LQKogfk/yxTIvKTF49HLN9yr5Yeq8guYLnrPzB7Cf+j9AQ" +
903          "IDAQAB",
904  
905          "OU=Certisign Autoridade Certificadora AC3S",
906          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOZE7Wz658mCeY7yjvujTDNRqd0mYecf" +
907          "Hkli0nFzmQRY8t7+bVR6nhg4F8Pihx+oC7XfhDaxkQwZhvFZ4trklkROyEGmlZFleyPZLY" +
908          "Zku/ma1DGMc4yYuOLAQus0trk/adH4SyzeYAwr42pbxZtZ+LGSD/5agopFW2irayxddE4w" +
909          "IDAQAB",
910  
911          "O=Certplus, CN=Class 1 Primary CA",
912          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw2spyC7HrnxSBemTiVYKWnnJzN" +
913          "wl74eKLQXYgRcEGzpF+HkODUnUgUHIq0X7dcgV8uLQvNlhbISkExmn2fnySdxMD8Z9V7QT" +
914          "3B4JcSk2nYBY9BvYiRTr09KTSyrxd+dqZb0Z5ar9DEpj4cKZtA8EtlobNjw3PL/F5V7xX1" +
915          "cOH8f9LOfkb2qbYpY5EZtm8Cy2UtzhJ//bbf7rq2MUHWOIY+IWDPkgVA+b3RVqdoNPvSeL" +
916          "U6Y30ofyR1BSO2bp0XgaG7I7afBZPDhb0SpMM14Oylal7S1bgoNN1jhOila2ai8kaxIwpi" +
917          "rerwy7qkQSHBPFZQ/j/dgaMUvkPwx8RegWMwIDAQAB",
918  
919          "O=Certplus, CN=Class 2 Primary CA",
920          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FCW0BL4NdIIeHq2UnD9b+7PuR" +
921          "HLXXfh7Ol+BI3WzG9zQ1dgrDMKROwDXxyAJJHlqJFWEoL34Cv0265hLokQjWtsurMCvdU2" +
922          "xUg3I+LwWjdSMxcS4tFgTb4vQRHj9hclDIuRwBuZe5lWDa/u0rxHV+N5SXs0iSckhN6x7O" +
923          "lYTv5O31q+Qa2sCMUYDu/SU+5s0J0SARON3IBi95WpRIhKcU5gVZ7bIxl5VgcMP2MLXLDi" +
924          "vn4V/JQzWEE4dMThj4vfJqwftYs7t0NZa7Akpm2Qi8Ry6l0zmLfL3l5775TxGz7KySHBxZ" +
925          "gCqqL2W3eb9X6WVTQcZ2nA8ULjR6z8KBxmVQIDAQAB",
926  
927          "O=Certplus, CN=Class 3 Primary CA",
928          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5QwbtBM2X5eYOVvuybKUm9rbI" +
929          "WZpQvvABpvG01YtRgH+t17+MssUt38nLiNUum5sgt89Y9bmUgJWN7NSJWGJYkFNCcwC1e2" +
930          "DHdjKctsqj65mVESDZhwdkdM+UmWIgj5a+qqADajFaccHp+Mylp5eyHaiR9jfnmSUAkEKK" +
931          "3O420ESUqZsT9FCXhYIO+N/oDIBO0pLKBYjYQCJZc/oBPXe4sj45+4x7hCQDgbkkq9SpRV" +
932          "x1YVDYF3zJ+iN4krW4UNi3f4xIv7EMuUx+kaVhKXZhTEu9d9bQIbv3FiJhjpSYr6o97hhK" +
933          "2AykriIoxqCGGDsiLHCYg4Vl3RMavwCZ8TWQIDAQAB",
934  
935          "CN=Autoridad Certificadora de la Asociacion Nacional del Notariado Mexicano",
936          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7tlrVYRxJvaOrUG71tLeY+ryP2" +
937          "XyOxPBrlEm9L94j8ZMSay/Qd71KMco55/XgOXU7iMrk5U9yY9q9coA6RDHiIIabqNf8DRS" +
938          "ISVoKPiV8ICVoiyxP2r2KNbihP0WZ5wluXXb5cZZA7SrQgeI1VxIRaIJA8muZ5KoolPHyq" +
939          "t+mhKVWgVXjRBklicRsOYyMFvNPQygGxMtuxqr3TnOkmuiBNQTX213Z1Q5qHtpisZfeMoH" +
940          "GGlu+cDT0IqOrx4waO742KhmDIR9I2qJPGJNFHSs25uc/LCD/gcw8factEjI5jpCJQko91" +
941          "bCsdejmHcCh+qKwV3axIonB4VeSExVKEDtCQIDAQAB",
942  
943          "O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
944          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
945          "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
946          "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
947          "IDAQAB",
948  
949          "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
950          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
951          "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
952          "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
953          "IDAQAB",
954  
955          "C=FR, O=Certplus, CN=Class 3P Primary CA",
956          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzf/62CbQXhp9UlYsN4fcWmmK+" +
957          "OuUMapvJPpIL7kxBOCVu/wQzIJypt1A498T+HgT3aeC61kehQ6mp2/LxYLZRyp7py84xpl" +
958          "y0+F6pJWdWbWVUDv+8zWOD+rHO9CjRmJ9reVhsKnHen3KfEq2WV5/Cv1jsoad36e6Kz5Zr" +
959          "9F++gTnV+2c+V9e477EnRdHwZehRumXhhEALq8027RUg4GrevutbTBu7zrOA9IIpHHb9K4" +
960          "cju6f8CNbLe8R3MhKoX/rNYoohnVl2o6uaxtRezmTcPbqF3FXYKYrEpaquYrCAwQdLxi9j" +
961          "pJBGbYURwmpth1n5y/rmBRPVy8ok97iWfNUwIDAQAB",
962  
963          "C=FR, O=Certplus, CN=Class 3TS Primary CA",
964          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvWWaI0MAPPklAUOYW0Y0N2c39F" +
965          "tXjqPezYwvQbMVPeWYi/LMXKfHrzXHs6dPxxApV+kDiYNyBnZSwXACN0Dt8M6LsbGJrAKo" +
966          "W93c1UNFBtwotulRG2ru83tIxZ0Rro2mcpPAJUKRqD5G4mhMgUCwQtN6vntH0kdQDKQSps" +
967          "rkEtDAfDo8AanKApbeglrF+xm6PJzYD3QfmBiulFAyB1IQEUpL7FhVLNSeS5R7BdJy3wbw" +
968          "jcsInuTutEStgvEbYWrxs/gWMTZCJLqQv7V+YW7CWQxUebRMiCgezBvfhIsjyL6vB/KRst" +
969          "qNyoxffCg8fIlsBlm9Ps7FgtNqyaxoVe7FrwIDAQAB",
970  
971          "C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority",
972          "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AKT7gWJ7zhAn3ej3vmxuxnCZ27jVBQNpKI" +
973          "Kccn+WP47srCmSP4oU+EJ2vr1dA7mQ1NC8BrJRM1/Ewr+2i4+ZtmIiYN3b3yCCtMqiLy1Q" +
974          "7ZQy3uBVjdRo4uBM0s0FFi6VZlxhUjgeUaiCocTvJekK5osrjjFm2fjZ/b07adnrAgMBAA" +
975          "E=",
976  
977          "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 1",
978          "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ3ZsMoBdERA+vIUBzZ1bwPmloEbrZN/" +
979          "KBrsMkrGmhzfymGFVW/4ufMsHb53gsOdtggUGl79PNgI0YPOJSDAuf92Se5aDwuGFi9L/g" +
980          "o9pYK/0VBGu9Op58nfI92OSVw+xOwvFlqwxL7EeCW+LhUHXY9mG0GFztM6BLHoP7T4S8eQ" +
981          "IDAQAB",
982  
983          "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2",
984          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqwujNeCLKRSxFIWvPBDkOW81XU" +
985          "qu3ephjZVJ9G9koxpgZqSpQCKE2dSl5XiTDmgBrblNXDrO07ioQkDfz6O6gllqkhusHJra" +
986          "CCslJ/lpI0fx4Ossepv1EwLQfjR8wp48AFmr9doM9TI8K6xQ2tbD3oOUyqgMmTIOCEhWW2" +
987          "r72uFYWAFJX3JBPBUGAY5draq4k7TNnuun6GotUjTbOu9cdVHa2/Mx+e5xmDLEVBVEDPmb" +
988          "Ve2t3xgIoKOGiknuUwWPGUzV3lh5m9JqHEKrxdWnz2gPluThYZh2YciRfNY+AOKRUIfhnQ" +
989          "rmrZfSHcY6fcu82gM01Y5bAfVqB7cWtm5KfwIDAQAB",
990  
991          "C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA",
992          "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC0SBGAWKDVpZkP9jcsRLZu0XzzKmueEb" +
993          "aIIwRccSWeahJ3EW6/aDllqPay9qIYsokVoGe3eowiSGv2hDQftsr3G3LL8ltI04ceInYT" +
994          "BLSsbJZ/5w4IyTJRMC3VgOghZ7rzXggkLAdZnZAa7kbJtaQelrRBkdR/0o04JrBvQ24JfQ" +
995          "IBAw==",
996  
997          "OU=National Retail Federation, CN=DST (NRF) RootCA",
998          "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2aybd/pQ08zcuUCsuXJqAIcj/A" +
999          "+WIdAmr+TitV/606Z9ITAuzBeCj5h0/Gekpt+Il6JCKfWn2xGT+14jMMKqvCLnQRvl7SXe" +
1000         "yD/b3ldFeEBGg7LVGj3fD0Vt1WMCddgvxm6rlZF0Nw3LTQlc0dRbOtrdDshrmdjVOczfhV" +
1001         "XEklMCo+H3gMlwo9rcM8R/okcIHDWWH6EDHDCD9MTM/5jDsEZEosC/rdvSgfZMmCynXiTz" +
1002         "hspj1bp98JrAStAbWO7sqWfPaQJsIsBgLCzRyCDqyC373Zy7y1FM3OdXBDtUmxGlMnTsdA" +
1003         "HzkBVbL3wsk2W5Zme0gYg15Z6RGH+BqEHIywIDAQAB",
1004 
1005         "OU=United Parcel Service, CN=DST (UPS) RootCA",
1006         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7xfsrynm2SsnwNt7JJ9m9ASjwq" +
1007         "0KyrDNhCuqN/OAoWDvQo/lXXdfV0JU3SvbYbJxXpN7b1/rJCvnpPLr8XOzC431Wdcy36yQ" +
1008         "jk4xuiVNtgym8eWvDOHlb1IDFcHfvn5KpqYYRnA/76dNqNz1dNlhekA8oZQo6sKUiMs3FQ" +
1009         "UZPJViuhwt+yiM0ciekjxbEVQ7eNlHO5stSuY+e2vf9PYFzyj2upg2AJ48N4UKnN63pIXF" +
1010         "Y/23YhRtFx7MioCFQjIRsCHinXfJgBZBnuvlFIl/t8O8T8Gfh5uW7GP2+ZBWDpWjIwqMZN" +
1011         "qbuxx3sExd5sjo9X15LVckP8zjPSyYzxKfFwIDAQAB",
1012 
1013         "CN=Autoridad Certificadora del Colegio Nacional de Correduria Publica Mexicana",
1014         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmO0dhYH7/jd0viOAJ18bQX6856" +
1015         "WK2HNdlkjqq1iqfaUdz/4gCtnydQnts9X9+JMqGaleqLEU8tZChkFBXk/FVqeaokJvLihI" +
1016         "6i6r2cHZmvClnotdEWeaNzdTYGbxIv93d0fp3dwYRu4u3+LBluDqWN6H65OIaZmwPm52KU" +
1017         "Bhwyhmc3+sMXb0OM3WMo9zMhAVNNJ8RND8eQwAnX0P4+P3RPWedEknrRvXMshTrm8qsNe1" +
1018         "LRgsbjs6TUzb9Wi1L7AMkPk93HU2msLgv7uWiMJr7hjXTlA/V4tnaKS+AzNdWRI0if52yN" +
1019         "kVdgFUZP2s41DvEMjQ7l/sHd9PBZg8tBReAQIDAQAB",
1020 
1021         "CN=DST RootCA X1",
1022         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sYmtuelPcHEaNVQb1PFb0kTCb" +
1023         "ivLEiNFGqjF19a+dMudS/YKGLRky/8TdSrh+UIx5nnkj91vesltBXBmxk90kSN13QgbTcC" +
1024         "j2mTW4rEGZ30sg78Fmy5sQWSg9GFLGCUPkVVoNmrCCHmYOg7dPKZUFFo0AMtsYC+o9hSsE" +
1025         "TNQ0pwjliFleFOLNYtQW/WhOfImETKR9ssJKVpJs9ruCdiw/TJepIj7RNngq5FLkXlfnI/" +
1026         "hZ2UYhDmPJGhrXcA4BXs84SAcnqObmCXxyRZEDSDW+GlpGm2VzUceFnG0y86c2fulMoEEw" +
1027         "ViBnAjs/R87kXZZAtbSaqkQ84mxEQSbLjdeQIDAQAB",
1028 
1029         "OU=DSTCA X2, CN=DST RootCA X2",
1030         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3HXwjMB1lprAYh8m98ThmurgVn" +
1031         "Nbmc0BRKgIttWn2hoEGDmSSnijgcL1d3pQtHD/mqvGx8pug09CmPsmC9rcbdapmVVSZ+ko" +
1032         "A5Lc5bAFmg8V+WtZclby+jn8qmjuDx8Qgy/8nfoXlt2C4+ZFfcBLgEQf7SzghP2RXJJUaS" +
1033         "XlYmnc5e4AUr0zC611AoWnZFAtxRkZMMAm28nT/S6ZrVm1C03UQa6FSENZ3Leo4qLew4/X" +
1034         "uKFipmhQUuTPMaeUhdqfRjIXVuXy62Y9Ev9D25jvd8/LgY00scZQSibR5D5BUK9sriI0Lt" +
1035         "VrboO6ebh2ZUjaCSlkYyK5+0d2hYyGRMsJ2wIDAQAB",
1036 
1037         "C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA",
1038         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC2HfdLjQ8T4xL1Cf4GMg6vTEH1fdRHPS" +
1039         "oK34MF3t595gMW9lE6y0caSq1+xP0dtL50injdC4OOtIQTxPv4bSmuoeEPD0PjtV5gafqD" +
1040         "lPx55tx27dFEK479Erv+F3cXDIntp+9RfcTtOMM7o3r74k2gYLXy/RNl08bsP741nD0i7w" +
1041         "IBAw==",
1042 
1043         "C=US, O=Digital Signature Trust Co., OU=DSTCA E1",
1044         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodG" +
1045         "BmE5gGHKlREmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth" +
1046         "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQ" +
1047         "IBAw==",
1048 
1049         "C=US, O=Digital Signature Trust Co., OU=DSTCA E2",
1050         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+S" +
1051         "SmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e" +
1052         "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQ" +
1053         "IBAw==",
1054 
1055         "CN=Entrust.net Certification Authority (2048)",
1056         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvw" +
1057         "tKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtL" +
1058         "A/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24Sc" +
1059         "F2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUy" +
1060         "VYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJ" +
1061         "G/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQAB",
1062 
1063         "CN=Entrust.net Client Certification Authority",
1064         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/" +
1065         "Bo6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDe" +
1066         "g7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173iw" +
1067         "IBAw==",
1068 
1069         "CN=Entrust.net Secure Server Certification Authority",
1070         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO" +
1071         "2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc" +
1072         "1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQw" +
1073         "IBAw==",
1074 
1075         "C=US, O=Equifax, OU=Equifax Secure Certificate Authority",
1076         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBXbFYZwhi7qCaLR8IbZEUaJgKHv7aBG" +
1077         "8ThGIhw9F8zp8F4LgB8E407OKKlQRkrPFrU18Fs8tngL9CAo7+3QEJ7OEAFE/8+/AM3UO6" +
1078         "WyvhH4BwmRVXkxbxD5dqt8JoIxzMTVkwrFEeO68r1u5jRXvF2V9Q0uNQDzqI578U/eDHuQ" +
1079         "IDAQAB",
1080 
1081         "C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1",
1082         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOLxm8F7d33pOpX1oNF080GgyY9CLZWd" +
1083         "TEaEbwtDXFhQMgxq9FpSFRRUHrFlg2Mm/iUGJk+f1RnKok2fSdgyqHCiHTEjg0bI0Ablqg" +
1084         "2ULuGiGV+VJMVVrFDzhPRvpt+C411h186+LwsHWAyKkTrL6I7zpuq18qOGICsBJ7/o+mAw" +
1085         "IDAQAB",
1086 
1087         "CN=Baltimore EZ by DST",
1088         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMyzPUN5uEf5FbduJrFMkph57c" +
1089         "Vw8zrp1d0D9Co/YIyW5UcWAvc2svGeJoj1nkJlng+uf+PMsW4h9fGIInTWH7J3BDkyuke1" +
1090         "NcATXQFyowVDzE7aJpqHqGFj9GanwxVG6tHR6jDDu3Fqm8FDhsE5H8ZWYAIb/Ig6oJm7jN" +
1091         "d4YdBeV4+RO4CLbv/JZYEKObuQEyA1SD+l4b8twXGDhSDtIIfLtv4ZjATd7Sld3woSzolW" +
1092         "8h9aGTFYtv1jNurJI96nkZcnZXKZbMd6RMRfvpsfHsqeWBymqiNq4wYbkiTYVyIJUBWQRv" +
1093         "CDXraATBKBPWZvBFU6iGvQ71aHUKC51lUbnQIDAQAB",
1094 
1095         "C=US, O=Equifax Secure, OU=Equifax Secure eBusiness CA-2",
1096         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkOTmTHlIGGyg2+LKjKcXtjrIRvf7r57" +
1097         "R0wo//BefZnQa/Esg/DvLW0SSyEd7RcwmK1LEsmAkNHlBGsoOmRY1iaLuFGyBwMqpAzaaW" +
1098         "X8RxNz8E87dBJDkHGh4uYVigEgvlpd/Fq+o3ccwcyDc6uZdSp6zFaiSUTpx7z8Bq1t8hvQ" +
1099         "IDAQAB",
1100 
1101         "C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1",
1102         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC65xeQAmWxNFU8ScJR1d+n0TeP0eeBc0" +
1103         "FSYJudoRcmeK3HsegmlDK13jONOi/b8pp6WnOYo1zp+4pzG1znw7+AbM2p9NYrwPf5mapj" +
1104         "orFHAg/U5FE6EjxsilpUhHDbwcWQz3JFy6hZwM0znT+jluuFMyEcPh4+YG52nGeFxcjDYQ" +
1105         "IDAQAB",
1106 
1107         "O=EUnet International, CN=EUnet International Root CA",
1108         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeQTvZQUmLKJxZFPdQaCh7TQhcZ/+FHg" +
1109         "umzzoyArB8fEqftokCIQxKmYvLZFF+eFq2XqlTt+/vx9+lIVmXTuIH5S18GdUqysgz05YQ" +
1110         "Lt2gAJ/9yuhhqVPKth0YPpwR4GPnKmdbyESV8BNVSLu+VbhnN83LABMN/E9pFGpRlOy8Jw" +
1111         "IDAQAB",
1112 
1113         "CN=FESTE, Public Notary Certs, EmailAddress=feste@feste.org",
1114         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhg/ObLsnn4cf0VAXNdkD+tLMTvucVXo" +
1115         "Ym6EB3GlU/0QMmjPqHX6TF+f61MonGf0GR2BVATnBS8PHa+GI1mV4clFNhzD5iwINdWNH4" +
1116         "SBFxbPewd+EYl7QHKDCRMcdPVPOEnsxZiUVtfrTJ245ClWbU3x4YTfylD9YahDnEyvK98w" +
1117         "IDAQAB",
1118 
1119         "CN=FESTE, Verified Certs",
1120         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqY58fOBqEBISzS5MZhKJ7YsOnqyzsYE" +
1121         "5VEeIEMicgNfkaeB8nZ6fggrAF6Capm4pEVr9LhFOjIqYOFlO5f68QyDMYVNnGTHzRW1ZS" +
1122         "U4amWz8T8sMB0jGhM1y8XeTcYjzKI5dPcPuBjrDZnq+T6raxJI0ELVFDPDjsJ0Nxh+g8xw" +
1123         "IDAQAB",
1124 
1125         "CN=First Data Digital Certificates Inc. Certification Authority",
1126         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDfHBQeCbm/pEByIJl5toQi9NeFksUEJO" +
1127         "gHLgLkF5UFN5V2Pfyx5Q+HDmK5LDCXJuELFWcAphXe6I3LlewCWFLAR2UzTFafCh8EwDdQ" +
1128         "gVe63/rya2fry9CAD9lXlRBlewZFWOuutF7jkxUrmby2KS/7Qp9HKy5M6zQoMpkO7/9voQ" +
1129         "IBAw==",
1130 
1131         "C=ES, O=FNMT, OU=FNMT Clase 2 CA",
1132         "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCYP60ZNpM9Pv52QhT9NW/x+q0ieljjRt" +
1133         "Bdxlr5Yi2PMV7+tDD+UHSs1p0d4GLGSd0UEn1xC6wGwT/XBofgkInW5eMDsvInsZ8zyKpr" +
1134         "NkqjxD95QZ2JRi8rPmPUOFaRqh2xDUJ1TfOHTuMPTcy0bL9iE4fq0JuOtuL/GfSUCdWWYQ" +
1135         "IBAw==",
1136 
1137         "CN=Belgacom E-Trust Primary CA",
1138         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq2bmz1U9qTcVB0HsEYWqLcYEH2mTjWG" +
1139         "4nVcKtzhew/PqSjQjwHHL/ssMx/uBqh5dMzENXpyh5OrWDXaQdavFqxT4UIh1ZBm/wpjF3" +
1140         "3LBJOObLDA/+qnI0iNooOiFa7nQrG6TbWxMWtXNfw66M0sA+PbDL8OyLhgvCwUQYWmOo1Q" +
1141         "IDAQAB",
1142 
1143         "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA",
1144         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2g7mmY3Oo+NPin778YuDJWvqSB" +
1145         "/xKrC5lREEvfBj0eJnZs8c3c8bSCvujYmOmq8pgGWr6cctEsurHExwB6E9CjDNFY1P+N3U" +
1146         "jFAVHO9Q7sQu9/zpUvKRfeBt1TUwjl5Dc/JB6dVq47KJOlY5OG8GPIhpWypNxadUuGyJzJ" +
1147         "v5PMrl/Yn1EjySeJbW3HRuk0Rh0Y3HRrJ1DoboGYrVbWzVeBaVounICjjr8iQTT3NUkxOF" +
1148         "Ohu8HjS1iwWMuXeLsdsfIJGrCVNukM57N3S5cEeRIlFjFnmusa5BJgjIGSvRRqpI1mQq14" +
1149         "M0/ywqwWwZQ0oHhefTfPYhaO/q8lKff5OQzwIDAQAB",
1150 
1151         "CN=GTE CyberTrust Global Root",
1152         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9p" +
1153         "TAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6" +
1154         "XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQ" +
1155         "IDAQAB",
1156 
1157         "CN=GTE CyberTrust Root",
1158         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6jr11kBL65Xl0stn3JtQOQR3pNgdWct" +
1159         "W4adpU1LHWeG2q4zs9o4Q3JcevrwTcsyKx6W2+gm3rjS+9tK5wHqLWbiAxUeZWXHNSsiNQ" +
1160         "Trz7mmdAxIYRRsdDIrrqAE9scs1hnN7L+u4w0ub6W53Fmdwg+Dm/ZIwHVju93Gxe9r/h2Q" +
1161         "IDAQAB",
1162 
1163         "C=US, O=GTE Corporation, CN=GTE CyberTrust Root",
1164         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7" +
1165         "pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3" +
1166         "FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44Aw" +
1167         "IDAQAB",
1168 
1169         "OU=ValiCert Class 3 Policy Validation Authority",
1170         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFl" +
1171         "LWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2" +
1172         "bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPw" +
1173         "IDAQAB",
1174 
1175         "OU=ValiCert Class 1 Policy Validation Authority",
1176         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSL" +
1177         "wxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+Fiw" +
1178         "nRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQ" +
1179         "IDAQAB",
1180 
1181         "OU=ValiCert Class 2 Policy Validation Authority",
1182         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZU" +
1183         "cOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XB" +
1184         "hVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9w" +
1185         "IDAQAB",
1186 
1187         "C=hk, O=C&W HKT SecureNet CA Class A",
1188         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBuiCqVMc2NGUUh0Y6i0jBbb9M" +
1189         "hn3qFIAv/Lo8+n39mxMeDjLihxBKZkWsZc/tCnuOo+Ctr7EX9/JCheyIqsbniqyKIYOZ5M" +
1190         "UNHwmLXvpLIbYGu/+XO0C3X5Irvp5YGgldJ2THzTp/5dlRXtB9TH3mAwAO7yLpTxhjLlWV" +
1191         "Ho34CiKgDvPIhdEeMAX1TkDEcQbLD1+DN2HDRmW9S7NGM502aUOuzNIinz9hK71CEpN6VE" +
1192         "Td+JDAQMfUF7h/MWwUMpZLTWRWerhkxljwG36mOMTnhUREcaU4aMaxgnIQvFVmYOJfbgea" +
1193         "xoAHTpmmQ8SU6e4B3IiBtQBvddCfiNixP9XQIDAQAB",
1194 
1195         "CN=IPS SERVIDORES",
1196         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGb" +
1197         "WOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU" +
1198         "3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzhPvYR3oydAQ" +
1199         "IDAQAB",
1200 
1201         "CN=Microsoft Root Authority",
1202         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQK9wXDmO/JOGyifl3heMOqiqY" +
1203         "0lX/j+lUyjt/6doiA+fFGim6KPYDJr0UJkee6sdslU2vLrnIYcj5+EZrPFa3piI9YdPN4P" +
1204         "AZLolsS/LWaammgmmdA6LL8MtVgmwUbnCj44liypKDmo7EmDQuOED7uabFVhrIJ8oWAtd0" +
1205         "zpmbRkO5pQHDEIJBSfqeeRKxjmPZhjFGBYBWWfHTdSh/en75QCxhvTv1VFs4mAvzrsVJRO" +
1206         "rv2nem10Tq8YzJYJKCEAV5BgaTe7SxIHPFb/W/ukZgoIptKBVlfvtjteFoF3BNr2vq6Alf" +
1207         "6wzX/WpxpyXDzKvPAIoyIwswaFybMgdxOF3wIDAQAB",
1208 
1209         "CN=Microsoft Root Certificate Authority",
1210         "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8136gGfUWqepDCyQINA1CDx1hM" +
1211         "23B4mcidrezsNg+pFoWp6UcSkYdnzC4MgldpQOWPoENDbm36/3gLrpWAsrk+WdBeN3IpH3" +
1212         "NGQ8IpEdXuEJkLwU/vx1WBnhebcHkqOuiFkI2J8HygNY/GgpbTLX0qjLS/zhC0gyT+bruK" +
1213         "1P5FxvE5SZ25XVdduoGreUkbR3W/VIDI9qeX0UcAR9ba+Q9dpw2Ee3v5svbOcFt+ERYKx5" +
1214         "kRR8xdam5OF+1cN+5ZLSPAC1NoLeeeFt87Vu+J8zyctSfXOYNtuLoWuilZebo97CTSb/Bp" +
1215         "ZnJQbI56zk7hIzlTGZyDUITjTKeVPVtb5jMllANsClTgRNPdtbBzPkWL/vP1Nk2EJZNVf9" +
1216         "D0V8JARNntY4dBGXIpDOaER0km/VS2+whuPHNkKg0PzBwFr5o2G5MEdxlgoWsJHAQpXvEH" +
1217         "8oauMqH7HkzQM/d3EExyD8SQ8dRYik18t+iK2OLexF28RRBMkq/OyGnpoRl1vezlOI5uK3" +
1218         "/ayVwihA2+8EkN+BMznZskWlI4cGpVWJMbsGLWAOQRh9Hy61l8sR6xXVJKWU7xUUif1Lc/" +
1219         "oyW/zRMwD5WWJwBzLqLqtALXvK3SFnGzCZjxaqI6hB0bBuEZs2xN5AdJzhWGXBYB56WzjI" +
1220         "j7sEJnzUFkDltmtsqob9AL/OwTUCAwEAAQ==",
1221 
1222         "CN=NetLock Expressz (Class C) Tanusitvanykiado",
1223         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr7LBsYYojJa9gIOPZn/yTC9tdjbChs0" +
1224         "A6gs79deB4MgOGWoaVke1T+p1A/Obo3dlbegO9XfM7DMNReZutVaDp0AMQrwq6FELZUiYR" +
1225         "IsfSIMyCpJqp/riBdp1qt9I2dT6xhgn2bm1+Trd67K5xhPYEMwglMut0rBZExuRAkx1/rQ" +
1226         "IDAQAB",
1227 
1228         "CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado",
1229         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeL" +
1230         "Vu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX" +
1231         "9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8Wg" +
1232         "D/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF" +
1233         "/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCo" +
1234         "R64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQAB",
1235 
1236         "OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado",
1237         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBN" +
1238         "wcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX" +
1239         "iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQ" +
1240         "IDAQAB",
1241 
1242         "CN=Post.Trust Root CA",
1243         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1n8T5A0k2Nj76bbDsVKjTty3O+" +
1244         "L3Dl+B5gHwpuY2cNgTc6H/UgiQ8hW88jIcqNfhBhB7QaiUxz89RBXcgFHnMP5TSPWQX21t" +
1245         "JeBgu6D71sYp+E1wUBo3oA7NeCq2aPOZ1AyOXhJi/8JfWporiEequ6HZdfAsXP5twrFbMc" +
1246         "yDhxqnvpAO6BBUU1ILnEnzgAL+byemo1cwuNu40AAEA+Tl1EMG66toTWgm0pk0ueASln9L" +
1247         "u2tuIXHmCEVKHWYNN8kD4dHK3LEvcPa3gWKWG2Sn/rvhhutBn6ic2Mqg4dYv+A/hukA492" +
1248         "3RpcpMGciW3MxJHAq206iROvna7B3Nc0okPwIDAQAB",
1249 
1250         "CN=PTT Post Root CA, 0.9.2342.19200300.100.1.3=ca@ptt-post.nl",
1251         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsH7iOgHxSK1T1HHO276A4FCtma" +
1252         "KEeto6JyQ6EYE2Eg3mo5mOpMwmtQ5hxu4oq22G3y6XYfpAacmNjMQxe/pSXlZMIJ5gGl9s" +
1253         "SnjJiTyflYasd2cOpg5C6CxiSTJLBD4yQ5AOCiLKyHQOhe+DgcVb8ttshQhvTialBqt245" +
1254         "iiTl7EgODo+8zpMGzycmGuJ35T1BWUD9KPeYLZ9o+rxhPmHJh0SwBhDnlpVPKQsqMJAWX3" +
1255         "BEdsTvopK/AOBheT3ILAEd6PsDBGWUhKZs42r8fPMdGSdBQj1aq64InbEtHs1GkjuAsWST" +
1256         "POGvninF98aB13uwGqZ+Ixxv/WOmn9DBt8IwIDAQAB",
1257 
1258         "CN=Saunalahden Serveri CA, EmailAddress=gold-certs@saunalahti.fi",
1259         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5wQp3NbgUtPWTwCvHIGIvzxUcv" +
1260         "OeeWP9y2DaDHxyL8obqeIQaWd6OZ/CoCXMg4ONgxEcuP3n26mIowySIVfBquLqM35KZgO8" +
1261         "c43SHCn9x39D7Y/rV3uhQb9NczFKNyi0GFdYPGhwUJO6EB14zZPDwoLvuN8PDFjVMFdDOh" +
1262         "QlKjhZBrREzdvJXkbyS7gcQ0GB0j5Dsq4hnhtKgHymyrP0JqkuLPi39zwYD5sybxEJc8TN" +
1263         "L+jT7Ek284GN2ML/0Bpt3dgUvzLQ6cMNPgiv7dpLnWrPE4uQgmn612cjYUtb/aWAZB1696" +
1264         "XT2ncceLtR++dGgJBxcbYW+EO0Gb0Yq952ewIDAQAB",
1265 
1266         "CN=Saunalahden Serveri CA, EmailAddress=silver-certs@saunalahti.fi",
1267         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0neMvIdsNk5TqmhgRbgjd2fj7k" +
1268         "mC5mx/XpJdtRxhUteoYEsW+ut5fp1MkulXe16GMKkoPH030SHidhoZw++q2u74AZ4aOSov" +
1269         "k3UDZj9uKU2NhGOMpx8VlLQ0SbTk00GruvvEXLWecvUoyjKCY0zHRPi0HcSKCldVkK8wiV" +
1270         "QOp2gm00AHIrPOPKP7mNckPN58gkm0NIx9JNtkbmSy6f+GyKx+q1Pk0kH0EYTuR0wIHUTm" +
1271         "Vk0AfNqJQjnveAjRhea+XJ4zuTX/HM70g7XyZMUxSKm0rMXYPIwabab/Qq3z+EvOrNrFir" +
1272         "APAyPB9fPHWX8w8d9mHVoxBaJGHTnkVbOtDwIDAQAB",
1273 
1274         "C=hk, O=C&W HKT SecureNet CA Class B",
1275         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn+AlkQ8EV8LHXLFlAmYPqP3YMQ" +
1276         "5vgmz5wx6w46C9OERSx4x2EnhMfsIrjIrk+dwK4JVF3+seftJE+AMVAOzEsTx6tk22lgp3" +
1277         "vAdg7/C3N/6J/bLYB6tS/oI/vDVnM9n7LNy1WGGiDLF9lNGohGkkPZfNmwhMUImBmh/Swi" +
1278         "BvzD8OZcThSEncO/nlKjEHbqZrR6gZWq7ToXS1vMLbOT36q7DwySIJ1DxGaGwuLh/4qIwR" +
1279         "oXY1UpLXq4gh3L3pnNn4Pt4wMUwCIi9XZrtWcjk3UJmvV9D0S9Qp7alvxtOyhpGLHRBtaB" +
1280         "Zk8Q5tv15n/bKOcGXnb3K8RHWrAXb/N2RFIQIDAQAB",
1281 
1282         "C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority",
1283         "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6z" +
1284         "V4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXAT" +
1285         "cXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAA" +
1286         "E=",
1287 
1288         "C=au, O=SecureNet CA Class A",
1289         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqaN8+JCzjoRM4Aq+qxIqjQw+L7" +
1290         "XdmxCIuWq3h3Ugt0vvIiMG6/BWMvfLLXDFA2+3wdDDZhMCvVVJh4fpLZ6l5XY2q+JkJViI" +
1291         "wxsbAvBdsY+fE03CUim0EDVPNoivCy2BCCRhw2iNWm0x6FQZUxf9pxP2QJmmqCnAn0J7Jy" +
1292         "nB7tvvjQNkJYGx/pUaHtoQQWIbVn8YGEiY0k1LwRhot2lna2RMbo8CvxRpe/ZEIxDpLrxe" +
1293         "Ys1bnMyjjoxRgbSiorG8qMnoKpiqu0sVoeHpkHqef+hlBegRcXpv43XeVT/L2OrIAM0llH" +
1294         "JkHu99ED5NL5F5vQLq15DBSWhuWRQl4t3dCQIDAQAB",
1295 
1296         "C=au, O=SecureNet CA Class B",
1297         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmPZxhVadudGZcc0kfl73Va7+J" +
1298         "Y1LinKp30KHvcxUuhayNPPOQFOW/AfsbhK0rNHQ2Y/AUBOMEnhD/3rEmN4zPYWYhj1b2n9" +
1299         "fm4zdiGjwIgP6uYl/KmXzBhyxzG2C5vNwsV4YWNFrDSmJ3hoxL1SaM6ETdIkpShsgObK5s" +
1300         "/mmp5QeM7zNtKjQ1ocBq/LIO7QLMREGJBssZFkZbm3hYNLqJGZxeCc97hQ19OwT5rtY/tN" +
1301         "9NQoJDqAW3uTjMUFhK87hv6BMce2nV8a6pB7sEZesghSAFcNVVKDeJVK/WiPntlQtktT+v" +
1302         "KFApVOOPWDp5bUMT8/p8o3U9zFL20adKbMvwIDAQAB",
1303 
1304         "C=au, O=SecureNet CA Root",
1305         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyi02Dz1v3oGkb2lQkyzfJ6IZp" +
1306         "nF2xfURVTDe8DwJFZmmL9E4HkTdmiu3Zp0z6Lpl+bBwKnD9yzVNjtzna+C2twOX1Ov625Q" +
1307         "16jwqo6rY9Kbdf5VCnzRs8BZk1Eqh2mKGe3k19eOFKu1GVizzmzgTYLTA4TBqwAYekmoFX" +
1308         "0IyQFgJ5To+wlgntE/Ts0To3j9ZfcRX/abADCMIu0oiWUb0x9he8Mjo+PGgPmD8/e63oZ4" +
1309         "X/aVw4xqSCJlhdMiefb9RBboD2EENip1xtviZRQnYtyCXJYSMw5MGNX2PJ2xzWEcsYX5A9" +
1310         "G69kzW7p990ZIh8PYKFqQ0h/dWj5O+l69SpwIDAQAB",
1311 
1312         "C=au, O=SecureNet CA SGC Root",
1313         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1uxDYpTIbpSiDiQQmVE/Vbrc8" +
1314         "WF8wYx5Qj8jLHVescLIwq8WgkiAfinwN5XdDGLrTbMXnP39kTwMcr1LKIF8wocMHqGM+JG" +
1315         "U/Zk1kersVOUY3fEYtMvC+pfsHUCXvgrzybz3tKt62V/vC5BhPyZmumBG6ecZsf49bKEGy" +
1316         "B1ciHHhP8CRswPpmmFfVkh1Q6nXVYVT8wfQSx/Zhuv691Bo+yp5lZK/h6nxFwiny/gC3QB" +
1317         "cMhzgwoHpGie5FEOjXQxL6LG2ggQK+8lPmyGtUbnl4PAq96wrgYa58j7736tjrCaRfGb9b" +
1318         "HoMbtkAL9/kWbNqK+V6hM6Akxb68CT5EH8rQIDAQAB",
1319 
1320         "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1321         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1322         "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1323         "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1324         "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1325         "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1326         "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1327 
1328         "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1329         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1330         "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1331         "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1332         "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1333         "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1334         "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1335 
1336         "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1337         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1338         "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1339         "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1340         "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1341         "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1342         "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1343 
1344         "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1345         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1346         "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1347         "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1348         "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1349         "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1350         "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1351 
1352         "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1353         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1354         "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1355         "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1356         "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1357         "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1358         "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1359 
1360         "C=hk, O=C&W HKT SecureNet CA Root",
1361         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBiikFaM1l2/RliRJ+qddeCk66" +
1362         "JQcIdFSUmSa7c5AEt7qNpA4eYNouA3AUhNznLhXJPTw/mSDSTvSM5HKsutkjqq1pWy8hme" +
1363         "PpV8j2ACdJMWKGn+O+5deJMcejwj6WE5bMUwLR+EkgVx53TBQkfpMLGjFww2Y89Q0DKoh6" +
1364         "VAYhQROPvOL40zsIvpjnD7sJ7HXQPu9uWNcjzIvFSSz8qQ38jbrwXx61DK0QWsBbQBFZb1" +
1365         "6zihafeDQ+g8pl2lLLokFi/7DjJwphLWmTb3axuj5/zHG8jYL3XRNbPpwtaPBB3BtX4EOz" +
1366         "iJ5KMj8P3KvczrnRcGFXLt0Ob71m+z8Z0+uwIDAQAB",
1367 
1368         "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1369         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1370         "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1371         "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1372         "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1373         "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1374         "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1375         
1376         "CN=SERVICIOS DE CERTIFICACION - A.N.C.",
1377         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsiov7CtZakOTiUYqiuXs+gX64s" +
1378         "jeQWuvA9sAWu9IN89XifvdyZIQ3ncDlRyQPse2ZyU7VZjv2Tz+JuSKO0SpdDeDCncndLip" +
1379         "ca3dlxPSyqIuuLqdyb5Z6Nly8oqFZhxHXrSHgtYP32cmpr02sfNdkFBRdjIsOy+qX2Fe41" +
1380         "TVEl3/DY0Rx4J6Nt/hTBbEdN0tau/QsfAzp/6/N2dDEi55SpSvhPsHEQhOMJN16QFUzsXe" +
1381         "FIbwrq6bciUPRHfi82yveZwuSceemHYyFpq8AN7gtCAFkRfdgBUU7jZBxCGP7tkAShnGcW" +
1382         "GlEV0AO+SndGw6Sm6D4HoxXCFl+AiHQodn5QIDAQAB",
1383 
1384         "CN=SIA Secure Client CA",
1385         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS/LBAYGpmY1Jm5mkJcY2BmB4dHfPgSQ" +
1386         "3IK2/Qd1FFxZ1uo1xw3hV4Fh5f4MJi9H0yQ3cI19/S9X83glLGfpOd8U1naMIvwiWIHXHm" +
1387         "2ArQeORRQjlVBvOAYv6WpW3FRsdB5QASm2bB4o2VPtXHDFj3yGCknHhxlYzeegm/HNX8ow" +
1388         "IDAQAB",
1389 
1390         "C=IT, O=SIA S.p.A., L=Milano, CN=SIA Secure Server CA",
1391         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA28ELzCfTEiIuuWQWdKxZJ+IqkA" +
1392         "CSntWYXCtRbhsTb1RvShCihethC+ztnH7Of2WTbsxsQZzILarGs5v7THCcEXXzcom6iQCt" +
1393         "xy5J53PagLIs/vKXmfQCGzQvOaqL5u8F/Ln1ulR/ob+OHkg2Mwl0Yac9x5skx8OJzcpOKD" +
1394         "EjBhxiFY7fTxtrLUri9LDczvOQ/XmBE8E+Lma8+SJNCy9iM42oK+rpb3OnN5QEL+leTQ3p" +
1395         "7XwyP3lK5jp2KSBQ84+CRHJsMDRIWKpdGz8B6yHs6n6oK4Rd9sExlU8pe7U1t/60BlewFN" +
1396         "fyVVmMupu5MT/lqqrvJXCVkjZB8VWfwQhEnQIDAQAB",
1397 
1398         "OU=Public CA Services",
1399         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOeC2xUTrnnCtF+SjyO8uvfG0Q" +
1400         "Cv1lRp8V2mYvhh0Zzeyjss6VwWJzTmuNHKdO8leGRt/hzoiXMxU2dnhsStamjnClZEgzpY" +
1401         "R4l3Gtpv8vkHQMk9Ae9q0dlrhJ7FaytOtyz4pGpXq2gxuhlmuuwbV/vOStZLeMPBgT1Llj" +
1402         "CZqcMt4uQSJgqkYxIc1HfIgdSnVUMt/ARWndwLrrdsCtozkIgFyX5UgujSMtDXAUkqNZB5" +
1403         "OXPWi7xhzYdtUBUFTKnoSkcxiwXM5flC1xJg+Do/o6k2GqWGNiymBIMJ9lLFsH0fiEGQmM" +
1404         "VlaJYQshPJFkm9Kr6wSKfC/S1eVtA3TVhR+wIDAQAB",
1405 
1406         "OU=TC TrustCenter Class 1 CA",
1407         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwKeu0drOu17ZbtF7nveOxnEkEV1uhq9" +
1408         "l/Exv9umGr2Odx3y0AlF1RSH0j73VihJA8Ch9ZEXQvjoCl/TACPSlSzXIaSSGcvMtSjkih" +
1409         "Y5bIEIUwaVd0RcBahsbVPeBoV30xaiSNRZc+MX5oZjJuJG3sMjbJQcrwMUTIo2HKG6A2Hw" +
1410         "IDAQAB",
1411 
1412         "OU=TC TrustCenter Class 2 CA",
1413         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaOOjtMgApcYMBDb+MAdzaxq05pKmKL9" +
1414         "WLXGhfUMZi9Wa9ypEi7KodUdc9s1Gyg05dy0mw8ExV5Wstx4ULMBySToLUygLt92++3ODj" +
1415         "FLgFU/Ka9FaLWp6Fk9G0glauTbuoS1cWvP74WJ74KY2we814yU+si2cM8Zz7/FebV1xPDQ" +
1416         "IDAQAB",
1417 
1418         "OU=TC TrustCenter Class 3 CA",
1419         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2tME1BS4NjeygQGocDiemUJJrUBsH3i" +
1420         "7ndszg2vyEqF6MY2orTdlOAnYRwQvyjXnKALbxsA7X+6QXPa+raXqWJ7+vM6GaKlmqxLU3" +
1421         "CPISpTG2Q/UylnEoKKuNKIbfu+7jDH0w1sNSq49dJ5xrwKPnBWtXSUSzbupkz9KOelB3dw" +
1422         "IDAQAB",
1423 
1424         "OU=TC TrustCenter Class 4 CA",
1425         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/L2PWNnuyDdNV9WRs5iVdxrTIFLolOI" +
1426         "PrVmKlVallo/QjmcJLudDNVGemo6CjqTMrduS9rXey7VwSdMPFtg9SmnKTQ5BiZhUPRaXd" +
1427         "4N24b0BuV8F5cqNgqrp2HRKJU1r8Ar7hCRPFSi/cPYsZrdeLJEX7TPTNXDUdKUxR8/JsVQ" +
1428         "IDAQAB",
1429 
1430         "CN=Thawte Premium Server CA",
1431         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSNjZqi9fCW57agUFijzjuSQRV1tDvHB" +
1432         "uVFkfvGEg1OlL0K2oGjzsv6lbjr4aNnhf3nrRldQJN78sJoiFR2JvQZ9C6DZIGFHPUk8uX" +
1433         "KgCcXE4MvPoVUvzyRG7aEUpuCJ8vLeP5qjqGc7ZGU1jIiQW9gxG4cz+qB430Qk3nQJ0cNw" +
1434         "IDAQAB",
1435 
1436         "C=hk, O=C&W HKT SecureNet CA SGC Root",
1437         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqFNPj0Pdr+zBtA0bX7cIoprIQu" +
1438         "Nt1yUa3+DKvC8iJPlpIr0arVHncfe1dtTzPsg+EdBNe5keGLeezT5hG0URS1sm3Ck8AE0R" +
1439         "2h2Pnh903hVAvDDJD9/4LXzYjZ2g4J+wzydgzzgRCO82L3xONh0mAqf01FBDgUnr3beWFD" +
1440         "BjMtEDzSG8N5EePmWuFoL2FWBLUTuW5RnowvemBYE6qH8YWD53w1kAg/T1eUlgpy4DPgH9" +
1441         "heLfoZqJ2fhkCiuEzUPNJTUAXjBmdKHHCHWsSSeC17CVNW4dmYDrkqAtWtY4u7VHJ6sazL" +
1442         "9TU8FGsm/o101XEd2wNUgfqybqVg24CjC22wIDAQAB",
1443 
1444         "CN=Thawte Server CA",
1445         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTpFBuyP9Wa+bPXbbqDGh1R6KqwtqEJf" +
1446         "yo9EdR2oW1IHSUhh4PdcnpCGH1Bm0wbhUZAulSwGLbTZme4moMRDjN/r7jZAlwxf6xaym2" +
1447         "L0nIO9QnBCUQly/nkG3AKEKZ10xD3sP1IW1Un13DWOHA5NlbsLjctHvfNjrCtWYiEtaHDQ" +
1448         "IDAQAB",
1449 
1450         "CN=UTN - DATACorp SGC",
1451         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLi" +
1452         "t6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/W" +
1453         "w5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1k" +
1454         "duSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2A" +
1455         "swkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorG" +
1456         "kVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB",
1457 
1458         "CN=UTN-USERFirst-Hardware",
1459         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsffDOD+0qH/POYJRZ9Btn9L/WP" +
1460         "PnnyvsDYlUmbk4mRb34CF5SMK7YXQSlh08anLVPBBnOjntKxPNZuuVCTOkbJex6MbswXV5" +
1461         "nEZejavQav25KlUXEFSzGfCa9vGxXbanbfvgcRdrooj7AN/+GjF3DJoBerEy4ysBBzhuw6" +
1462         "VeI7xFm3tQwckwj9vlK3rTW/szQB6g1ZgXvIuHw4nTXaCOsqqq9o5piAbF+okh8widaS4J" +
1463         "M5spDUYPjMxJNLBpUb35Bs1orWZMvD6sYb0KiA7I3z3ufARMnQpea5HW7sftKI2rTYeJc9" +
1464         "BupNAeFosU4XZEA39jrOTNSZzFkvSrMqFIWwIDAQAB",
1465 
1466         "CN=UTN-USERFirst-Network Applications",
1467         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/uRoeQ2VYWsBjRboJpYsvi1Dw" +
1468         "V3g64ysXaSaOwjSsl2P+Octjd5A7mraY0HJbYZZ+SwGxhzYUrofs3TL2TjpnwM+heAow1H" +
1469         "iU9RcS/u/D/5uBaAh4mTJSCaQ4JpJHYoWTWhHcB/gwZkFiAs00mkhbTAYX9RCPhoFZGAy6" +
1470         "XV7js69IQEXmBZp4w0cu64eMXROxJKb35lJ7mkVcW5b0OkxR0smcBSpHhMFbNAmAhrQ8YB" +
1471         "sHp79WscIj/L7/+o0DpLdhWe0tHGLuPbVxsyorhv6IamP3Cr5XCSq0QeQFD7nKNi5GxuoM" +
1472         "je4oBC+ukv6M4yBI98jbccozU8Fd2ew66XpQIDAQAB",
1473 
1474         "CN=VeriSign Class 3 Public Primary Certification Authority - G3",
1475         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7qcUvx4Hxoebxs3c734yWuUEj" +
1476         "BP8DZH9dCRCvUXyKVhwRZATfuKYZDldiDBEQZ9qyxupvURQY76La0qYVmkZyZM0Oi8Ultw" +
1477         "IARY0XrJpGm8gxdkrQWLvNBYzo2M9evwQkkLnZcnZzJu4a6TFRxwvCBNLxjekojobIVXER" +
1478         "rpfuMmEVSiRZZVg8owiejc2KPtKoA/f3llVz4VIGYIL5WTv6pHL6hGl/AS4v7CCitR5nbm" +
1479         "t0a34g2mzKjDTFlVieboU1wc6p3wYhYLp8lfDPDewnbOr/dq8vpBpqIzFMnlemPTnmI31Y" +
1480         "Vlng7mUyR0G14dElNbxyzng0k7Fa6KaLlXlwIDAQAB",
1481 
1482         "CN=VeriSign Class 4 Public Primary Certification Authority - G3",
1483         "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArculEWnGWavxj7UZD1bOzLUfIO" +
1484         "SeJiVL4HNliVne0IPk9Q+1u63xfOgh/OToDO58RSIZdpK0E7cgWwn6Ya6o8qWNhcIq1t5m" +
1485         "NtKbAvSokmB8nGm0jyQe0IZS9jKcQVgeIr3NRWKVCG7QZt1ToszwENxUc4sEoUYzM1wXQL" +
1486         "meTdPzvlWD6LGJjlp8mpYikDuIJfLSU4gCDAt48uY3F0swRgfkgG2m2JYu6Cz4EbM4DWam" +
1487         "m+rJI1vbjuLzE44aWS2qAvDspIdm3ME/9di59OyCxtI9lR3lwE+EydmjRCgGatdFrPBrau" +
1488         "9OX/gRgh44YzRmUNQ+k3P6MMNmrf+TLZfvAwIDAQAB",
1489 
1490         "OU=VeriSign Trust Network",
1491         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1492         "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1493         "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1494         "IDAQAB",
1495 
1496         "OU=VeriSign Trust Network",
1497         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1498         "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1499         "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1500         "IDAQAB",
1501 
1502         "OU=VeriSign Trust Network",
1503         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1504         "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1505         "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1506         "IDAQAB",
1507 
1508         "OU=VeriSign Trust Network",
1509         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1510         "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1511         "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1512         "IDAQAB"
1513     };
1514 
1515     public static boolean alwaysFalse = false;
1516 
1517     static class entropySpinner extends Thread {
1518         volatile boolean stop = false;
1519         byte counter = 0;
1520         entropySpinner() { start(); }
1521         public void run() {
1522             while (true) {
1523                 counter++;
1524 
1525                 // without this line, GCJ will over-optimize this loop into an infinite loop. Argh.
1526                 if (alwaysFalse) stop = true;
1527 
1528                 if (stop) return;
1529             }
1530         }
1531     }
1532     
1533     private static volatile boolean initializationFinished = false;
1534     static { 
1535         entropySpinner[] spinners = new entropySpinner[10];
1536         for(int i=0; i<spinners.length; i++) spinners[i] = new entropySpinner();
1537 
1538         for(int i=0; i<pad1.length; i++) pad1[i] = (byte)0x36;
1539         for(int i=0; i<pad2.length; i++) pad2[i] = (byte)0x5C;
1540         for(int i=0; i<pad1_sha.length; i++) pad1_sha[i] = (byte)0x36;
1541         for(int i=0; i<pad2_sha.length; i++) pad2_sha[i] = (byte)0x5C;
1542 
1543         try { 
1544             if (Log.on) Log.info(SSL.class, "reading in trusted root public keys..."); 
1545             trusted_CA_public_keys = new SubjectPublicKeyInfo[base64_encoded_trusted_CA_public_keys.length / 2];
1546             trusted_CA_public_key_identifiers = new String[base64_encoded_trusted_CA_public_keys.length / 2];
1547             for(int i=0; i<base64_encoded_trusted_CA_public_keys.length; i+=2) {
1548                 trusted_CA_public_key_identifiers[i/2] = base64_encoded_trusted_CA_public_keys[i];
1549                 byte[] b = Base64.decode(base64_encoded_trusted_CA_public_keys[i+1]);
1550                 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(b)); 
1551                 trusted_CA_public_keys[i/2] = new SubjectPublicKeyInfo((DERSequence)dIn.readObject());
1552             }
1553 
1554         } catch (Exception e) { 
1555             if (Log.on) Log.info(SSL.class, e);
1556         } 
1557         
1558         if (Log.on) Log.info(SSL.class, "generating entropy..."); 
1559         randpool = new byte[10];
1560         try { Thread.sleep(100); } catch (Exception e) { }
1561         for(int i=0; i<spinners.length; i++) {
1562             spinners[i].stop = true;
1563             randpool[i] = spinners[i].counter;
1564         }
1565         
1566         MD5Digest md5 = new MD5Digest();
1567         md5.update(randpool, 0, randpool.length);
1568         intToBytes(System.currentTimeMillis(), randpool, 0, 4); md5.update(randpool, 0, 4);
1569         intToBytes(Runtime.getRuntime().freeMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1570         intToBytes(Runtime.getRuntime().totalMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1571         intToBytes(System.identityHashCode(SSL.class), randpool, 0, 4); md5.update(randpool, 0, 4);
1572         Properties p = System.getProperties();
1573         for(Enumeration e = p.propertyNames(); e.hasMoreElements();) {
1574             String s = (String)e.nextElement();
1575             byte[] b = s.getBytes();
1576             md5.update(b, 0, b.length);
1577             b = p.getProperty(s).getBytes();
1578             md5.update(b, 0, b.length);
1579         }
1580         randpool = new byte[md5.getDigestSize()];
1581         md5.doFinal(randpool, 0);
1582 
1583         if (Log.on) Log.info(SSL.class, "SSL is initialized."); 
1584         initializationFinished = true;
1585         SSL.class.notifyAll();
1586     } 
1587 
1588 
1589     /**
1590      *  A PKCS1 encoder which uses SSL's built-in PRNG instead of java.security.SecureRandom.
1591      *  This code was derived from BouncyCastle's org.bouncycastle.crypto.encoding.PKCS1Encoding.
1592      */
1593     private static class PKCS1 implements AsymmetricBlockCipher {
1594         private static int HEADER_LENGTH = 10;
1595         private AsymmetricBlockCipher engine;
1596         private boolean forEncryption;
1597         private boolean forPrivateKey;
1598         
1599         public PKCS1(AsymmetricBlockCipher cipher) { this.engine = cipher; }   
1600         public AsymmetricBlockCipher getUnderlyingCipher() { return engine; }
1601 
1602         public void init(boolean forEncryption, CipherParameters param) {
1603             engine.init(forEncryption, (AsymmetricKeyParameter)param);
1604             this.forPrivateKey = ((AsymmetricKeyParameter)param).isPrivate();
1605             this.forEncryption = forEncryption;
1606         }
1607 
1608         public int getInputBlockSize() { return engine.getInputBlockSize() - (forEncryption ? HEADER_LENGTH : 0); }
1609         public int getOutputBlockSize() { return engine.getOutputBlockSize() - (forEncryption ? 0 : HEADER_LENGTH); }
1610 
1611         public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1612             return forEncryption ? encodeBlock(in, inOff, inLen) : decodeBlock(in, inOff, inLen);
1613         }
1614 
1615         private byte[] encodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1616             byte[]  block = new byte[engine.getInputBlockSize()];
1617             if (forPrivateKey) {
1618                 block[0] = 0x01;                        // type code 1
1619                 for (int i = 1; i != block.length - inLen - 1; i++)
1620                     block[i] = (byte)0xFF;
1621             } else {
1622                 getRandomBytes(block, 0, block.length);
1623                 block[0] = 0x02;                        // type code 2
1624 
1625                 // a zero byte marks the end of the padding, so all
1626                 // the pad bytes must be non-zero.
1627                 for (int i = 1; i != block.length - inLen - 1; i++)
1628                     while (block[i] == 0)
1629                         getRandomBytes(block, i, 1);
1630             }
1631 
1632             block[block.length - inLen - 1] = 0x00;       // mark the end of the padding
1633             System.arraycopy(in, inOff, block, block.length - inLen, inLen);
1634             return engine.processBlock(block, 0, block.length);
1635         }
1636 
1637         private byte[] decodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1638             byte[]  block = engine.processBlock(in, inOff, inLen);
1639             if (block.length < getOutputBlockSize())
1640                 throw new InvalidCipherTextException("block truncated");
1641             if (block[0] != 1 && block[0] != 2)
1642                 throw new InvalidCipherTextException("unknown block type");
1643 
1644             // find and extract the message block.
1645             int start;
1646             for (start = 1; start != block.length; start++)
1647                 if (block[start] == 0)
1648                     break;
1649             start++;           // data should start at the next byte
1650 
1651             if (start >= block.length || start < HEADER_LENGTH)
1652                 throw new InvalidCipherTextException("no data in block");
1653 
1654             byte[]  result = new byte[block.length - start];
1655             System.arraycopy(block, start, result, 0, result.length);
1656             return result;
1657         }
1658     }
1659 
1660 }
1661 
1662