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