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