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