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