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