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 {
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((DERSequence)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.equalsIgnoreCase(hostname))
379 throw new SSLException("connecting to host " + hostname + " but server certificate was issued for " + CN);
381 SimpleDateFormat dateF = new SimpleDateFormat("MM-dd-yyyy-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(0, 4) + "-" + s.substring(4, 6) + "-" + s.substring(6, 8) + "-" +
386 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" +
387 s.substring(12, 14) + "-" + s.substring(14);
389 Date startDate = dateF.parse(s, new ParsePosition(0));
391 s = tbs.getEndDate().getTime();
392 s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
393 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
394 Date endDate = dateF.parse(s, new ParsePosition(0));
396 Date now = new Date();
397 if (!ignoreUntrustedCert && now.after(endDate))
398 throw new SSLException("server certificate expired on " + endDate);
399 if (!ignoreUntrustedCert && now.before(startDate))
400 throw new SSLException("server certificate will not be valid until " + startDate);
402 Log.log(this, "server cert (name, validity dates) checks out okay");
406 // don't check the top cert since some very old root certs lack a BasicConstraints field.
407 if (certlen + 3 + i < numcertbytes) {
408 // defend against Mike Benham's attack
409 X509Extension basicConstraints = this_cert.getTBSCertificate().getExtensions().getExtension(X509Extensions.BasicConstraints);
410 if (basicConstraints == null) throw new SSLException("certificate did not contain a basic constraints block");
411 DERInputStream dis = new DERInputStream(new ByteArrayInputStream(basicConstraints.getValue().getOctets()));
412 BasicConstraints bc = new BasicConstraints((DERSequence)dis.readObject());
413 if (!bc.isCA()) throw new SSLException("non-CA certificate used for signing");
416 if (!isSignedBy(last_cert, this_cert.getSubjectPublicKeyInfo()))
417 throw new SSLException("the server sent a broken chain of certificates");
420 last_cert = this_cert;
424 if (Log.on) Log.log(this, " Certificate (" + numcerts + " certificates)");
426 if (ignoreUntrustedCert) break;
428 boolean good = false;
430 // pass 1 -- only check CA's whose subject is a partial match
431 String subject = this_cert.getSubject().toString();
432 for(int i=0; i<trusted_CA_public_keys.length; i++) {
433 if (subject.indexOf(trusted_CA_public_key_identifiers[i]) != -1 && isSignedBy(this_cert, trusted_CA_public_keys[i])) {
434 if (Log.on) Log.log(this, "pass 1: server cert was signed by trusted CA " + i);
440 // pass 2 -- try all certs
442 for(int i=0; i<trusted_CA_public_keys.length; i++) {
443 if (isSignedBy(this_cert, trusted_CA_public_keys[i])) {
444 if (Log.on) Log.log(this, "pass 2: server cert was signed by trusted CA " + i);
450 if (!good) throw new SSLException("server cert was not signed by a trusted CA");
454 if (Log.on) Log.log(this, "got ServerKeyExchange");
455 serverKeyExchange = rec;
459 if (Log.on) Log.log(this, "got Request for Client Certificates");
460 cert_requested = true;
463 case 14: if (Log.on) Log.log(this, " ServerHelloDone"); return;
464 default: throw new SSLException("unknown handshake of type " + rec[0]);
469 public void readServerFinished() throws IOException {
471 byte[] rec = readHandshake();
472 if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
474 byte[] expectedFinished = concat(new byte[][] {
475 md5(new byte[][] { master_secret, pad2,
476 md5(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
477 master_secret, pad1 }) }),
478 sha(new byte[][] { master_secret, pad2_sha,
479 sha(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
480 master_secret, pad1_sha } ) } ) } );
482 for(int i=0; i<expectedFinished.length; i++)
483 if (expectedFinished[i] != rec[i + 4])
484 throw new SSLException("server Finished message mismatch!");
486 if (Log.on) Log.log(this, "server finished message checked out okay!");
491 class SSLOutputStream extends OutputStream {
493 /** the underlying outputstream */
494 DataOutputStream raw;
496 /** the sequence number for sending */
497 public long seq_num = 0;
499 /** the encryption engine for sending */
500 RC4Engine rc4 = null;
502 public SSLOutputStream(OutputStream raw) { this.raw = new DataOutputStream(raw); }
503 public void flush() throws IOException { raw.flush(); }
504 public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); }
505 public void write(byte[] b, int off, int len) throws IOException { write(b, off, len, (byte)23); }
506 public void close() throws IOException {
507 write(new byte[] { 0x1, 0x0 }, 0, 2, (byte)21);
511 /** writes a single SSL Record */
512 public void write(byte[] payload, int off, int len, byte type) throws IOException {
514 // largest permissible frame is 2^14 octets
516 write(payload, off, 1 << 14, type);
517 write(payload, off + 1 << 14, len - 1 << 14, type);
522 raw.writeShort(0x0300);
526 raw.write(payload, off, len);
529 byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num);
530 byte[] encryptedPayload = new byte[MAC.length + len];
531 rc4.processBytes(payload, off, len, encryptedPayload, 0);
532 rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len);
533 raw.writeShort(encryptedPayload.length);
534 raw.write(encryptedPayload);
541 /** tacks a handshake header onto payload before sending it */
542 public void writeHandshake(int type, byte[] payload) throws IOException {
543 byte[] real_payload = new byte[payload.length + 4];
544 System.arraycopy(payload, 0, real_payload, 4, payload.length);
545 real_payload[0] = (byte)(type & 0xFF);
546 intToBytes(payload.length, real_payload, 1, 3);
547 handshakes = concat(new byte[][] { handshakes, real_payload });
548 write(real_payload, 0, real_payload.length, (byte)22);
551 public void sendClientHandshakes() throws IOException {
553 if (Log.on) Log.log(this, "shaking hands");
554 if (cert_requested) {
555 if (Log.on) Log.log(this, "telling the server we have no certificates");
556 writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 });
559 // generate the premaster secret
560 byte[] pre_master_secret = new byte[48];
561 pre_master_secret[0] = 0x03; // first two bytes of premaster secret are our version number
562 pre_master_secret[1] = 0x00;
563 getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2);
565 // encrypt and send the pre_master_secret
567 byte[] encrypted_pre_master_secret;
569 SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo();
570 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
571 BigInteger modulus = rsa_pks.getModulus();
572 BigInteger exponent = rsa_pks.getPublicExponent();
574 if (serverKeyExchange != null) {
576 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
577 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
579 int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff);
580 byte[] b_modulus = new byte[modulus_size];
581 System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size);
582 modulus = new BigInteger(1, b_modulus);
584 int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff);
585 byte[] b_exponent = new byte[exponent_size];
586 System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size);
587 exponent = new BigInteger(1, b_exponent);
589 byte[] server_params = new byte[modulus_size + exponent_size + 4];
590 System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length);
592 byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ),
593 sha(new byte[][] { client_random, server_random, server_params } ) } );
595 byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length,
596 serverKeyExchange.length - 6 - server_params.length);
598 for(int i=0; i<expectedSignature.length; i++)
599 if (expectedSignature[i] != recievedSignature[i])
600 throw new SSLException("ServerKeyExchange message had invalid signature " + i);
602 if (Log.on) Log.log(this, "ServerKeyExchange successfully processed");
605 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
606 rsa.init(true, new RSAKeyParameters(false, modulus, exponent));
608 encrypted_pre_master_secret = rsa.processBlock(pre_master_secret, 0, pre_master_secret.length);
609 writeHandshake(16, encrypted_pre_master_secret);
611 } catch (Exception e) {
612 SSLException t = new SSLException("exception encrypting premaster secret");
613 t.fillInStackTrace();
618 if (Log.on) Log.log(this, "Handshake complete; sending ChangeCipherSpec");
619 write(new byte[] { 0x01 }, 0, 1, (byte)20);
622 // compute master_secret
623 master_secret = concat(new byte[][] {
624 md5(new byte[][] { pre_master_secret,
625 sha(new byte[][] { new byte[] { 0x41 }, pre_master_secret, client_random, server_random })}),
626 md5(new byte[][] { pre_master_secret,
627 sha(new byte[][] { new byte[] { 0x42, 0x42 }, pre_master_secret, client_random, server_random })}),
628 md5(new byte[][] { pre_master_secret,
629 sha(new byte[][] { new byte[] { 0x43, 0x43, 0x43 }, pre_master_secret, client_random, server_random })})
632 // construct the key material
633 byte[] key_material = new byte[] { };
634 for(int i=0; key_material.length < 72; i++) {
635 byte[] crap = new byte[i + 1];
636 for(int j=0; j<crap.length; j++) crap[j] = (byte)(((byte)0x41) + ((byte)i));
637 key_material = concat(new byte[][] { key_material,
638 md5(new byte[][] { master_secret,
639 sha(new byte[][] { crap, master_secret, server_random, client_random }) }) });
642 client_write_key = new byte[export ? 5 : 16];
643 server_write_key = new byte[export ? 5 : 16];
645 System.arraycopy(key_material, 0, client_write_MAC_secret, 0, 16);
646 System.arraycopy(key_material, 16, server_write_MAC_secret, 0, 16);
647 System.arraycopy(key_material, 32, client_write_key, 0, export ? 5 : 16);
648 System.arraycopy(key_material, export ? 37 : 48, server_write_key, 0, export ? 5 : 16);
651 // see SSLv3 spec, 6.2.2 for explanation
652 byte[] client_untrimmed = md5(new byte[][] { concat(new byte[][] { client_write_key, client_random, server_random } ) });
653 byte[] server_untrimmed = md5(new byte[][] { concat(new byte[][] { server_write_key, server_random, client_random } ) });
654 client_write_key = new byte[16];
655 server_write_key = new byte[16];
656 System.arraycopy(client_untrimmed, 0, client_write_key, 0, 16);
657 System.arraycopy(server_untrimmed, 0, server_write_key, 0, 16);
660 rc4 = new RC4Engine();
661 rc4.init(true, new KeyParameter(client_write_key));
662 is.rc4 = new RC4Engine();
663 is.rc4.init(false, new KeyParameter(server_write_key));
666 writeHandshake(20, concat(new byte[][] {
667 md5(new byte[][] { master_secret, pad2,
668 md5(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
669 master_secret, pad1 }) }),
670 sha(new byte[][] { master_secret, pad2_sha,
671 sha(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
672 master_secret, pad1_sha } ) })
675 if (Log.on) Log.log(this, "wrote Finished message");
679 public void writeClientHello() throws IOException {
681 if (Log.on) Log.log(this, "sending ClientHello");
682 int unixtime = (int)(System.currentTimeMillis() / (long)1000);
684 byte[] out = new byte[] {
685 0x03, 0x00, // client version (SSLv3.0)
687 // space for random bytes
688 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
689 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
692 0x0, // empty vector for sessionid
693 0x0, 0x4, 0x0, 0x4, 0x0, 0x3, // we support two ciphersuites: SSL_RSA_WITH_RC4_128_MD5 and SSL_RSA_EXPORT_WITH_RC4_40_MD5
694 0x1, 0x0 // we only support one compression method: none
697 // don't need to use secure random here since it's sent in the clear
698 Random rand = new Random(System.currentTimeMillis());
699 rand.nextBytes(client_random);
700 intToBytes(unixtime, client_random, 0, 4);
701 System.arraycopy(client_random, 0, out, 2, client_random.length);
703 writeHandshake(1, out);
708 // Static Helpers ////////////////////////////////////////////////////////////////////
710 /** copy the least significant num bytes of val into byte array b, startint at offset */
711 public static void intToBytes(long val, byte[] b, int offset, int num) {
712 for(int i=0; i<num; i++)
713 b[offset + num - i - 1] = (byte)((val & (0xFFL << (i * 8))) >> (i * 8));
716 /** fills b with random bytes */
717 public static synchronized void getRandomBytes(byte[] b, int offset, int len) {
718 MD5Digest md5 = new MD5Digest();
719 byte[] b2 = new byte[16];
722 md5.update(randpool, 0, randpool.length);
723 intToBytes(randcnt++, b2, 0, 8);
724 md5.update(b2, 0, 8);
726 int n = len < 16 ? len : 16;
727 System.arraycopy(b2, 0, b, offset, n);
733 public static byte[] computeMAC(byte type, byte[] payload, int off, int len, byte[] MAC_secret, long seq_num) {
734 byte[] MAC = new byte[16];
735 MD5Digest md5 = new MD5Digest();
736 md5.update(MAC_secret, 0, MAC_secret.length);
737 md5.update(pad1, 0, pad1.length);
739 byte[] b = new byte[11];
740 intToBytes(seq_num, b, 0, 8);
742 intToBytes(len, b, 9, 2);
743 md5.update(b, 0, b.length);
745 md5.update(payload, off, len);
748 md5.update(MAC_secret, 0, MAC_secret.length);
749 md5.update(pad2, 0, pad2.length);
750 md5.update(MAC, 0, MAC.length);
756 public static byte[] concat(byte[][] inputs) {
758 for(int i=0; i<inputs.length; i++) total += inputs[i].length;
759 byte[] ret = new byte[total];
761 for(int i=0; i<inputs.length; i++) {
762 System.arraycopy(inputs[i], 0, ret, pos, inputs[i].length);
763 pos += inputs[i].length;
768 SHA1Digest master_sha1 = new SHA1Digest();
769 public byte[] sha(byte[][] inputs) {
771 for(int i=0; i<inputs.length; i++) master_sha1.update(inputs[i], 0, inputs[i].length);
772 byte[] ret = new byte[master_sha1.getDigestSize()];
773 master_sha1.doFinal(ret, 0);
777 MD5Digest master_md5 = new MD5Digest();
778 public byte[] md5(byte[][] inputs) {
780 for(int i=0; i<inputs.length; i++) master_md5.update(inputs[i], 0, inputs[i].length);
781 byte[] ret = new byte[master_md5.getDigestSize()];
782 master_md5.doFinal(ret, 0);
786 // FEATURE: improve error reporting in here
787 /** returns true iff certificate "signee" is signed by public key "signer" */
788 public static boolean isSignedBy(X509CertificateStructure signee, SubjectPublicKeyInfo signer) throws SSLException {
792 String signature_algorithm_oid = signee.getSignatureAlgorithm().getObjectId().getId();
793 if (signature_algorithm_oid.equals("1.2.840.113549.1.1.4")) hash = new MD5Digest();
794 else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.2")) hash = new MD2Digest();
795 else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.5")) hash = new SHA1Digest();
796 else throw new SSLException("unsupported signing algorithm: " + signature_algorithm_oid);
799 // decrypt the signature using the signer's public key
800 byte[] ED = signee.getSignature().getBytes();
801 SubjectPublicKeyInfo pki = signer;
802 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
803 BigInteger modulus = rsa_pks.getModulus();
804 BigInteger exponent = rsa_pks.getPublicExponent();
805 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
806 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
808 // Decode the embedded octet string
809 byte[] D = rsa.processBlock(ED, 0, ED.length);
810 BERInputStream beris = new BERInputStream(new ByteArrayInputStream(D));
811 DERObject derob = beris.readObject();
812 DERSequence dercs = (DERSequence)derob;
813 DEROctetString deros = (DEROctetString)dercs.getObjectAt(1);
814 byte[] MD = deros.getOctets();
816 // generate our own hash
817 ByteArrayOutputStream baos = new ByteArrayOutputStream();
818 DEROutputStream dos = new DEROutputStream(baos);
819 dos.writeObject(signee.getTBSCertificate());
821 byte[] b = baos.toByteArray();
822 hash.update(b, 0, b.length);
823 byte[] md_out = new byte[MD.length];
824 hash.doFinal(md_out, 0);
826 // compare our hash to the signed hash
827 for(int j=0; j<MD.length; j++) if (md_out[j] != MD[j]) return false;
830 } catch (Exception e) {
836 // Embedded Trusted Public Keys //////////////////////////////////////////////
838 /** base64-encoded sequence of DER-encoded PKCS7 certs for all the "trusted root CA's" included with IE5.5 */
839 static String[] base64_encoded_trusted_CA_public_keys = new String[] {
841 "CN=ABA.ECOM Root CA",
842 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdMR4HlVQwcITMsFQgDiDYNGPe" +
843 "STurYG0w1ZvT7BzkNnAYohqO+8zNCizLBVllOEZgUA2kRJgNhUCqUlhpTtY1b/cGyjoRnS" +
844 "eL5oKkReL8/MGF5HvDqxRj0e8LksNF+MfEwIKZ1AVes8fYPetfD3ioMOoUy0OqWzX1oil+" +
845 "wZm8EFaP3mt6mRlCzkeEgkGiUZOuuVnDkKis9CsvAc1V/7a+1oVns5LHI4sO6TqdN7dzzr" +
846 "cQOpOEoWbIkqytozE3nCVYztnLvyy1sQ+C5hNcYpTCrQKmPRZVm0+M359ACEtldChZ0yqP" +
847 "kqVPv/eEG8vXEo9LuQvP+WNATjRZ6hRihAgQIDAQAB",
850 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCws2enlrV2g+kWA9kaoHbVdOecBdJRP9" +
851 "tPGaGoOU7LJH1hxB5qIK4Pgd7quDn9Gx9rNkDtTSEl8qPZoVHYbMAblvjUQpTUp84bj9NU" +
852 "JqKE7zKFr0o/8TI2rz3mOifrA8IlfvRhK62KGkvmmzZo1C/l0oiU3Baq2sIVTGzD4RmRyQ" +
855 "CN=Xcert EZ by DST",
856 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVQY3rS/963odKrti3yPwtR1Gt" +
857 "WEubZi/Inv5JdhkvsduOFaRzSengYi+9PqOMu4iwf3GqAXdwdaMBzUKTgg1ydA2FCTQ7/S" +
858 "GKIpdgVyqmu2aZireR4cZfVqi/zFFqqictpg7U5uGSV6Ch0w41CbQjxE66GwIB7bAn7+PR" +
859 "+/0ACK20B2philFadXtlLCAReYd4+KgcYatGoq5q+p1gCsz9gVSXzbG6H+gfqH+dOQwQLA" +
860 "+dBC6ZFoJV/Gv4c56ZUAYCi/gyzA51621zYW52CHdujnJ7IlDYt65aod5VnNzgsOb8bInO" +
861 "MQ2YU507eb+sa6fHTSXXVWq3SkolG/UnzucQIDAQAB",
863 "CN=Certiposte Classe A Personne",
864 "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQAox3xaJSN48rMAR0Biy2+MQlCfnl" +
865 "7UXA5lC1hWlSvjRtBhNuAtRpuCy5Hu0pV8mpKvBAp+pp/g17HDRfmYQRs5redW19m2f867" +
866 "OS4sO8+2cwODzhNdMmpjottb+Esz6FBsy6gX7J6TuWwGSyYLdx6e+eWMiTfS0bv9qYwrLJ" +
867 "wQMdhLjM23cX44LCnjF7JP6FK245I80v3hAtphEHTSGvPI0dFmB1/EhGNpva5s3GUjHLf7" +
868 "98YTLoN+P6nlCyBtAQo34lzait4icOkN4HQ9xOtxm2Eq4g0Ui0xGN0wm0mjWVsNXqqJgN6" +
869 "9fnaCzgILmQypMgAAJUNmoanNtA/5ec5LlAgMBAAE=",
871 "CN=Certiposte Serveur",
872 "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQA+p3gzOJHiylaV0ZFGsiPcpVZ/D8" +
873 "eXuOKekS4oFi6O80e2XIPE8Ob+ZxqTZH1ACdgdaADs1BHu2GOJAyPphF/HVQ5K4nK7KcFV" +
874 "ZHao45LN9/ZuQlYYUjOJ+YAUqBlRfsd3v3qoMcB9F25DTtVmyQU+S+Ll4lUbdKpRHarMmB" +
875 "F3pOvbKg4nx9XNSOzcfk5J50HNmQvRS14YGw06CpstmznHQAzQdgd8fI9+XHKOh9W+8qa5" +
876 "3r/dnxJ5R3zFyZdARgCS0xNak0+dfthfTMFdSEnZLZg8/MynhyHwPo5yfVk4NhYaDEi+of" +
877 "LVPqgWDCBZz84PM4M9rav1/93X/WkIiADvAgMBAAE=",
879 "OU=Certisign - Autoridade Certificadora - AC2",
880 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5MMyl65DWVpRnM4mDbUa+cJeTF04KJ3" +
881 "DOycXyxdIt0RGcdzJsdNOSb/rp1bhhmqpMEz41OvDuCTbZ0Zcxx16sQUm/SG1OIFPJe2qj" +
882 "ljFrsm6ozy9yTAatMs9aCPN9EJyqu7pz+fPwuCRvqGW2Iv4FWxBVRMIDHa3RIswIbfuMyw" +
885 "OU=Certisign - Autoridade Certificadora - AC4",
886 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsg9TMg5A/X+y+wenQx1hGWR/xk0qyFx" +
887 "MLzymZqwRFM+PRXr68jiV3Yt2bkpsxCkBFedXys91suUD9mH9Aoi3pspO9S9XB3unR+nH3" +
888 "P0G89BSvzWvIOUqdYGW0hNBqQeljrptp6rlGHNsYCDtiTN5B156GfxNyEdTc6t5gpbvdGw" +
891 "OU=Certisign Autoridade Certificadora AC1S",
892 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwwJXro8VB+JtvcWOOkRFX+QPHaJoanG" +
893 "Hwww8Ml2KIfiYBNX398W9PF5WqfvK7vO/idnNhlTZRgz6E6D+6VzY3lBNskmQflA3rVC9R" +
894 "WuUoXvCShufkbSF6XzcL51u9LQKogfk/yxTIvKTF49HLN9yr5Yeq8guYLnrPzB7Cf+j9AQ" +
897 "OU=Certisign Autoridade Certificadora AC3S",
898 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOZE7Wz658mCeY7yjvujTDNRqd0mYecf" +
899 "Hkli0nFzmQRY8t7+bVR6nhg4F8Pihx+oC7XfhDaxkQwZhvFZ4trklkROyEGmlZFleyPZLY" +
900 "Zku/ma1DGMc4yYuOLAQus0trk/adH4SyzeYAwr42pbxZtZ+LGSD/5agopFW2irayxddE4w" +
903 "O=Certplus, CN=Class 1 Primary CA",
904 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw2spyC7HrnxSBemTiVYKWnnJzN" +
905 "wl74eKLQXYgRcEGzpF+HkODUnUgUHIq0X7dcgV8uLQvNlhbISkExmn2fnySdxMD8Z9V7QT" +
906 "3B4JcSk2nYBY9BvYiRTr09KTSyrxd+dqZb0Z5ar9DEpj4cKZtA8EtlobNjw3PL/F5V7xX1" +
907 "cOH8f9LOfkb2qbYpY5EZtm8Cy2UtzhJ//bbf7rq2MUHWOIY+IWDPkgVA+b3RVqdoNPvSeL" +
908 "U6Y30ofyR1BSO2bp0XgaG7I7afBZPDhb0SpMM14Oylal7S1bgoNN1jhOila2ai8kaxIwpi" +
909 "rerwy7qkQSHBPFZQ/j/dgaMUvkPwx8RegWMwIDAQAB",
911 "O=Certplus, CN=Class 2 Primary CA",
912 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FCW0BL4NdIIeHq2UnD9b+7PuR" +
913 "HLXXfh7Ol+BI3WzG9zQ1dgrDMKROwDXxyAJJHlqJFWEoL34Cv0265hLokQjWtsurMCvdU2" +
914 "xUg3I+LwWjdSMxcS4tFgTb4vQRHj9hclDIuRwBuZe5lWDa/u0rxHV+N5SXs0iSckhN6x7O" +
915 "lYTv5O31q+Qa2sCMUYDu/SU+5s0J0SARON3IBi95WpRIhKcU5gVZ7bIxl5VgcMP2MLXLDi" +
916 "vn4V/JQzWEE4dMThj4vfJqwftYs7t0NZa7Akpm2Qi8Ry6l0zmLfL3l5775TxGz7KySHBxZ" +
917 "gCqqL2W3eb9X6WVTQcZ2nA8ULjR6z8KBxmVQIDAQAB",
919 "O=Certplus, CN=Class 3 Primary CA",
920 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5QwbtBM2X5eYOVvuybKUm9rbI" +
921 "WZpQvvABpvG01YtRgH+t17+MssUt38nLiNUum5sgt89Y9bmUgJWN7NSJWGJYkFNCcwC1e2" +
922 "DHdjKctsqj65mVESDZhwdkdM+UmWIgj5a+qqADajFaccHp+Mylp5eyHaiR9jfnmSUAkEKK" +
923 "3O420ESUqZsT9FCXhYIO+N/oDIBO0pLKBYjYQCJZc/oBPXe4sj45+4x7hCQDgbkkq9SpRV" +
924 "x1YVDYF3zJ+iN4krW4UNi3f4xIv7EMuUx+kaVhKXZhTEu9d9bQIbv3FiJhjpSYr6o97hhK" +
925 "2AykriIoxqCGGDsiLHCYg4Vl3RMavwCZ8TWQIDAQAB",
927 "CN=Autoridad Certificadora de la Asociacion Nacional del Notariado Mexicano",
928 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7tlrVYRxJvaOrUG71tLeY+ryP2" +
929 "XyOxPBrlEm9L94j8ZMSay/Qd71KMco55/XgOXU7iMrk5U9yY9q9coA6RDHiIIabqNf8DRS" +
930 "ISVoKPiV8ICVoiyxP2r2KNbihP0WZ5wluXXb5cZZA7SrQgeI1VxIRaIJA8muZ5KoolPHyq" +
931 "t+mhKVWgVXjRBklicRsOYyMFvNPQygGxMtuxqr3TnOkmuiBNQTX213Z1Q5qHtpisZfeMoH" +
932 "GGlu+cDT0IqOrx4waO742KhmDIR9I2qJPGJNFHSs25uc/LCD/gcw8factEjI5jpCJQko91" +
933 "bCsdejmHcCh+qKwV3axIonB4VeSExVKEDtCQIDAQAB",
935 "O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
936 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
937 "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
938 "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
941 "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
942 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
943 "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
944 "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
947 "C=FR, O=Certplus, CN=Class 3P Primary CA",
948 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzf/62CbQXhp9UlYsN4fcWmmK+" +
949 "OuUMapvJPpIL7kxBOCVu/wQzIJypt1A498T+HgT3aeC61kehQ6mp2/LxYLZRyp7py84xpl" +
950 "y0+F6pJWdWbWVUDv+8zWOD+rHO9CjRmJ9reVhsKnHen3KfEq2WV5/Cv1jsoad36e6Kz5Zr" +
951 "9F++gTnV+2c+V9e477EnRdHwZehRumXhhEALq8027RUg4GrevutbTBu7zrOA9IIpHHb9K4" +
952 "cju6f8CNbLe8R3MhKoX/rNYoohnVl2o6uaxtRezmTcPbqF3FXYKYrEpaquYrCAwQdLxi9j" +
953 "pJBGbYURwmpth1n5y/rmBRPVy8ok97iWfNUwIDAQAB",
955 "C=FR, O=Certplus, CN=Class 3TS Primary CA",
956 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvWWaI0MAPPklAUOYW0Y0N2c39F" +
957 "tXjqPezYwvQbMVPeWYi/LMXKfHrzXHs6dPxxApV+kDiYNyBnZSwXACN0Dt8M6LsbGJrAKo" +
958 "W93c1UNFBtwotulRG2ru83tIxZ0Rro2mcpPAJUKRqD5G4mhMgUCwQtN6vntH0kdQDKQSps" +
959 "rkEtDAfDo8AanKApbeglrF+xm6PJzYD3QfmBiulFAyB1IQEUpL7FhVLNSeS5R7BdJy3wbw" +
960 "jcsInuTutEStgvEbYWrxs/gWMTZCJLqQv7V+YW7CWQxUebRMiCgezBvfhIsjyL6vB/KRst" +
961 "qNyoxffCg8fIlsBlm9Ps7FgtNqyaxoVe7FrwIDAQAB",
963 "C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority",
964 "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AKT7gWJ7zhAn3ej3vmxuxnCZ27jVBQNpKI" +
965 "Kccn+WP47srCmSP4oU+EJ2vr1dA7mQ1NC8BrJRM1/Ewr+2i4+ZtmIiYN3b3yCCtMqiLy1Q" +
966 "7ZQy3uBVjdRo4uBM0s0FFi6VZlxhUjgeUaiCocTvJekK5osrjjFm2fjZ/b07adnrAgMBAA" +
969 "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 1",
970 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ3ZsMoBdERA+vIUBzZ1bwPmloEbrZN/" +
971 "KBrsMkrGmhzfymGFVW/4ufMsHb53gsOdtggUGl79PNgI0YPOJSDAuf92Se5aDwuGFi9L/g" +
972 "o9pYK/0VBGu9Op58nfI92OSVw+xOwvFlqwxL7EeCW+LhUHXY9mG0GFztM6BLHoP7T4S8eQ" +
975 "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2",
976 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqwujNeCLKRSxFIWvPBDkOW81XU" +
977 "qu3ephjZVJ9G9koxpgZqSpQCKE2dSl5XiTDmgBrblNXDrO07ioQkDfz6O6gllqkhusHJra" +
978 "CCslJ/lpI0fx4Ossepv1EwLQfjR8wp48AFmr9doM9TI8K6xQ2tbD3oOUyqgMmTIOCEhWW2" +
979 "r72uFYWAFJX3JBPBUGAY5draq4k7TNnuun6GotUjTbOu9cdVHa2/Mx+e5xmDLEVBVEDPmb" +
980 "Ve2t3xgIoKOGiknuUwWPGUzV3lh5m9JqHEKrxdWnz2gPluThYZh2YciRfNY+AOKRUIfhnQ" +
981 "rmrZfSHcY6fcu82gM01Y5bAfVqB7cWtm5KfwIDAQAB",
983 "C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA",
984 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC0SBGAWKDVpZkP9jcsRLZu0XzzKmueEb" +
985 "aIIwRccSWeahJ3EW6/aDllqPay9qIYsokVoGe3eowiSGv2hDQftsr3G3LL8ltI04ceInYT" +
986 "BLSsbJZ/5w4IyTJRMC3VgOghZ7rzXggkLAdZnZAa7kbJtaQelrRBkdR/0o04JrBvQ24JfQ" +
989 "OU=National Retail Federation, CN=DST (NRF) RootCA",
990 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2aybd/pQ08zcuUCsuXJqAIcj/A" +
991 "+WIdAmr+TitV/606Z9ITAuzBeCj5h0/Gekpt+Il6JCKfWn2xGT+14jMMKqvCLnQRvl7SXe" +
992 "yD/b3ldFeEBGg7LVGj3fD0Vt1WMCddgvxm6rlZF0Nw3LTQlc0dRbOtrdDshrmdjVOczfhV" +
993 "XEklMCo+H3gMlwo9rcM8R/okcIHDWWH6EDHDCD9MTM/5jDsEZEosC/rdvSgfZMmCynXiTz" +
994 "hspj1bp98JrAStAbWO7sqWfPaQJsIsBgLCzRyCDqyC373Zy7y1FM3OdXBDtUmxGlMnTsdA" +
995 "HzkBVbL3wsk2W5Zme0gYg15Z6RGH+BqEHIywIDAQAB",
997 "OU=United Parcel Service, CN=DST (UPS) RootCA",
998 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7xfsrynm2SsnwNt7JJ9m9ASjwq" +
999 "0KyrDNhCuqN/OAoWDvQo/lXXdfV0JU3SvbYbJxXpN7b1/rJCvnpPLr8XOzC431Wdcy36yQ" +
1000 "jk4xuiVNtgym8eWvDOHlb1IDFcHfvn5KpqYYRnA/76dNqNz1dNlhekA8oZQo6sKUiMs3FQ" +
1001 "UZPJViuhwt+yiM0ciekjxbEVQ7eNlHO5stSuY+e2vf9PYFzyj2upg2AJ48N4UKnN63pIXF" +
1002 "Y/23YhRtFx7MioCFQjIRsCHinXfJgBZBnuvlFIl/t8O8T8Gfh5uW7GP2+ZBWDpWjIwqMZN" +
1003 "qbuxx3sExd5sjo9X15LVckP8zjPSyYzxKfFwIDAQAB",
1005 "CN=Autoridad Certificadora del Colegio Nacional de Correduria Publica Mexicana",
1006 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmO0dhYH7/jd0viOAJ18bQX6856" +
1007 "WK2HNdlkjqq1iqfaUdz/4gCtnydQnts9X9+JMqGaleqLEU8tZChkFBXk/FVqeaokJvLihI" +
1008 "6i6r2cHZmvClnotdEWeaNzdTYGbxIv93d0fp3dwYRu4u3+LBluDqWN6H65OIaZmwPm52KU" +
1009 "Bhwyhmc3+sMXb0OM3WMo9zMhAVNNJ8RND8eQwAnX0P4+P3RPWedEknrRvXMshTrm8qsNe1" +
1010 "LRgsbjs6TUzb9Wi1L7AMkPk93HU2msLgv7uWiMJr7hjXTlA/V4tnaKS+AzNdWRI0if52yN" +
1011 "kVdgFUZP2s41DvEMjQ7l/sHd9PBZg8tBReAQIDAQAB",
1014 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sYmtuelPcHEaNVQb1PFb0kTCb" +
1015 "ivLEiNFGqjF19a+dMudS/YKGLRky/8TdSrh+UIx5nnkj91vesltBXBmxk90kSN13QgbTcC" +
1016 "j2mTW4rEGZ30sg78Fmy5sQWSg9GFLGCUPkVVoNmrCCHmYOg7dPKZUFFo0AMtsYC+o9hSsE" +
1017 "TNQ0pwjliFleFOLNYtQW/WhOfImETKR9ssJKVpJs9ruCdiw/TJepIj7RNngq5FLkXlfnI/" +
1018 "hZ2UYhDmPJGhrXcA4BXs84SAcnqObmCXxyRZEDSDW+GlpGm2VzUceFnG0y86c2fulMoEEw" +
1019 "ViBnAjs/R87kXZZAtbSaqkQ84mxEQSbLjdeQIDAQAB",
1021 "OU=DSTCA X2, CN=DST RootCA X2",
1022 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3HXwjMB1lprAYh8m98ThmurgVn" +
1023 "Nbmc0BRKgIttWn2hoEGDmSSnijgcL1d3pQtHD/mqvGx8pug09CmPsmC9rcbdapmVVSZ+ko" +
1024 "A5Lc5bAFmg8V+WtZclby+jn8qmjuDx8Qgy/8nfoXlt2C4+ZFfcBLgEQf7SzghP2RXJJUaS" +
1025 "XlYmnc5e4AUr0zC611AoWnZFAtxRkZMMAm28nT/S6ZrVm1C03UQa6FSENZ3Leo4qLew4/X" +
1026 "uKFipmhQUuTPMaeUhdqfRjIXVuXy62Y9Ev9D25jvd8/LgY00scZQSibR5D5BUK9sriI0Lt" +
1027 "VrboO6ebh2ZUjaCSlkYyK5+0d2hYyGRMsJ2wIDAQAB",
1029 "C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA",
1030 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC2HfdLjQ8T4xL1Cf4GMg6vTEH1fdRHPS" +
1031 "oK34MF3t595gMW9lE6y0caSq1+xP0dtL50injdC4OOtIQTxPv4bSmuoeEPD0PjtV5gafqD" +
1032 "lPx55tx27dFEK479Erv+F3cXDIntp+9RfcTtOMM7o3r74k2gYLXy/RNl08bsP741nD0i7w" +
1035 "C=US, O=Digital Signature Trust Co., OU=DSTCA E1",
1036 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodG" +
1037 "BmE5gGHKlREmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth" +
1038 "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQ" +
1041 "C=US, O=Digital Signature Trust Co., OU=DSTCA E2",
1042 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+S" +
1043 "SmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e" +
1044 "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQ" +
1047 "CN=Entrust.net Certification Authority (2048)",
1048 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvw" +
1049 "tKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtL" +
1050 "A/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24Sc" +
1051 "F2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUy" +
1052 "VYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJ" +
1053 "G/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQAB",
1055 "CN=Entrust.net Client Certification Authority",
1056 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/" +
1057 "Bo6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDe" +
1058 "g7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173iw" +
1061 "CN=Entrust.net Secure Server Certification Authority",
1062 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO" +
1063 "2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc" +
1064 "1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQw" +
1067 "C=US, O=Equifax, OU=Equifax Secure Certificate Authority",
1068 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBXbFYZwhi7qCaLR8IbZEUaJgKHv7aBG" +
1069 "8ThGIhw9F8zp8F4LgB8E407OKKlQRkrPFrU18Fs8tngL9CAo7+3QEJ7OEAFE/8+/AM3UO6" +
1070 "WyvhH4BwmRVXkxbxD5dqt8JoIxzMTVkwrFEeO68r1u5jRXvF2V9Q0uNQDzqI578U/eDHuQ" +
1073 "C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1",
1074 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOLxm8F7d33pOpX1oNF080GgyY9CLZWd" +
1075 "TEaEbwtDXFhQMgxq9FpSFRRUHrFlg2Mm/iUGJk+f1RnKok2fSdgyqHCiHTEjg0bI0Ablqg" +
1076 "2ULuGiGV+VJMVVrFDzhPRvpt+C411h186+LwsHWAyKkTrL6I7zpuq18qOGICsBJ7/o+mAw" +
1079 "CN=Baltimore EZ by DST",
1080 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMyzPUN5uEf5FbduJrFMkph57c" +
1081 "Vw8zrp1d0D9Co/YIyW5UcWAvc2svGeJoj1nkJlng+uf+PMsW4h9fGIInTWH7J3BDkyuke1" +
1082 "NcATXQFyowVDzE7aJpqHqGFj9GanwxVG6tHR6jDDu3Fqm8FDhsE5H8ZWYAIb/Ig6oJm7jN" +
1083 "d4YdBeV4+RO4CLbv/JZYEKObuQEyA1SD+l4b8twXGDhSDtIIfLtv4ZjATd7Sld3woSzolW" +
1084 "8h9aGTFYtv1jNurJI96nkZcnZXKZbMd6RMRfvpsfHsqeWBymqiNq4wYbkiTYVyIJUBWQRv" +
1085 "CDXraATBKBPWZvBFU6iGvQ71aHUKC51lUbnQIDAQAB",
1087 "C=US, O=Equifax Secure, OU=Equifax Secure eBusiness CA-2",
1088 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkOTmTHlIGGyg2+LKjKcXtjrIRvf7r57" +
1089 "R0wo//BefZnQa/Esg/DvLW0SSyEd7RcwmK1LEsmAkNHlBGsoOmRY1iaLuFGyBwMqpAzaaW" +
1090 "X8RxNz8E87dBJDkHGh4uYVigEgvlpd/Fq+o3ccwcyDc6uZdSp6zFaiSUTpx7z8Bq1t8hvQ" +
1093 "C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1",
1094 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC65xeQAmWxNFU8ScJR1d+n0TeP0eeBc0" +
1095 "FSYJudoRcmeK3HsegmlDK13jONOi/b8pp6WnOYo1zp+4pzG1znw7+AbM2p9NYrwPf5mapj" +
1096 "orFHAg/U5FE6EjxsilpUhHDbwcWQz3JFy6hZwM0znT+jluuFMyEcPh4+YG52nGeFxcjDYQ" +
1099 "O=EUnet International, CN=EUnet International Root CA",
1100 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeQTvZQUmLKJxZFPdQaCh7TQhcZ/+FHg" +
1101 "umzzoyArB8fEqftokCIQxKmYvLZFF+eFq2XqlTt+/vx9+lIVmXTuIH5S18GdUqysgz05YQ" +
1102 "Lt2gAJ/9yuhhqVPKth0YPpwR4GPnKmdbyESV8BNVSLu+VbhnN83LABMN/E9pFGpRlOy8Jw" +
1105 "CN=FESTE, Public Notary Certs, EmailAddress=feste@feste.org",
1106 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhg/ObLsnn4cf0VAXNdkD+tLMTvucVXo" +
1107 "Ym6EB3GlU/0QMmjPqHX6TF+f61MonGf0GR2BVATnBS8PHa+GI1mV4clFNhzD5iwINdWNH4" +
1108 "SBFxbPewd+EYl7QHKDCRMcdPVPOEnsxZiUVtfrTJ245ClWbU3x4YTfylD9YahDnEyvK98w" +
1111 "CN=FESTE, Verified Certs",
1112 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqY58fOBqEBISzS5MZhKJ7YsOnqyzsYE" +
1113 "5VEeIEMicgNfkaeB8nZ6fggrAF6Capm4pEVr9LhFOjIqYOFlO5f68QyDMYVNnGTHzRW1ZS" +
1114 "U4amWz8T8sMB0jGhM1y8XeTcYjzKI5dPcPuBjrDZnq+T6raxJI0ELVFDPDjsJ0Nxh+g8xw" +
1117 "CN=First Data Digital Certificates Inc. Certification Authority",
1118 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDfHBQeCbm/pEByIJl5toQi9NeFksUEJO" +
1119 "gHLgLkF5UFN5V2Pfyx5Q+HDmK5LDCXJuELFWcAphXe6I3LlewCWFLAR2UzTFafCh8EwDdQ" +
1120 "gVe63/rya2fry9CAD9lXlRBlewZFWOuutF7jkxUrmby2KS/7Qp9HKy5M6zQoMpkO7/9voQ" +
1123 "C=ES, O=FNMT, OU=FNMT Clase 2 CA",
1124 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCYP60ZNpM9Pv52QhT9NW/x+q0ieljjRt" +
1125 "Bdxlr5Yi2PMV7+tDD+UHSs1p0d4GLGSd0UEn1xC6wGwT/XBofgkInW5eMDsvInsZ8zyKpr" +
1126 "NkqjxD95QZ2JRi8rPmPUOFaRqh2xDUJ1TfOHTuMPTcy0bL9iE4fq0JuOtuL/GfSUCdWWYQ" +
1129 "CN=Belgacom E-Trust Primary CA",
1130 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq2bmz1U9qTcVB0HsEYWqLcYEH2mTjWG" +
1131 "4nVcKtzhew/PqSjQjwHHL/ssMx/uBqh5dMzENXpyh5OrWDXaQdavFqxT4UIh1ZBm/wpjF3" +
1132 "3LBJOObLDA/+qnI0iNooOiFa7nQrG6TbWxMWtXNfw66M0sA+PbDL8OyLhgvCwUQYWmOo1Q" +
1135 "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA",
1136 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2g7mmY3Oo+NPin778YuDJWvqSB" +
1137 "/xKrC5lREEvfBj0eJnZs8c3c8bSCvujYmOmq8pgGWr6cctEsurHExwB6E9CjDNFY1P+N3U" +
1138 "jFAVHO9Q7sQu9/zpUvKRfeBt1TUwjl5Dc/JB6dVq47KJOlY5OG8GPIhpWypNxadUuGyJzJ" +
1139 "v5PMrl/Yn1EjySeJbW3HRuk0Rh0Y3HRrJ1DoboGYrVbWzVeBaVounICjjr8iQTT3NUkxOF" +
1140 "Ohu8HjS1iwWMuXeLsdsfIJGrCVNukM57N3S5cEeRIlFjFnmusa5BJgjIGSvRRqpI1mQq14" +
1141 "M0/ywqwWwZQ0oHhefTfPYhaO/q8lKff5OQzwIDAQAB",
1143 "CN=GTE CyberTrust Global Root",
1144 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9p" +
1145 "TAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6" +
1146 "XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQ" +
1149 "CN=GTE CyberTrust Root",
1150 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6jr11kBL65Xl0stn3JtQOQR3pNgdWct" +
1151 "W4adpU1LHWeG2q4zs9o4Q3JcevrwTcsyKx6W2+gm3rjS+9tK5wHqLWbiAxUeZWXHNSsiNQ" +
1152 "Trz7mmdAxIYRRsdDIrrqAE9scs1hnN7L+u4w0ub6W53Fmdwg+Dm/ZIwHVju93Gxe9r/h2Q" +
1155 "C=US, O=GTE Corporation, CN=GTE CyberTrust Root",
1156 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7" +
1157 "pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3" +
1158 "FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44Aw" +
1161 "OU=ValiCert Class 3 Policy Validation Authority",
1162 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFl" +
1163 "LWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2" +
1164 "bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPw" +
1167 "OU=ValiCert Class 1 Policy Validation Authority",
1168 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSL" +
1169 "wxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+Fiw" +
1170 "nRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQ" +
1173 "OU=ValiCert Class 2 Policy Validation Authority",
1174 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZU" +
1175 "cOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XB" +
1176 "hVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9w" +
1179 "C=hk, O=C&W HKT SecureNet CA Class A",
1180 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBuiCqVMc2NGUUh0Y6i0jBbb9M" +
1181 "hn3qFIAv/Lo8+n39mxMeDjLihxBKZkWsZc/tCnuOo+Ctr7EX9/JCheyIqsbniqyKIYOZ5M" +
1182 "UNHwmLXvpLIbYGu/+XO0C3X5Irvp5YGgldJ2THzTp/5dlRXtB9TH3mAwAO7yLpTxhjLlWV" +
1183 "Ho34CiKgDvPIhdEeMAX1TkDEcQbLD1+DN2HDRmW9S7NGM502aUOuzNIinz9hK71CEpN6VE" +
1184 "Td+JDAQMfUF7h/MWwUMpZLTWRWerhkxljwG36mOMTnhUREcaU4aMaxgnIQvFVmYOJfbgea" +
1185 "xoAHTpmmQ8SU6e4B3IiBtQBvddCfiNixP9XQIDAQAB",
1187 "CN=IPS SERVIDORES",
1188 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGb" +
1189 "WOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU" +
1190 "3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzhPvYR3oydAQ" +
1193 "CN=Microsoft Root Authority",
1194 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQK9wXDmO/JOGyifl3heMOqiqY" +
1195 "0lX/j+lUyjt/6doiA+fFGim6KPYDJr0UJkee6sdslU2vLrnIYcj5+EZrPFa3piI9YdPN4P" +
1196 "AZLolsS/LWaammgmmdA6LL8MtVgmwUbnCj44liypKDmo7EmDQuOED7uabFVhrIJ8oWAtd0" +
1197 "zpmbRkO5pQHDEIJBSfqeeRKxjmPZhjFGBYBWWfHTdSh/en75QCxhvTv1VFs4mAvzrsVJRO" +
1198 "rv2nem10Tq8YzJYJKCEAV5BgaTe7SxIHPFb/W/ukZgoIptKBVlfvtjteFoF3BNr2vq6Alf" +
1199 "6wzX/WpxpyXDzKvPAIoyIwswaFybMgdxOF3wIDAQAB",
1201 "CN=Microsoft Root Certificate Authority",
1202 "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8136gGfUWqepDCyQINA1CDx1hM" +
1203 "23B4mcidrezsNg+pFoWp6UcSkYdnzC4MgldpQOWPoENDbm36/3gLrpWAsrk+WdBeN3IpH3" +
1204 "NGQ8IpEdXuEJkLwU/vx1WBnhebcHkqOuiFkI2J8HygNY/GgpbTLX0qjLS/zhC0gyT+bruK" +
1205 "1P5FxvE5SZ25XVdduoGreUkbR3W/VIDI9qeX0UcAR9ba+Q9dpw2Ee3v5svbOcFt+ERYKx5" +
1206 "kRR8xdam5OF+1cN+5ZLSPAC1NoLeeeFt87Vu+J8zyctSfXOYNtuLoWuilZebo97CTSb/Bp" +
1207 "ZnJQbI56zk7hIzlTGZyDUITjTKeVPVtb5jMllANsClTgRNPdtbBzPkWL/vP1Nk2EJZNVf9" +
1208 "D0V8JARNntY4dBGXIpDOaER0km/VS2+whuPHNkKg0PzBwFr5o2G5MEdxlgoWsJHAQpXvEH" +
1209 "8oauMqH7HkzQM/d3EExyD8SQ8dRYik18t+iK2OLexF28RRBMkq/OyGnpoRl1vezlOI5uK3" +
1210 "/ayVwihA2+8EkN+BMznZskWlI4cGpVWJMbsGLWAOQRh9Hy61l8sR6xXVJKWU7xUUif1Lc/" +
1211 "oyW/zRMwD5WWJwBzLqLqtALXvK3SFnGzCZjxaqI6hB0bBuEZs2xN5AdJzhWGXBYB56WzjI" +
1212 "j7sEJnzUFkDltmtsqob9AL/OwTUCAwEAAQ==",
1214 "CN=NetLock Expressz (Class C) Tanusitvanykiado",
1215 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr7LBsYYojJa9gIOPZn/yTC9tdjbChs0" +
1216 "A6gs79deB4MgOGWoaVke1T+p1A/Obo3dlbegO9XfM7DMNReZutVaDp0AMQrwq6FELZUiYR" +
1217 "IsfSIMyCpJqp/riBdp1qt9I2dT6xhgn2bm1+Trd67K5xhPYEMwglMut0rBZExuRAkx1/rQ" +
1220 "CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado",
1221 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeL" +
1222 "Vu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX" +
1223 "9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8Wg" +
1224 "D/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF" +
1225 "/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCo" +
1226 "R64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQAB",
1228 "OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado",
1229 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBN" +
1230 "wcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX" +
1231 "iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQ" +
1234 "CN=Post.Trust Root CA",
1235 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1n8T5A0k2Nj76bbDsVKjTty3O+" +
1236 "L3Dl+B5gHwpuY2cNgTc6H/UgiQ8hW88jIcqNfhBhB7QaiUxz89RBXcgFHnMP5TSPWQX21t" +
1237 "JeBgu6D71sYp+E1wUBo3oA7NeCq2aPOZ1AyOXhJi/8JfWporiEequ6HZdfAsXP5twrFbMc" +
1238 "yDhxqnvpAO6BBUU1ILnEnzgAL+byemo1cwuNu40AAEA+Tl1EMG66toTWgm0pk0ueASln9L" +
1239 "u2tuIXHmCEVKHWYNN8kD4dHK3LEvcPa3gWKWG2Sn/rvhhutBn6ic2Mqg4dYv+A/hukA492" +
1240 "3RpcpMGciW3MxJHAq206iROvna7B3Nc0okPwIDAQAB",
1242 "CN=PTT Post Root CA, 0.9.2342.19200300.100.1.3=ca@ptt-post.nl",
1243 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsH7iOgHxSK1T1HHO276A4FCtma" +
1244 "KEeto6JyQ6EYE2Eg3mo5mOpMwmtQ5hxu4oq22G3y6XYfpAacmNjMQxe/pSXlZMIJ5gGl9s" +
1245 "SnjJiTyflYasd2cOpg5C6CxiSTJLBD4yQ5AOCiLKyHQOhe+DgcVb8ttshQhvTialBqt245" +
1246 "iiTl7EgODo+8zpMGzycmGuJ35T1BWUD9KPeYLZ9o+rxhPmHJh0SwBhDnlpVPKQsqMJAWX3" +
1247 "BEdsTvopK/AOBheT3ILAEd6PsDBGWUhKZs42r8fPMdGSdBQj1aq64InbEtHs1GkjuAsWST" +
1248 "POGvninF98aB13uwGqZ+Ixxv/WOmn9DBt8IwIDAQAB",
1250 "CN=Saunalahden Serveri CA, EmailAddress=gold-certs@saunalahti.fi",
1251 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5wQp3NbgUtPWTwCvHIGIvzxUcv" +
1252 "OeeWP9y2DaDHxyL8obqeIQaWd6OZ/CoCXMg4ONgxEcuP3n26mIowySIVfBquLqM35KZgO8" +
1253 "c43SHCn9x39D7Y/rV3uhQb9NczFKNyi0GFdYPGhwUJO6EB14zZPDwoLvuN8PDFjVMFdDOh" +
1254 "QlKjhZBrREzdvJXkbyS7gcQ0GB0j5Dsq4hnhtKgHymyrP0JqkuLPi39zwYD5sybxEJc8TN" +
1255 "L+jT7Ek284GN2ML/0Bpt3dgUvzLQ6cMNPgiv7dpLnWrPE4uQgmn612cjYUtb/aWAZB1696" +
1256 "XT2ncceLtR++dGgJBxcbYW+EO0Gb0Yq952ewIDAQAB",
1258 "CN=Saunalahden Serveri CA, EmailAddress=silver-certs@saunalahti.fi",
1259 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0neMvIdsNk5TqmhgRbgjd2fj7k" +
1260 "mC5mx/XpJdtRxhUteoYEsW+ut5fp1MkulXe16GMKkoPH030SHidhoZw++q2u74AZ4aOSov" +
1261 "k3UDZj9uKU2NhGOMpx8VlLQ0SbTk00GruvvEXLWecvUoyjKCY0zHRPi0HcSKCldVkK8wiV" +
1262 "QOp2gm00AHIrPOPKP7mNckPN58gkm0NIx9JNtkbmSy6f+GyKx+q1Pk0kH0EYTuR0wIHUTm" +
1263 "Vk0AfNqJQjnveAjRhea+XJ4zuTX/HM70g7XyZMUxSKm0rMXYPIwabab/Qq3z+EvOrNrFir" +
1264 "APAyPB9fPHWX8w8d9mHVoxBaJGHTnkVbOtDwIDAQAB",
1266 "C=hk, O=C&W HKT SecureNet CA Class B",
1267 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn+AlkQ8EV8LHXLFlAmYPqP3YMQ" +
1268 "5vgmz5wx6w46C9OERSx4x2EnhMfsIrjIrk+dwK4JVF3+seftJE+AMVAOzEsTx6tk22lgp3" +
1269 "vAdg7/C3N/6J/bLYB6tS/oI/vDVnM9n7LNy1WGGiDLF9lNGohGkkPZfNmwhMUImBmh/Swi" +
1270 "BvzD8OZcThSEncO/nlKjEHbqZrR6gZWq7ToXS1vMLbOT36q7DwySIJ1DxGaGwuLh/4qIwR" +
1271 "oXY1UpLXq4gh3L3pnNn4Pt4wMUwCIi9XZrtWcjk3UJmvV9D0S9Qp7alvxtOyhpGLHRBtaB" +
1272 "Zk8Q5tv15n/bKOcGXnb3K8RHWrAXb/N2RFIQIDAQAB",
1274 "C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority",
1275 "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6z" +
1276 "V4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXAT" +
1277 "cXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAA" +
1280 "C=au, O=SecureNet CA Class A",
1281 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqaN8+JCzjoRM4Aq+qxIqjQw+L7" +
1282 "XdmxCIuWq3h3Ugt0vvIiMG6/BWMvfLLXDFA2+3wdDDZhMCvVVJh4fpLZ6l5XY2q+JkJViI" +
1283 "wxsbAvBdsY+fE03CUim0EDVPNoivCy2BCCRhw2iNWm0x6FQZUxf9pxP2QJmmqCnAn0J7Jy" +
1284 "nB7tvvjQNkJYGx/pUaHtoQQWIbVn8YGEiY0k1LwRhot2lna2RMbo8CvxRpe/ZEIxDpLrxe" +
1285 "Ys1bnMyjjoxRgbSiorG8qMnoKpiqu0sVoeHpkHqef+hlBegRcXpv43XeVT/L2OrIAM0llH" +
1286 "JkHu99ED5NL5F5vQLq15DBSWhuWRQl4t3dCQIDAQAB",
1288 "C=au, O=SecureNet CA Class B",
1289 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmPZxhVadudGZcc0kfl73Va7+J" +
1290 "Y1LinKp30KHvcxUuhayNPPOQFOW/AfsbhK0rNHQ2Y/AUBOMEnhD/3rEmN4zPYWYhj1b2n9" +
1291 "fm4zdiGjwIgP6uYl/KmXzBhyxzG2C5vNwsV4YWNFrDSmJ3hoxL1SaM6ETdIkpShsgObK5s" +
1292 "/mmp5QeM7zNtKjQ1ocBq/LIO7QLMREGJBssZFkZbm3hYNLqJGZxeCc97hQ19OwT5rtY/tN" +
1293 "9NQoJDqAW3uTjMUFhK87hv6BMce2nV8a6pB7sEZesghSAFcNVVKDeJVK/WiPntlQtktT+v" +
1294 "KFApVOOPWDp5bUMT8/p8o3U9zFL20adKbMvwIDAQAB",
1296 "C=au, O=SecureNet CA Root",
1297 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyi02Dz1v3oGkb2lQkyzfJ6IZp" +
1298 "nF2xfURVTDe8DwJFZmmL9E4HkTdmiu3Zp0z6Lpl+bBwKnD9yzVNjtzna+C2twOX1Ov625Q" +
1299 "16jwqo6rY9Kbdf5VCnzRs8BZk1Eqh2mKGe3k19eOFKu1GVizzmzgTYLTA4TBqwAYekmoFX" +
1300 "0IyQFgJ5To+wlgntE/Ts0To3j9ZfcRX/abADCMIu0oiWUb0x9he8Mjo+PGgPmD8/e63oZ4" +
1301 "X/aVw4xqSCJlhdMiefb9RBboD2EENip1xtviZRQnYtyCXJYSMw5MGNX2PJ2xzWEcsYX5A9" +
1302 "G69kzW7p990ZIh8PYKFqQ0h/dWj5O+l69SpwIDAQAB",
1304 "C=au, O=SecureNet CA SGC Root",
1305 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1uxDYpTIbpSiDiQQmVE/Vbrc8" +
1306 "WF8wYx5Qj8jLHVescLIwq8WgkiAfinwN5XdDGLrTbMXnP39kTwMcr1LKIF8wocMHqGM+JG" +
1307 "U/Zk1kersVOUY3fEYtMvC+pfsHUCXvgrzybz3tKt62V/vC5BhPyZmumBG6ecZsf49bKEGy" +
1308 "B1ciHHhP8CRswPpmmFfVkh1Q6nXVYVT8wfQSx/Zhuv691Bo+yp5lZK/h6nxFwiny/gC3QB" +
1309 "cMhzgwoHpGie5FEOjXQxL6LG2ggQK+8lPmyGtUbnl4PAq96wrgYa58j7736tjrCaRfGb9b" +
1310 "HoMbtkAL9/kWbNqK+V6hM6Akxb68CT5EH8rQIDAQAB",
1312 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1313 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1314 "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1315 "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1316 "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1317 "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1318 "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1320 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1321 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1322 "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1323 "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1324 "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1325 "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1326 "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1328 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1329 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1330 "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1331 "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1332 "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1333 "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1334 "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1336 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1337 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1338 "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1339 "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1340 "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1341 "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1342 "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1344 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1345 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1346 "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1347 "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1348 "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1349 "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1350 "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1352 "C=hk, O=C&W HKT SecureNet CA Root",
1353 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBiikFaM1l2/RliRJ+qddeCk66" +
1354 "JQcIdFSUmSa7c5AEt7qNpA4eYNouA3AUhNznLhXJPTw/mSDSTvSM5HKsutkjqq1pWy8hme" +
1355 "PpV8j2ACdJMWKGn+O+5deJMcejwj6WE5bMUwLR+EkgVx53TBQkfpMLGjFww2Y89Q0DKoh6" +
1356 "VAYhQROPvOL40zsIvpjnD7sJ7HXQPu9uWNcjzIvFSSz8qQ38jbrwXx61DK0QWsBbQBFZb1" +
1357 "6zihafeDQ+g8pl2lLLokFi/7DjJwphLWmTb3axuj5/zHG8jYL3XRNbPpwtaPBB3BtX4EOz" +
1358 "iJ5KMj8P3KvczrnRcGFXLt0Ob71m+z8Z0+uwIDAQAB",
1360 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1361 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1362 "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1363 "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1364 "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1365 "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1366 "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1368 "CN=SERVICIOS DE CERTIFICACION - A.N.C.",
1369 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsiov7CtZakOTiUYqiuXs+gX64s" +
1370 "jeQWuvA9sAWu9IN89XifvdyZIQ3ncDlRyQPse2ZyU7VZjv2Tz+JuSKO0SpdDeDCncndLip" +
1371 "ca3dlxPSyqIuuLqdyb5Z6Nly8oqFZhxHXrSHgtYP32cmpr02sfNdkFBRdjIsOy+qX2Fe41" +
1372 "TVEl3/DY0Rx4J6Nt/hTBbEdN0tau/QsfAzp/6/N2dDEi55SpSvhPsHEQhOMJN16QFUzsXe" +
1373 "FIbwrq6bciUPRHfi82yveZwuSceemHYyFpq8AN7gtCAFkRfdgBUU7jZBxCGP7tkAShnGcW" +
1374 "GlEV0AO+SndGw6Sm6D4HoxXCFl+AiHQodn5QIDAQAB",
1376 "CN=SIA Secure Client CA",
1377 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS/LBAYGpmY1Jm5mkJcY2BmB4dHfPgSQ" +
1378 "3IK2/Qd1FFxZ1uo1xw3hV4Fh5f4MJi9H0yQ3cI19/S9X83glLGfpOd8U1naMIvwiWIHXHm" +
1379 "2ArQeORRQjlVBvOAYv6WpW3FRsdB5QASm2bB4o2VPtXHDFj3yGCknHhxlYzeegm/HNX8ow" +
1382 "C=IT, O=SIA S.p.A., L=Milano, CN=SIA Secure Server CA",
1383 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA28ELzCfTEiIuuWQWdKxZJ+IqkA" +
1384 "CSntWYXCtRbhsTb1RvShCihethC+ztnH7Of2WTbsxsQZzILarGs5v7THCcEXXzcom6iQCt" +
1385 "xy5J53PagLIs/vKXmfQCGzQvOaqL5u8F/Ln1ulR/ob+OHkg2Mwl0Yac9x5skx8OJzcpOKD" +
1386 "EjBhxiFY7fTxtrLUri9LDczvOQ/XmBE8E+Lma8+SJNCy9iM42oK+rpb3OnN5QEL+leTQ3p" +
1387 "7XwyP3lK5jp2KSBQ84+CRHJsMDRIWKpdGz8B6yHs6n6oK4Rd9sExlU8pe7U1t/60BlewFN" +
1388 "fyVVmMupu5MT/lqqrvJXCVkjZB8VWfwQhEnQIDAQAB",
1390 "OU=Public CA Services",
1391 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOeC2xUTrnnCtF+SjyO8uvfG0Q" +
1392 "Cv1lRp8V2mYvhh0Zzeyjss6VwWJzTmuNHKdO8leGRt/hzoiXMxU2dnhsStamjnClZEgzpY" +
1393 "R4l3Gtpv8vkHQMk9Ae9q0dlrhJ7FaytOtyz4pGpXq2gxuhlmuuwbV/vOStZLeMPBgT1Llj" +
1394 "CZqcMt4uQSJgqkYxIc1HfIgdSnVUMt/ARWndwLrrdsCtozkIgFyX5UgujSMtDXAUkqNZB5" +
1395 "OXPWi7xhzYdtUBUFTKnoSkcxiwXM5flC1xJg+Do/o6k2GqWGNiymBIMJ9lLFsH0fiEGQmM" +
1396 "VlaJYQshPJFkm9Kr6wSKfC/S1eVtA3TVhR+wIDAQAB",
1398 "OU=TC TrustCenter Class 1 CA",
1399 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwKeu0drOu17ZbtF7nveOxnEkEV1uhq9" +
1400 "l/Exv9umGr2Odx3y0AlF1RSH0j73VihJA8Ch9ZEXQvjoCl/TACPSlSzXIaSSGcvMtSjkih" +
1401 "Y5bIEIUwaVd0RcBahsbVPeBoV30xaiSNRZc+MX5oZjJuJG3sMjbJQcrwMUTIo2HKG6A2Hw" +
1404 "OU=TC TrustCenter Class 2 CA",
1405 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaOOjtMgApcYMBDb+MAdzaxq05pKmKL9" +
1406 "WLXGhfUMZi9Wa9ypEi7KodUdc9s1Gyg05dy0mw8ExV5Wstx4ULMBySToLUygLt92++3ODj" +
1407 "FLgFU/Ka9FaLWp6Fk9G0glauTbuoS1cWvP74WJ74KY2we814yU+si2cM8Zz7/FebV1xPDQ" +
1410 "OU=TC TrustCenter Class 3 CA",
1411 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2tME1BS4NjeygQGocDiemUJJrUBsH3i" +
1412 "7ndszg2vyEqF6MY2orTdlOAnYRwQvyjXnKALbxsA7X+6QXPa+raXqWJ7+vM6GaKlmqxLU3" +
1413 "CPISpTG2Q/UylnEoKKuNKIbfu+7jDH0w1sNSq49dJ5xrwKPnBWtXSUSzbupkz9KOelB3dw" +
1416 "OU=TC TrustCenter Class 4 CA",
1417 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/L2PWNnuyDdNV9WRs5iVdxrTIFLolOI" +
1418 "PrVmKlVallo/QjmcJLudDNVGemo6CjqTMrduS9rXey7VwSdMPFtg9SmnKTQ5BiZhUPRaXd" +
1419 "4N24b0BuV8F5cqNgqrp2HRKJU1r8Ar7hCRPFSi/cPYsZrdeLJEX7TPTNXDUdKUxR8/JsVQ" +
1422 "CN=Thawte Premium Server CA",
1423 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSNjZqi9fCW57agUFijzjuSQRV1tDvHB" +
1424 "uVFkfvGEg1OlL0K2oGjzsv6lbjr4aNnhf3nrRldQJN78sJoiFR2JvQZ9C6DZIGFHPUk8uX" +
1425 "KgCcXE4MvPoVUvzyRG7aEUpuCJ8vLeP5qjqGc7ZGU1jIiQW9gxG4cz+qB430Qk3nQJ0cNw" +
1428 "C=hk, O=C&W HKT SecureNet CA SGC Root",
1429 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqFNPj0Pdr+zBtA0bX7cIoprIQu" +
1430 "Nt1yUa3+DKvC8iJPlpIr0arVHncfe1dtTzPsg+EdBNe5keGLeezT5hG0URS1sm3Ck8AE0R" +
1431 "2h2Pnh903hVAvDDJD9/4LXzYjZ2g4J+wzydgzzgRCO82L3xONh0mAqf01FBDgUnr3beWFD" +
1432 "BjMtEDzSG8N5EePmWuFoL2FWBLUTuW5RnowvemBYE6qH8YWD53w1kAg/T1eUlgpy4DPgH9" +
1433 "heLfoZqJ2fhkCiuEzUPNJTUAXjBmdKHHCHWsSSeC17CVNW4dmYDrkqAtWtY4u7VHJ6sazL" +
1434 "9TU8FGsm/o101XEd2wNUgfqybqVg24CjC22wIDAQAB",
1436 "CN=Thawte Server CA",
1437 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTpFBuyP9Wa+bPXbbqDGh1R6KqwtqEJf" +
1438 "yo9EdR2oW1IHSUhh4PdcnpCGH1Bm0wbhUZAulSwGLbTZme4moMRDjN/r7jZAlwxf6xaym2" +
1439 "L0nIO9QnBCUQly/nkG3AKEKZ10xD3sP1IW1Un13DWOHA5NlbsLjctHvfNjrCtWYiEtaHDQ" +
1442 "CN=UTN - DATACorp SGC",
1443 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLi" +
1444 "t6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/W" +
1445 "w5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1k" +
1446 "duSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2A" +
1447 "swkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorG" +
1448 "kVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB",
1450 "CN=UTN-USERFirst-Hardware",
1451 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsffDOD+0qH/POYJRZ9Btn9L/WP" +
1452 "PnnyvsDYlUmbk4mRb34CF5SMK7YXQSlh08anLVPBBnOjntKxPNZuuVCTOkbJex6MbswXV5" +
1453 "nEZejavQav25KlUXEFSzGfCa9vGxXbanbfvgcRdrooj7AN/+GjF3DJoBerEy4ysBBzhuw6" +
1454 "VeI7xFm3tQwckwj9vlK3rTW/szQB6g1ZgXvIuHw4nTXaCOsqqq9o5piAbF+okh8widaS4J" +
1455 "M5spDUYPjMxJNLBpUb35Bs1orWZMvD6sYb0KiA7I3z3ufARMnQpea5HW7sftKI2rTYeJc9" +
1456 "BupNAeFosU4XZEA39jrOTNSZzFkvSrMqFIWwIDAQAB",
1458 "CN=UTN-USERFirst-Network Applications",
1459 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/uRoeQ2VYWsBjRboJpYsvi1Dw" +
1460 "V3g64ysXaSaOwjSsl2P+Octjd5A7mraY0HJbYZZ+SwGxhzYUrofs3TL2TjpnwM+heAow1H" +
1461 "iU9RcS/u/D/5uBaAh4mTJSCaQ4JpJHYoWTWhHcB/gwZkFiAs00mkhbTAYX9RCPhoFZGAy6" +
1462 "XV7js69IQEXmBZp4w0cu64eMXROxJKb35lJ7mkVcW5b0OkxR0smcBSpHhMFbNAmAhrQ8YB" +
1463 "sHp79WscIj/L7/+o0DpLdhWe0tHGLuPbVxsyorhv6IamP3Cr5XCSq0QeQFD7nKNi5GxuoM" +
1464 "je4oBC+ukv6M4yBI98jbccozU8Fd2ew66XpQIDAQAB",
1466 "CN=VeriSign Class 3 Public Primary Certification Authority - G3",
1467 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7qcUvx4Hxoebxs3c734yWuUEj" +
1468 "BP8DZH9dCRCvUXyKVhwRZATfuKYZDldiDBEQZ9qyxupvURQY76La0qYVmkZyZM0Oi8Ultw" +
1469 "IARY0XrJpGm8gxdkrQWLvNBYzo2M9evwQkkLnZcnZzJu4a6TFRxwvCBNLxjekojobIVXER" +
1470 "rpfuMmEVSiRZZVg8owiejc2KPtKoA/f3llVz4VIGYIL5WTv6pHL6hGl/AS4v7CCitR5nbm" +
1471 "t0a34g2mzKjDTFlVieboU1wc6p3wYhYLp8lfDPDewnbOr/dq8vpBpqIzFMnlemPTnmI31Y" +
1472 "Vlng7mUyR0G14dElNbxyzng0k7Fa6KaLlXlwIDAQAB",
1474 "CN=VeriSign Class 4 Public Primary Certification Authority - G3",
1475 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArculEWnGWavxj7UZD1bOzLUfIO" +
1476 "SeJiVL4HNliVne0IPk9Q+1u63xfOgh/OToDO58RSIZdpK0E7cgWwn6Ya6o8qWNhcIq1t5m" +
1477 "NtKbAvSokmB8nGm0jyQe0IZS9jKcQVgeIr3NRWKVCG7QZt1ToszwENxUc4sEoUYzM1wXQL" +
1478 "meTdPzvlWD6LGJjlp8mpYikDuIJfLSU4gCDAt48uY3F0swRgfkgG2m2JYu6Cz4EbM4DWam" +
1479 "m+rJI1vbjuLzE44aWS2qAvDspIdm3ME/9di59OyCxtI9lR3lwE+EydmjRCgGatdFrPBrau" +
1480 "9OX/gRgh44YzRmUNQ+k3P6MMNmrf+TLZfvAwIDAQAB",
1482 "OU=VeriSign Trust Network",
1483 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1484 "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1485 "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1488 "OU=VeriSign Trust Network",
1489 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1490 "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1491 "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1494 "OU=VeriSign Trust Network",
1495 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1496 "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1497 "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1500 "OU=VeriSign Trust Network",
1501 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1502 "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1503 "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1507 public static boolean alwaysFalse = false;
1509 static class entropySpinner extends Thread {
1510 volatile boolean stop = false;
1512 entropySpinner() { start(); }
1517 // without this line, GCJ will over-optimize this loop into an infinite loop. Argh.
1518 if (alwaysFalse) stop = true;
1527 entropySpinner[] spinners = new entropySpinner[10];
1528 for(int i=0; i<spinners.length; i++) spinners[i] = new entropySpinner();
1530 for(int i=0; i<pad1.length; i++) pad1[i] = (byte)0x36;
1531 for(int i=0; i<pad2.length; i++) pad2[i] = (byte)0x5C;
1532 for(int i=0; i<pad1_sha.length; i++) pad1_sha[i] = (byte)0x36;
1533 for(int i=0; i<pad2_sha.length; i++) pad2_sha[i] = (byte)0x5C;
1536 if (Log.on) Log.log(TinySSL.class, "reading in trusted root public keys...");
1537 trusted_CA_public_keys = new SubjectPublicKeyInfo[base64_encoded_trusted_CA_public_keys.length / 2];
1538 trusted_CA_public_key_identifiers = new String[base64_encoded_trusted_CA_public_keys.length / 2];
1539 for(int i=0; i<base64_encoded_trusted_CA_public_keys.length; i+=2) {
1540 trusted_CA_public_key_identifiers[i/2] = base64_encoded_trusted_CA_public_keys[i];
1541 byte[] b = Base64.decode(base64_encoded_trusted_CA_public_keys[i+1]);
1542 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(b));
1543 trusted_CA_public_keys[i/2] = new SubjectPublicKeyInfo((DERSequence)dIn.readObject());
1546 } catch (Exception e) {
1547 if (Log.on) Log.log(TinySSL.class, e);
1550 if (Log.on) Log.log(TinySSL.class, "generating entropy...");
1551 randpool = new byte[10];
1552 try { Thread.sleep(100); } catch (Exception e) { }
1553 for(int i=0; i<spinners.length; i++) {
1554 spinners[i].stop = true;
1555 randpool[i] = spinners[i].counter;
1558 MD5Digest md5 = new MD5Digest();
1559 md5.update(randpool, 0, randpool.length);
1560 intToBytes(System.currentTimeMillis(), randpool, 0, 4); md5.update(randpool, 0, 4);
1561 intToBytes(Runtime.getRuntime().freeMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1562 intToBytes(Runtime.getRuntime().totalMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1563 intToBytes(System.identityHashCode(TinySSL.class), randpool, 0, 4); md5.update(randpool, 0, 4);
1564 Properties p = System.getProperties();
1565 for(Enumeration e = p.propertyNames(); e.hasMoreElements();) {
1566 String s = (String)e.nextElement();
1567 byte[] b = s.getBytes();
1568 md5.update(b, 0, b.length);
1569 b = p.getProperty(s).getBytes();
1570 md5.update(b, 0, b.length);
1572 randpool = new byte[md5.getDigestSize()];
1573 md5.doFinal(randpool, 0);
1575 if (Log.on) Log.log(TinySSL.class, "TinySSL is initialized.");
1580 * A PKCS1 encoder which uses TinySSL's built-in PRNG instead of java.security.SecureRandom.
1581 * This code was derived from BouncyCastle's org.bouncycastle.crypto.encoding.PKCS1Encoding.
1583 private static class PKCS1 implements AsymmetricBlockCipher {
1584 private static int HEADER_LENGTH = 10;
1585 private AsymmetricBlockCipher engine;
1586 private boolean forEncryption;
1587 private boolean forPrivateKey;
1589 public PKCS1(AsymmetricBlockCipher cipher) { this.engine = cipher; }
1590 public AsymmetricBlockCipher getUnderlyingCipher() { return engine; }
1592 public void init(boolean forEncryption, CipherParameters param) {
1593 engine.init(forEncryption, (AsymmetricKeyParameter)param);
1594 this.forPrivateKey = ((AsymmetricKeyParameter)param).isPrivate();
1595 this.forEncryption = forEncryption;
1598 public int getInputBlockSize() { return engine.getInputBlockSize() - (forEncryption ? HEADER_LENGTH : 0); }
1599 public int getOutputBlockSize() { return engine.getOutputBlockSize() - (forEncryption ? 0 : HEADER_LENGTH); }
1601 public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1602 return forEncryption ? encodeBlock(in, inOff, inLen) : decodeBlock(in, inOff, inLen);
1605 private byte[] encodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1606 byte[] block = new byte[engine.getInputBlockSize()];
1607 if (forPrivateKey) {
1608 block[0] = 0x01; // type code 1
1609 for (int i = 1; i != block.length - inLen - 1; i++)
1610 block[i] = (byte)0xFF;
1612 getRandomBytes(block, 0, block.length);
1613 block[0] = 0x02; // type code 2
1615 // a zero byte marks the end of the padding, so all
1616 // the pad bytes must be non-zero.
1617 for (int i = 1; i != block.length - inLen - 1; i++)
1618 while (block[i] == 0)
1619 getRandomBytes(block, i, 1);
1622 block[block.length - inLen - 1] = 0x00; // mark the end of the padding
1623 System.arraycopy(in, inOff, block, block.length - inLen, inLen);
1624 return engine.processBlock(block, 0, block.length);
1627 private byte[] decodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1628 byte[] block = engine.processBlock(in, inOff, inLen);
1629 if (block.length < getOutputBlockSize())
1630 throw new InvalidCipherTextException("block truncated");
1631 if (block[0] != 1 && block[0] != 2)
1632 throw new InvalidCipherTextException("unknown block type");
1634 // find and extract the message block.
1636 for (start = 1; start != block.length; start++)
1637 if (block[start] == 0)
1639 start++; // data should start at the next byte
1641 if (start >= block.length || start < HEADER_LENGTH)
1642 throw new InvalidCipherTextException("no data in block");
1644 byte[] result = new byte[block.length - start];
1645 System.arraycopy(block, start, result, 0, result.length);