propose-patch
[org.ibex.core.git] / src / org / xwt / util / SSL.java
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