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