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