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