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