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