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